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 */
test_priv(void)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);
test_subcode0(void)28 static void test_subcode0(void)
29 {
30 report(diag308_load_reset(0), "load modified clear done");
31 }
32
test_subcode1(void)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 */
test_uneven_reg(unsigned int subcode)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 */
test_unaligned_address(unsigned int subcode)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
test_subcode5(void)64 static void test_subcode5(void)
65 {
66 test_uneven_reg(5);
67 test_unaligned_address(5);
68 }
69
test_subcode6(void)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 */
test_unsupported_subcode(void)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
main(int argc,char ** argv)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