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