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