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"); 56 expect_pgm_int(); 57 sthyi((uint64_t)pagebuf, 0, NULL, 1, 2); 58 check_pgm_int_code(PGM_INT_CODE_SPECIFICATION); 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("Ill. fcode", cc == 3 && urc == CODE_UNSUPP); 80 } 81 82 static void test_fcode0_hdr(struct sthyi_hdr_sctn *hdr) 83 { 84 report("HDR length", (hdr->INFHDLN >= sizeof(*hdr) 85 && !(hdr->INFHDLN % 8))); 86 report("MACH sctn length", (hdr->INFMLEN >= sizeof(struct sthyi_mach_sctn) 87 && !(hdr->INFMLEN % 8))); 88 report("PAR sctn length", (hdr->INFPLEN >= sizeof(struct sthyi_par_sctn) 89 && !(hdr->INFPLEN % 8))); 90 91 report("MACH offset", hdr->INFMOFF >= hdr->INFHDLN); 92 report("PAR offset", hdr->INFPOFF >= hdr->INFHDLN); 93 } 94 95 static void test_fcode0_mach(struct sthyi_mach_sctn *mach) 96 { 97 int sum = mach->INFMSCPS + mach->INFMDCPS + mach->INFMSIFL + mach->INFMDIFL; 98 99 if (mach->INFMVAL1 & MACH_ID_VLD) { 100 report("MACH type", memcmp(mach->INFMTYPE, null_buf, sizeof(mach->INFMTYPE))); 101 report("MACH manu", memcmp(mach->INFMMANU, null_buf, sizeof(mach->INFMMANU))); 102 report("MACH seq", memcmp(mach->INFMSEQ, null_buf, sizeof(mach->INFMSEQ))); 103 report("MACH plant", memcmp(mach->INFMPMAN, null_buf, sizeof(mach->INFMPMAN))); 104 } 105 106 if (mach->INFMVAL1 & MACH_NAME_VLD) 107 report("MACH name", memcmp(mach->INFMNAME, null_buf, 108 sizeof(mach->INFMNAME))); 109 110 if (mach->INFMVAL1 & MACH_CNT_VLD) 111 report("MACH core counts", sum); 112 } 113 114 static void test_fcode0_par(struct sthyi_par_sctn *par) 115 { 116 int sum = par->INFPSCPS + par->INFPDCPS + par->INFPSIFL + par->INFPDIFL; 117 118 if (par->INFPVAL1 & PART_CNT_VLD) 119 report("PAR core counts", sum); 120 121 if (par->INFPVAL1 & PART_STSI_SUC) { 122 report("PAR number", par->INFPPNUM); 123 report("PAR name", memcmp(par->INFPPNAM, null_buf, sizeof(par->INFPPNAM))); 124 } 125 } 126 127 static void test_fcode0(void) 128 { 129 struct sthyi_hdr_sctn *hdr; 130 struct sthyi_mach_sctn *mach; 131 struct sthyi_par_sctn *par; 132 133 /* Zero destination memory. */ 134 memset(pagebuf, 0, PAGE_SIZE); 135 136 sthyi((uint64_t)pagebuf, 0, NULL, 0, 2); 137 hdr = (void *)pagebuf; 138 mach = (void *)pagebuf + hdr->INFMOFF; 139 par = (void *)pagebuf + hdr->INFPOFF; 140 141 test_fcode0_hdr(hdr); 142 test_fcode0_mach(mach); 143 test_fcode0_par(par); 144 } 145 146 int main(void) 147 { 148 bool has_sthyi = test_facility(74); 149 150 report_prefix_push("sthyi"); 151 152 /* Test for availability */ 153 report_xfail("STHYI available", !has_sthyi, has_sthyi); 154 if (!has_sthyi) 155 goto done; 156 157 /* Test register/argument checking. */ 158 test_exception_addr(); 159 test_exception_reg_odd(); 160 test_exception_reg_equal(); 161 test_function_code((uint64_t) pagebuf); 162 163 /* Test function code 0 - CP and IFL Capacity Information */ 164 test_fcode0(); 165 166 done: 167 report_prefix_pop(); 168 return report_summary(); 169 } 170