1 /* SPDX-License-Identifier: GPL-2.0-only */ 2 /* 3 * Tests exceptions and data validity for the emulated sthyi 4 * instruction. 5 * 6 * Copyright 2018 IBM Corp. 7 * 8 * Authors: 9 * Janosch Frank <frankja@linux.vnet.ibm.com> 10 */ 11 #include <libcflat.h> 12 #include <asm/asm-offsets.h> 13 #include <asm/interrupt.h> 14 #include <asm/page.h> 15 #include <asm/facility.h> 16 17 #include "sthyi.h" 18 19 static uint8_t pagebuf[PAGE_SIZE] __attribute__((aligned(PAGE_SIZE))); 20 static char null_buf[32] = {}; 21 22 static inline int sthyi(uint64_t vaddr, uint64_t fcode, uint64_t *rc, 23 unsigned int r1, unsigned int r2) 24 { 25 register uint64_t code asm("0") = fcode; 26 register uint64_t addr asm("2") = vaddr; 27 register uint64_t rc3 asm("3") = 42; 28 int cc = 0; 29 30 asm volatile( 31 ".insn rre,0xB2560000,%[r1],%[r2]\n" 32 "ipm %[cc]\n" 33 "srl %[cc],28\n" 34 : [cc] "=d" (cc), "+d" (rc3) 35 : [code] "d" (code), [addr] "a" (addr), [r1] "i" (r1), [r2] "i" (r2) 36 : "memory", "cc"); 37 if (rc) 38 *rc = rc3; 39 return cc; 40 } 41 42 static void test_exception_addr(void) 43 { 44 report_prefix_push("Illegal address check"); 45 expect_pgm_int(); 46 sthyi(42042, 0, NULL, 0, 2); 47 check_pgm_int_code(PGM_INT_CODE_SPECIFICATION); 48 report_prefix_pop(); 49 } 50 51 static void test_exception_reg_odd(void) 52 { 53 report_prefix_push("Register check odd R1"); 54 expect_pgm_int(); 55 sthyi((uint64_t)pagebuf, 0, NULL, 1, 2); 56 check_pgm_int_code(PGM_INT_CODE_SPECIFICATION); 57 report_prefix_pop(); 58 report_prefix_push("Register check odd R2"); 59 expect_pgm_int(); 60 sthyi((uint64_t)pagebuf, 0, NULL, 0, 3); 61 check_pgm_int_code(PGM_INT_CODE_SPECIFICATION); 62 report_prefix_pop(); 63 } 64 65 static void test_exception_reg_equal(void) 66 { 67 report_prefix_push("Register check equal"); 68 expect_pgm_int(); 69 sthyi((uint64_t)pagebuf, 0, NULL, 0, 0); 70 check_pgm_int_code(PGM_INT_CODE_SPECIFICATION); 71 report_prefix_pop(); 72 } 73 74 static void test_function_code(uint64_t addr) 75 { 76 uint64_t urc = 0; 77 int cc = sthyi((uint64_t)pagebuf, 42, &urc, 0, 2); 78 79 report(cc == 3 && urc == CODE_UNSUPP, "Illegal fcode"); 80 } 81 82 static void test_fcode0_hdr(struct sthyi_hdr_sctn *hdr) 83 { 84 report_prefix_push("Header"); 85 86 report(hdr->INFHDLN >= sizeof(*hdr) && !(hdr->INFHDLN % 8), "length"); 87 report((hdr->INFMLEN >= sizeof(struct sthyi_mach_sctn) && !(hdr->INFMLEN % 8)), 88 "Machine sctn length"); 89 report((hdr->INFPLEN >= sizeof(struct sthyi_par_sctn) && !(hdr->INFPLEN % 8)), 90 "Partition section length"); 91 92 report(hdr->INFMOFF >= hdr->INFHDLN, "Machine offset"); 93 report(hdr->INFPOFF >= hdr->INFHDLN, "Partition offset"); 94 report_prefix_pop(); 95 } 96 97 static void test_fcode0_mach(struct sthyi_mach_sctn *mach) 98 { 99 int sum = mach->INFMSCPS + mach->INFMDCPS + mach->INFMSIFL + mach->INFMDIFL; 100 101 report_prefix_push("Machine"); 102 if (mach->INFMVAL1 & MACH_ID_VLD) { 103 report(memcmp(mach->INFMTYPE, null_buf, sizeof(mach->INFMTYPE)), 104 "type"); 105 report(memcmp(mach->INFMMANU, null_buf, sizeof(mach->INFMMANU)), 106 "manufacturer"); 107 report(memcmp(mach->INFMSEQ, null_buf, sizeof(mach->INFMSEQ)), 108 "sequence"); 109 report(memcmp(mach->INFMPMAN, null_buf, sizeof(mach->INFMPMAN)), 110 "plant"); 111 } 112 113 if (mach->INFMVAL1 & MACH_NAME_VLD) 114 report(memcmp(mach->INFMNAME, null_buf, sizeof(mach->INFMNAME)), 115 "name"); 116 117 if (mach->INFMVAL1 & MACH_CNT_VLD) 118 report(sum, "core counts"); 119 report_prefix_pop(); 120 } 121 122 static void test_fcode0_par(struct sthyi_par_sctn *par) 123 { 124 int sum = par->INFPSCPS + par->INFPDCPS + par->INFPSIFL + par->INFPDIFL; 125 126 report_prefix_push("Partition"); 127 if (par->INFPVAL1 & PART_CNT_VLD) 128 report(sum, "core counts"); 129 130 if (par->INFPVAL1 & PART_STSI_SUC) { 131 report(memcmp(par->INFPPNAM, null_buf, sizeof(par->INFPPNAM)), 132 "name"); 133 } 134 report_prefix_pop(); 135 } 136 137 static void test_fcode0(void) 138 { 139 struct sthyi_hdr_sctn *hdr; 140 struct sthyi_mach_sctn *mach; 141 struct sthyi_par_sctn *par; 142 uint64_t rc = 42; 143 int cc; 144 145 /* Zero destination memory. */ 146 memset(pagebuf, 0, PAGE_SIZE); 147 148 report_prefix_push("fcode 0"); 149 cc = sthyi((uint64_t)pagebuf, 0, &rc, 0, 2); 150 hdr = (void *)pagebuf; 151 mach = (void *)pagebuf + hdr->INFMOFF; 152 par = (void *)pagebuf + hdr->INFPOFF; 153 154 report(cc == 0 && rc == CODE_SUCCES, "r2 + 1 == 0"); 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