1 /* 2 * Interception tests - for s390x CPU instruction that cause a VM exit 3 * 4 * Copyright (c) 2017 Red Hat Inc 5 * 6 * Authors: 7 * Thomas Huth <thuth@redhat.com> 8 * 9 * This code is free software; you can redistribute it and/or modify it 10 * under the terms of the GNU Library General Public License version 2. 11 */ 12 #include <libcflat.h> 13 #include <asm/asm-offsets.h> 14 #include <asm/interrupt.h> 15 #include <asm/page.h> 16 #include <asm/facility.h> 17 #include <asm/time.h> 18 19 static uint8_t pagebuf[PAGE_SIZE * 2] __attribute__((aligned(PAGE_SIZE * 2))); 20 21 static unsigned long nr_iterations; 22 static unsigned long time_to_run; 23 24 /* Test the STORE PREFIX instruction */ 25 static void test_stpx(void) 26 { 27 uint32_t old_prefix = -1U, tst_prefix = -1U; 28 uint32_t new_prefix = (uint32_t)(intptr_t)pagebuf; 29 30 /* Can we successfully change the prefix? */ 31 old_prefix = get_prefix(); 32 set_prefix(new_prefix); 33 tst_prefix = get_prefix(); 34 set_prefix(old_prefix); 35 report(old_prefix == 0 && tst_prefix == new_prefix, "store prefix"); 36 37 expect_pgm_int(); 38 low_prot_enable(); 39 asm volatile(" stpx 0(%0) " : : "r"(8)); 40 low_prot_disable(); 41 check_pgm_int_code(PGM_INT_CODE_PROTECTION); 42 43 expect_pgm_int(); 44 asm volatile(" stpx 0(%0) " : : "r"(1)); 45 check_pgm_int_code(PGM_INT_CODE_SPECIFICATION); 46 47 expect_pgm_int(); 48 asm volatile(" stpx 0(%0) " : : "r"(-8L)); 49 check_pgm_int_code(PGM_INT_CODE_ADDRESSING); 50 } 51 52 /* Test the SET PREFIX instruction */ 53 static void test_spx(void) 54 { 55 uint32_t new_prefix = (uint32_t)(intptr_t)pagebuf; 56 uint32_t old_prefix; 57 58 memset(pagebuf, 0, PAGE_SIZE * 2); 59 60 /* 61 * Temporarily change the prefix page to our buffer, and store 62 * some facility bits there ... at least some of them should be 63 * set in our buffer afterwards. 64 */ 65 old_prefix = get_prefix(); 66 set_prefix(new_prefix); 67 stfl(); 68 set_prefix(old_prefix); 69 report(pagebuf[GEN_LC_STFL] != 0, "stfl to new prefix"); 70 71 expect_pgm_int(); 72 asm volatile(" spx 0(%0) " : : "r"(1)); 73 check_pgm_int_code(PGM_INT_CODE_SPECIFICATION); 74 75 expect_pgm_int(); 76 asm volatile(" spx 0(%0) " : : "r"(-8L)); 77 check_pgm_int_code(PGM_INT_CODE_ADDRESSING); 78 } 79 80 /* Test the STORE CPU ADDRESS instruction */ 81 static void test_stap(void) 82 { 83 uint16_t cpuid = 0xffff; 84 85 asm volatile ("stap %0\n" : "+Q"(cpuid)); 86 report(cpuid != 0xffff, "get cpu address"); 87 88 expect_pgm_int(); 89 low_prot_enable(); 90 asm volatile ("stap 0(%0)\n" : : "r"(8)); 91 low_prot_disable(); 92 check_pgm_int_code(PGM_INT_CODE_PROTECTION); 93 94 expect_pgm_int(); 95 asm volatile ("stap 0(%0)\n" : : "r"(1)); 96 check_pgm_int_code(PGM_INT_CODE_SPECIFICATION); 97 98 expect_pgm_int(); 99 asm volatile ("stap 0(%0)\n" : : "r"(-8L)); 100 check_pgm_int_code(PGM_INT_CODE_ADDRESSING); 101 } 102 103 /* Test the STORE CPU ID instruction */ 104 static void test_stidp(void) 105 { 106 struct cpuid id = {}; 107 108 asm volatile ("stidp %0\n" : "+Q"(id)); 109 report(id.type, "type set"); 110 report(!id.version || id.version == 0xff, "version valid"); 111 report(!id.reserved, "reserved bits not set"); 112 113 expect_pgm_int(); 114 low_prot_enable(); 115 asm volatile ("stidp 0(%0)\n" : : "r"(8)); 116 low_prot_disable(); 117 check_pgm_int_code(PGM_INT_CODE_PROTECTION); 118 119 expect_pgm_int(); 120 asm volatile ("stidp 0(%0)\n" : : "r"(1)); 121 check_pgm_int_code(PGM_INT_CODE_SPECIFICATION); 122 123 expect_pgm_int(); 124 asm volatile ("stidp 0(%0)\n" : : "r"(-8L)); 125 check_pgm_int_code(PGM_INT_CODE_ADDRESSING); 126 } 127 128 /* Test the TEST BLOCK instruction */ 129 static void test_testblock(void) 130 { 131 int cc; 132 133 memset(pagebuf, 0xaa, PAGE_SIZE); 134 135 asm volatile ( 136 " lghi %%r0,0\n" 137 " .insn rre,0xb22c0000,0,%1\n" 138 " ipm %0\n" 139 " srl %0,28\n" 140 : "=d" (cc) 141 : "a"(pagebuf + 0x123) 142 : "memory", "0", "cc"); 143 report(cc == 0 && pagebuf[0] == 0 && pagebuf[PAGE_SIZE - 1] == 0, 144 "page cleared"); 145 146 expect_pgm_int(); 147 low_prot_enable(); 148 asm volatile (" .insn rre,0xb22c0000,0,%0\n" : : "r"(4096)); 149 low_prot_disable(); 150 check_pgm_int_code(PGM_INT_CODE_PROTECTION); 151 152 expect_pgm_int(); 153 asm volatile (" .insn rre,0xb22c0000,0,%0\n" : : "r"(-4096L)); 154 check_pgm_int_code(PGM_INT_CODE_ADDRESSING); 155 } 156 157 struct { 158 const char *name; 159 void (*func)(void); 160 bool run_it; 161 } tests[] = { 162 { "stpx", test_stpx, false }, 163 { "spx", test_spx, false }, 164 { "stap", test_stap, false }, 165 { "stidp", test_stidp, false }, 166 { "testblock", test_testblock, false }, 167 { NULL, NULL, false } 168 }; 169 170 static void parse_intercept_test_args(int argc, char **argv) 171 { 172 int i, ti; 173 bool run_all = true; 174 175 for (i = 1; i < argc; i++) { 176 if (!strcmp("-i", argv[i])) { 177 i++; 178 if (i >= argc) 179 report_abort("-i needs a parameter"); 180 nr_iterations = atol(argv[i]); 181 } else if (!strcmp("-t", argv[i])) { 182 i++; 183 if (i >= argc) 184 report_abort("-t needs a parameter"); 185 time_to_run = atol(argv[i]); 186 } else for (ti = 0; tests[ti].name != NULL; ti++) { 187 if (!strcmp(tests[ti].name, argv[i])) { 188 run_all = false; 189 tests[ti].run_it = true; 190 break; 191 } else if (tests[ti + 1].name == NULL) { 192 report_abort("Unsupported parameter '%s'", 193 argv[i]); 194 } 195 } 196 } 197 198 if (run_all) { 199 for (ti = 0; tests[ti].name != NULL; ti++) 200 tests[ti].run_it = true; 201 } 202 } 203 204 int main(int argc, char **argv) 205 { 206 uint64_t startclk; 207 int ti; 208 209 parse_intercept_test_args(argc, argv); 210 211 if (nr_iterations == 0 && time_to_run == 0) 212 nr_iterations = 1; 213 214 report_prefix_push("intercept"); 215 216 startclk = get_clock_ms(); 217 for (;;) { 218 for (ti = 0; tests[ti].name != NULL; ti++) { 219 report_prefix_push(tests[ti].name); 220 if (tests[ti].run_it) 221 tests[ti].func(); 222 report_prefix_pop(); 223 } 224 if (nr_iterations) { 225 nr_iterations -= 1; 226 if (nr_iterations == 0) 227 break; 228 } 229 if (time_to_run) { 230 if (get_clock_ms() - startclk > time_to_run) 231 break; 232 } 233 } 234 235 report_prefix_pop(); 236 237 return report_summary(); 238 } 239