1 /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 /* 3 * Diagnose 0x308 hypercall tests 4 * 5 * Copyright (c) 2019 Thomas Huth, Red Hat Inc. 6 */ 7 8 #include <libcflat.h> 9 #include <asm/asm-offsets.h> 10 #include <asm/interrupt.h> 11 #include <hardware.h> 12 13 /* The diagnose calls should be blocked in problem state */ 14 static void test_priv(void) 15 { 16 expect_pgm_int(); 17 enter_pstate(); 18 asm volatile ("diag %0,%1,0x308" :: "d"(0), "d"(3)); 19 check_pgm_int_code(PGM_INT_CODE_PRIVILEGED_OPERATION); 20 } 21 22 23 /* 24 * Check that diag308 with subcode 0 and 1 loads the PSW at address 0, i.e. 25 * that we can put a pointer into address 4 which then gets executed. 26 */ 27 extern int diag308_load_reset(u64); 28 static void test_subcode0(void) 29 { 30 report(diag308_load_reset(0), "load modified clear done"); 31 } 32 33 static void test_subcode1(void) 34 { 35 report(diag308_load_reset(1), "load normal reset done"); 36 } 37 38 /* Expect a specification exception when using an uneven register */ 39 static void test_uneven_reg(unsigned int subcode) 40 { 41 register unsigned long sc asm("6") = subcode; 42 register unsigned long r3 asm("9") = 0x2000; 43 44 report_prefix_push("uneven register"); 45 expect_pgm_int(); 46 asm volatile ("diag %0,%1,0x308" :: "d"(r3), "d"(sc)); 47 check_pgm_int_code(PGM_INT_CODE_SPECIFICATION); 48 report_prefix_pop(); 49 } 50 51 /* Expect a specification exception when using an unaligned address */ 52 static void test_unaligned_address(unsigned int subcode) 53 { 54 register unsigned long sc asm("6") = subcode; 55 register unsigned long addr asm("8") = 54321; 56 57 report_prefix_push("unaligned address"); 58 expect_pgm_int(); 59 asm volatile ("diag %0,%1,0x308" :: "d"(addr), "d"(sc)); 60 check_pgm_int_code(PGM_INT_CODE_SPECIFICATION); 61 report_prefix_pop(); 62 } 63 64 static void test_subcode5(void) 65 { 66 test_uneven_reg(5); 67 test_unaligned_address(5); 68 } 69 70 static void test_subcode6(void) 71 { 72 test_uneven_reg(6); 73 test_unaligned_address(6); 74 } 75 76 /* Unsupported subcodes should generate a specification exception */ 77 static void test_unsupported_subcode(void) 78 { 79 int subcodes[] = { 0x101, 0xffff, 0x10001, -1 }; 80 int idx; 81 82 for (idx = 0; idx < ARRAY_SIZE(subcodes); idx++) { 83 report_prefix_pushf("0x%04x", subcodes[idx]); 84 expect_pgm_int(); 85 asm volatile ("diag %0,%1,0x308" :: "d"(0), "d"(subcodes[idx])); 86 check_pgm_int_code(PGM_INT_CODE_SPECIFICATION); 87 report_prefix_pop(); 88 } 89 90 /* 91 * Subcode 2 is not available under QEMU but might be on other 92 * hypervisors so we only check for the specification 93 * exception on QEMU. 94 */ 95 report_prefix_pushf("0x%04x", 2); 96 if (host_is_qemu()) { 97 expect_pgm_int(); 98 asm volatile ("diag %0,%1,0x308" :: "d"(0), "d"(2)); 99 check_pgm_int_code(PGM_INT_CODE_SPECIFICATION); 100 } else { 101 report_skip("subcode is supported"); 102 } 103 report_prefix_pop(); 104 } 105 106 static struct { 107 const char *name; 108 void (*func)(void); 109 } tests[] = { 110 { "privileged", test_priv }, 111 { "subcode 0", test_subcode0 }, 112 { "subcode 1", test_subcode1 }, 113 { "subcode 5", test_subcode5 }, 114 { "subcode 6", test_subcode6 }, 115 { "unsupported", test_unsupported_subcode }, 116 { NULL, NULL } 117 }; 118 119 int main(int argc, char**argv) 120 { 121 int i; 122 123 report_prefix_push("diag308"); 124 for (i = 0; tests[i].name; i++) { 125 report_prefix_push(tests[i].name); 126 tests[i].func(); 127 report_prefix_pop(); 128 } 129 report_prefix_pop(); 130 131 return report_summary(); 132 } 133