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("Illegal fcode", cc == 3 && urc == CODE_UNSUPP); 82 } 83 84 static void test_fcode0_hdr(struct sthyi_hdr_sctn *hdr) 85 { 86 report_prefix_push("Header"); 87 88 report("length", hdr->INFHDLN >= sizeof(*hdr) && !(hdr->INFHDLN % 8)); 89 report("Machine sctn length", (hdr->INFMLEN >= sizeof(struct sthyi_mach_sctn) 90 && !(hdr->INFMLEN % 8))); 91 report("Partition section length", (hdr->INFPLEN >= sizeof(struct sthyi_par_sctn) 92 && !(hdr->INFPLEN % 8))); 93 94 report("Machine offset", hdr->INFMOFF >= hdr->INFHDLN); 95 report("Partition offset", hdr->INFPOFF >= hdr->INFHDLN); 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("type", memcmp(mach->INFMTYPE, null_buf, sizeof(mach->INFMTYPE))); 106 report("manufacturer", memcmp(mach->INFMMANU, null_buf, sizeof(mach->INFMMANU))); 107 report("sequence", memcmp(mach->INFMSEQ, null_buf, sizeof(mach->INFMSEQ))); 108 report("plant", memcmp(mach->INFMPMAN, null_buf, sizeof(mach->INFMPMAN))); 109 } 110 111 if (mach->INFMVAL1 & MACH_NAME_VLD) 112 report("name", memcmp(mach->INFMNAME, null_buf, 113 sizeof(mach->INFMNAME))); 114 115 if (mach->INFMVAL1 & MACH_CNT_VLD) 116 report("core counts", sum); 117 report_prefix_pop(); 118 } 119 120 static void test_fcode0_par(struct sthyi_par_sctn *par) 121 { 122 int sum = par->INFPSCPS + par->INFPDCPS + par->INFPSIFL + par->INFPDIFL; 123 124 report_prefix_push("Partition"); 125 if (par->INFPVAL1 & PART_CNT_VLD) 126 report("core counts", sum); 127 128 if (par->INFPVAL1 & PART_STSI_SUC) { 129 report("number", par->INFPPNUM); 130 report("name", memcmp(par->INFPPNAM, null_buf, sizeof(par->INFPPNAM))); 131 } 132 report_prefix_pop(); 133 } 134 135 static void test_fcode0(void) 136 { 137 struct sthyi_hdr_sctn *hdr; 138 struct sthyi_mach_sctn *mach; 139 struct sthyi_par_sctn *par; 140 141 /* Zero destination memory. */ 142 memset(pagebuf, 0, PAGE_SIZE); 143 144 report_prefix_push("fcode 0"); 145 sthyi((uint64_t)pagebuf, 0, NULL, 0, 2); 146 hdr = (void *)pagebuf; 147 mach = (void *)pagebuf + hdr->INFMOFF; 148 par = (void *)pagebuf + hdr->INFPOFF; 149 150 test_fcode0_hdr(hdr); 151 test_fcode0_mach(mach); 152 test_fcode0_par(par); 153 report_prefix_pop(); 154 } 155 156 int main(void) 157 { 158 bool has_sthyi = test_facility(74); 159 160 report_prefix_push("sthyi"); 161 162 /* Test for availability */ 163 if (!has_sthyi) { 164 report_skip("STHYI is not available"); 165 goto done; 166 } 167 168 /* Test register/argument checking. */ 169 report_prefix_push("Instruction"); 170 test_exception_addr(); 171 test_exception_reg_odd(); 172 test_exception_reg_equal(); 173 test_function_code((uint64_t) pagebuf); 174 report_prefix_pop(); 175 176 /* Test function code 0 - CP and IFL Capacity Information */ 177 test_fcode0(); 178 179 done: 180 report_prefix_pop(); 181 return report_summary(); 182 } 183