1 /* 2 * Tests exceptions and data validity for the emulated sthyi 3 * instruction. 4 * 5 * Copyright 2018 IBM Corp. 6 * 7 * Authors: 8 * Janosch Frank <frankja@linux.vnet.ibm.com> 9 * 10 * This code is free software; you can redistribute it and/or modify it 11 * under the terms of the GNU Library General Public License version 2. 12 */ 13 #include <libcflat.h> 14 #include <asm/asm-offsets.h> 15 #include <asm/interrupt.h> 16 #include <asm/page.h> 17 #include <asm/facility.h> 18 19 #include "sthyi.h" 20 21 static uint8_t pagebuf[PAGE_SIZE] __attribute__((aligned(PAGE_SIZE))); 22 static char null_buf[32] = {}; 23 24 static inline int sthyi(uint64_t vaddr, uint64_t fcode, uint64_t *rc, 25 unsigned int r1, unsigned int r2) 26 { 27 register uint64_t code asm("0") = fcode; 28 register uint64_t addr asm("2") = vaddr; 29 register uint64_t rc3 asm("3") = 0; 30 int cc = 0; 31 32 asm volatile(".insn rre,0xB2560000,%[r1],%[r2]\n" 33 "ipm %[cc]\n" 34 "srl %[cc],28\n" 35 : [cc] "=d" (cc) 36 : [code] "d" (code), [addr] "a" (addr), [r1] "i" (r1), 37 [r2] "i" (r2) 38 : "memory", "cc", "r3"); 39 if (rc) 40 *rc = rc3; 41 return cc; 42 } 43 44 static void test_exception_addr(void) 45 { 46 report_prefix_push("Illegal address check"); 47 expect_pgm_int(); 48 sthyi(42042, 0, NULL, 0, 2); 49 check_pgm_int_code(PGM_INT_CODE_SPECIFICATION); 50 report_prefix_pop(); 51 } 52 53 static void test_exception_reg_odd(void) 54 { 55 report_prefix_push("Register check odd R1"); 56 expect_pgm_int(); 57 sthyi((uint64_t)pagebuf, 0, NULL, 1, 2); 58 check_pgm_int_code(PGM_INT_CODE_SPECIFICATION); 59 report_prefix_pop(); 60 report_prefix_push("Register check odd R2"); 61 expect_pgm_int(); 62 sthyi((uint64_t)pagebuf, 0, NULL, 0, 3); 63 check_pgm_int_code(PGM_INT_CODE_SPECIFICATION); 64 report_prefix_pop(); 65 } 66 67 static void test_exception_reg_equal(void) 68 { 69 report_prefix_push("Register check equal"); 70 expect_pgm_int(); 71 sthyi((uint64_t)pagebuf, 0, NULL, 0, 0); 72 check_pgm_int_code(PGM_INT_CODE_SPECIFICATION); 73 report_prefix_pop(); 74 } 75 76 static void test_function_code(uint64_t addr) 77 { 78 uint64_t urc = 0; 79 int cc = sthyi((uint64_t)pagebuf, 42, &urc, 0, 2); 80 81 report(cc == 3 && urc == CODE_UNSUPP, "Illegal fcode"); 82 } 83 84 static void test_fcode0_hdr(struct sthyi_hdr_sctn *hdr) 85 { 86 report_prefix_push("Header"); 87 88 report(hdr->INFHDLN >= sizeof(*hdr) && !(hdr->INFHDLN % 8), "length"); 89 report((hdr->INFMLEN >= sizeof(struct sthyi_mach_sctn) && !(hdr->INFMLEN % 8)), 90 "Machine sctn length"); 91 report((hdr->INFPLEN >= sizeof(struct sthyi_par_sctn) && !(hdr->INFPLEN % 8)), 92 "Partition section length"); 93 94 report(hdr->INFMOFF >= hdr->INFHDLN, "Machine offset"); 95 report(hdr->INFPOFF >= hdr->INFHDLN, "Partition offset"); 96 report_prefix_pop(); 97 } 98 99 static void test_fcode0_mach(struct sthyi_mach_sctn *mach) 100 { 101 int sum = mach->INFMSCPS + mach->INFMDCPS + mach->INFMSIFL + mach->INFMDIFL; 102 103 report_prefix_push("Machine"); 104 if (mach->INFMVAL1 & MACH_ID_VLD) { 105 report(memcmp(mach->INFMTYPE, null_buf, sizeof(mach->INFMTYPE)), 106 "type"); 107 report(memcmp(mach->INFMMANU, null_buf, sizeof(mach->INFMMANU)), 108 "manufacturer"); 109 report(memcmp(mach->INFMSEQ, null_buf, sizeof(mach->INFMSEQ)), 110 "sequence"); 111 report(memcmp(mach->INFMPMAN, null_buf, sizeof(mach->INFMPMAN)), 112 "plant"); 113 } 114 115 if (mach->INFMVAL1 & MACH_NAME_VLD) 116 report(memcmp(mach->INFMNAME, null_buf, sizeof(mach->INFMNAME)), 117 "name"); 118 119 if (mach->INFMVAL1 & MACH_CNT_VLD) 120 report(sum, "core counts"); 121 report_prefix_pop(); 122 } 123 124 static void test_fcode0_par(struct sthyi_par_sctn *par) 125 { 126 int sum = par->INFPSCPS + par->INFPDCPS + par->INFPSIFL + par->INFPDIFL; 127 128 report_prefix_push("Partition"); 129 if (par->INFPVAL1 & PART_CNT_VLD) 130 report(sum, "core counts"); 131 132 if (par->INFPVAL1 & PART_STSI_SUC) { 133 report(par->INFPPNUM, "number"); 134 report(memcmp(par->INFPPNAM, null_buf, sizeof(par->INFPPNAM)), 135 "name"); 136 } 137 report_prefix_pop(); 138 } 139 140 static void test_fcode0(void) 141 { 142 struct sthyi_hdr_sctn *hdr; 143 struct sthyi_mach_sctn *mach; 144 struct sthyi_par_sctn *par; 145 146 /* Zero destination memory. */ 147 memset(pagebuf, 0, PAGE_SIZE); 148 149 report_prefix_push("fcode 0"); 150 sthyi((uint64_t)pagebuf, 0, NULL, 0, 2); 151 hdr = (void *)pagebuf; 152 mach = (void *)pagebuf + hdr->INFMOFF; 153 par = (void *)pagebuf + hdr->INFPOFF; 154 155 test_fcode0_hdr(hdr); 156 test_fcode0_mach(mach); 157 test_fcode0_par(par); 158 report_prefix_pop(); 159 } 160 161 int main(void) 162 { 163 bool has_sthyi = test_facility(74); 164 165 report_prefix_push("sthyi"); 166 167 /* Test for availability */ 168 if (!has_sthyi) { 169 report_skip("STHYI is not available"); 170 goto done; 171 } 172 173 /* Test register/argument checking. */ 174 report_prefix_push("Instruction"); 175 test_exception_addr(); 176 test_exception_reg_odd(); 177 test_exception_reg_equal(); 178 test_function_code((uint64_t) pagebuf); 179 report_prefix_pop(); 180 181 /* Test function code 0 - CP and IFL Capacity Information */ 182 test_fcode0(); 183 184 done: 185 report_prefix_pop(); 186 return report_summary(); 187 } 188