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 * Check that diag308 with subcode 1 loads the PSW at address 0, i.e. 26 * that we can put a pointer into address 4 which then gets executed. 27 */ 28 static void test_subcode1(void) 29 { 30 uint64_t saved_psw = *(uint64_t *)0; 31 long subcode = 1; 32 long ret, tmp; 33 34 asm volatile ( 35 " epsw %0,%1\n" 36 " st %0,0\n" 37 " larl %0,0f\n" 38 " oilh %0,0x8000\n" 39 " st %0,4\n" 40 " diag 0,%2,0x308\n" 41 " lghi %0,0\n" 42 " j 1f\n" 43 "0: lghi %0,1\n" 44 "1:" 45 : "=&d"(ret), "=&d"(tmp) : "d"(subcode) : "memory"); 46 47 *(uint64_t *)0 = saved_psw; 48 49 report("load normal reset done", ret == 1); 50 } 51 52 /* Expect a specification exception when using an uneven register */ 53 static void test_uneven_reg(unsigned int subcode) 54 { 55 register unsigned long sc asm("6") = subcode; 56 register unsigned long r3 asm("9") = 0x2000; 57 58 report_prefix_push("uneven register"); 59 expect_pgm_int(); 60 asm volatile ("diag %0,%1,0x308" :: "d"(r3), "d"(sc)); 61 check_pgm_int_code(PGM_INT_CODE_SPECIFICATION); 62 report_prefix_pop(); 63 } 64 65 /* Expect a specification exception when using an unaligned address */ 66 static void test_unaligned_address(unsigned int subcode) 67 { 68 register unsigned long sc asm("6") = subcode; 69 register unsigned long addr asm("8") = 54321; 70 71 report_prefix_push("unaligned address"); 72 expect_pgm_int(); 73 asm volatile ("diag %0,%1,0x308" :: "d"(addr), "d"(sc)); 74 check_pgm_int_code(PGM_INT_CODE_SPECIFICATION); 75 report_prefix_pop(); 76 } 77 78 static void test_subcode5(void) 79 { 80 test_uneven_reg(5); 81 test_unaligned_address(5); 82 } 83 84 static void test_subcode6(void) 85 { 86 test_uneven_reg(6); 87 test_unaligned_address(6); 88 } 89 90 /* Unsupported subcodes should generate a specification exception */ 91 static void test_unsupported_subcode(void) 92 { 93 int subcodes[] = { 2, 0x101, 0xffff, 0x10001, -1 }; 94 int idx; 95 96 for (idx = 0; idx < ARRAY_SIZE(subcodes); idx++) { 97 report_prefix_pushf("0x%04x", subcodes[idx]); 98 expect_pgm_int(); 99 asm volatile ("diag %0,%1,0x308" :: "d"(0), "d"(subcodes[idx])); 100 check_pgm_int_code(PGM_INT_CODE_SPECIFICATION); 101 report_prefix_pop(); 102 } 103 } 104 105 static struct { 106 const char *name; 107 void (*func)(void); 108 } tests[] = { 109 { "privileged", test_priv }, 110 { "subcode 1", test_subcode1 }, 111 { "subcode 5", test_subcode5 }, 112 { "subcode 6", test_subcode6 }, 113 { "unsupported", test_unsupported_subcode }, 114 { NULL, NULL } 115 }; 116 117 int main(int argc, char**argv) 118 { 119 int i; 120 121 report_prefix_push("diag308"); 122 for (i = 0; tests[i].name; i++) { 123 report_prefix_push(tests[i].name); 124 tests[i].func(); 125 report_prefix_pop(); 126 } 127 report_prefix_pop(); 128 129 return report_summary(); 130 } 131