xref: /kvm-unit-tests/s390x/diag308.c (revision c315f52b88b967cfb4cd58f3b4e1987378c47f3b)
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