xref: /kvm-unit-tests/s390x/diag288.c (revision b4667f4ca26aea926a2ddecfcb5669e0e4e7cbf4)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 /*
3  * Timer Event DIAG288 test
4  *
5  * Copyright (c) 2019 IBM Corp
6  *
7  * Authors:
8  *  Janosch Frank <frankja@linux.ibm.com>
9  */
10 
11 #include <libcflat.h>
12 #include <asm/asm-offsets.h>
13 #include <asm/interrupt.h>
14 
15 struct lowcore *lc = (struct lowcore *)0x0;
16 
17 #define CODE_INIT	0
18 #define CODE_CHANGE	1
19 #define CODE_CANCEL	2
20 
21 #define ACTION_RESTART	0
22 
23 static inline void diag288(unsigned long code, unsigned long time,
24 			   unsigned long action)
25 {
26 	register unsigned long fc asm("0") = code;
27 	register unsigned long tm asm("1") = time;
28 	register unsigned long ac asm("2") = action;
29 
30 	asm volatile("diag %0,%2,0x288"
31 		     : : "d" (fc), "d" (tm), "d" (ac));
32 }
33 
34 static void test_specs(void)
35 {
36 	report_prefix_push("specification");
37 
38 	report_prefix_push("uneven");
39 	expect_pgm_int();
40 	asm volatile("diag 1,2,0x288");
41 	check_pgm_int_code(PGM_INT_CODE_SPECIFICATION);
42 	report_prefix_pop();
43 
44 	report_prefix_push("unsupported action");
45 	expect_pgm_int();
46 	diag288(CODE_INIT, 15, 42);
47 	check_pgm_int_code(PGM_INT_CODE_SPECIFICATION);
48 	report_prefix_pop();
49 
50 	report_prefix_push("unsupported function");
51 	expect_pgm_int();
52 	diag288(42, 15, ACTION_RESTART);
53 	check_pgm_int_code(PGM_INT_CODE_SPECIFICATION);
54 	report_prefix_pop();
55 
56 	report_prefix_push("no init");
57 	expect_pgm_int();
58 	diag288(CODE_CANCEL, 15, ACTION_RESTART);
59 	check_pgm_int_code(PGM_INT_CODE_SPECIFICATION);
60 	report_prefix_pop();
61 
62 	report_prefix_push("min timer");
63 	expect_pgm_int();
64 	diag288(CODE_INIT, 14, ACTION_RESTART);
65 	check_pgm_int_code(PGM_INT_CODE_SPECIFICATION);
66 	report_prefix_pop();
67 
68 	report_prefix_pop();
69 }
70 
71 static void test_priv(void)
72 {
73 	report_prefix_push("privileged");
74 	expect_pgm_int();
75 	enter_pstate();
76 	diag288(CODE_INIT, 15, ACTION_RESTART);
77 	check_pgm_int_code(PGM_INT_CODE_PRIVILEGED_OPERATION);
78 	report_prefix_pop();
79 }
80 
81 static void test_bite(void)
82 {
83 	uint64_t mask, time;
84 
85 	/* If watchdog doesn't bite, the cpu timer does */
86 	asm volatile("stck %0" : "=Q" (time) : : "cc");
87 	time += (uint64_t)(16000 * 1000) << 12;
88 	asm volatile("sckc %0" : : "Q" (time));
89 	ctl_set_bit(0, CTL0_CLOCK_COMPARATOR);
90 	mask = extract_psw_mask();
91 	mask |= PSW_MASK_EXT;
92 	load_psw_mask(mask);
93 
94 	/* Arm watchdog */
95 	lc->restart_new_psw.mask = extract_psw_mask() & ~PSW_MASK_EXT;
96 	diag288(CODE_INIT, 15, ACTION_RESTART);
97 	asm volatile("		larl	%r0, 1f\n"
98 		     "		stg	%r0, 424\n"
99 		     "0:	nop\n"
100 		     "		j	0b\n"
101 		     "1:");
102 	report_pass("restart");
103 }
104 
105 int main(void)
106 {
107 	report_prefix_push("diag288");
108 	test_priv();
109 	test_specs();
110 	test_bite();
111 	return report_summary();
112 }
113