xref: /kvm-unit-tests/s390x/diag308.c (revision 6163f75d09a0a96a5c3db82dd768b13f79629c00)
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("load modified clear done", diag308_load_reset(0));
33 }
34 
35 static void test_subcode1(void)
36 {
37 	report("load normal reset done", diag308_load_reset(1));
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