xref: /kvm-unit-tests/s390x/gs.c (revision fdab948bc134fb9989a8265380a55e809879418e)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 /*
3  * Tests guarded storage support.
4  *
5  * Copyright 2018 IBM Corp.
6  *
7  * Authors:
8  *    Martin Schwidefsky <schwidefsky@de.ibm.com>
9  *    Janosch Frank <frankja@de.ibm.com>
10  */
11 #include <libcflat.h>
12 #include <asm/page.h>
13 #include <asm/facility.h>
14 #include <asm/interrupt.h>
15 #include <asm-generic/barrier.h>
16 
17 struct gs_cb {
18 	uint64_t reserved;
19 	uint64_t gsd;
20 	uint64_t gssm;
21 	uint64_t gs_epl_a;
22 };
23 
24 struct gs_epl {
25 	uint8_t pad1;
26 	union {
27 		uint8_t gs_eam;
28 		struct {
29 			uint8_t		: 6;
30 			uint8_t e	: 1;
31 			uint8_t b	: 1;
32 		};
33 	};
34 	union {
35 		uint8_t gs_eci;
36 		struct {
37 			uint8_t tx	: 1;
38 			uint8_t cx	: 1;
39 			uint8_t		: 5;
40 			uint8_t in	: 1;
41 		};
42 	};
43 	union {
44 		uint8_t gs_eai;
45 		struct {
46 			uint8_t		: 1;
47 			uint8_t t	: 1;
48 			uint8_t as	: 2;
49 			uint8_t ar	: 4;
50 		};
51 	};
52 	uint32_t pad2;
53 	uint64_t gs_eha;
54 	uint64_t gs_eia;
55 	uint64_t gs_eoa;
56 	uint64_t gs_eir;
57 	uint64_t gs_era;
58 };
59 
60 static volatile int guarded = 0;
61 static struct gs_cb gs_cb;
62 static struct gs_epl gs_epl;
63 static unsigned long gs_area = 0x2000000;
64 
65 void gs_handler(struct gs_cb *this_cb);
66 
67 static inline void load_gs_cb(struct gs_cb *gs_cb)
68 {
69 	asm volatile(".insn rxy,0xe3000000004d,0,%0" : : "Q" (*gs_cb));
70 }
71 
72 static inline void store_gs_cb(struct gs_cb *gs_cb)
73 {
74 	asm volatile(".insn rxy,0xe30000000049,0,%0" : : "Q" (*gs_cb));
75 }
76 
77 static inline unsigned long load_guarded(unsigned long *p)
78 {
79 	unsigned long v;
80 
81 	asm(".insn rxy,0xe3000000004c, %0,%1"
82 	    : "=d" (v)
83 	    : "m" (*p)
84 	    : "r14", "memory");
85 	return v;
86 }
87 
88 /* guarded-storage event handler and finally it calls gs_handler */
89 extern void gs_handler_asm(void);
90 	asm(".globl gs_handler_asm\n"
91 	    "gs_handler_asm:\n"
92 	    "	    lgr	    %r14,%r15\n" 		/* Save current stack address in r14 */
93 	    "	    aghi    %r15,-320\n" 		/* Allocate stack frame */
94 	    "	    stmg    %r0,%r13,192(%r15)\n" 	/* Store regs to save area */
95 	    "	    stg	    %r14,312(%r15)\n"
96 	    "	    la	    %r2,160(%r15)\n" 		/* Store gscb address in this_cb */
97 	    "	    .insn   rxy,0xe30000000049,0,160(%r15)\n" /* stgsc */
98 	    "	    lg	    %r14,24(%r2)\n" 		/* Get GSEPLA from GSCB*/
99 	    "	    lg	    %r14,40(%r14)\n" 		/* Get GSERA from GSEPL*/
100 	    "	    stg	    %r14,304(%r15)\n" 		/* Store GSERA in r14 of reg save area */
101 	    "	    brasl   %r14,gs_handler\n" 		/* Jump to gs_handler */
102 	    "	    lmg	    %r0,%r15,192(%r15)\n" 	/* Restore regs */
103 	    "	    aghi    %r14, 6\n" 			/* Add lgg instr len to GSERA */
104 	    "	    br	    %r14\n" 			/* Jump to next instruction after lgg */
105 	    "	    .size gs_handler_asm,.-gs_handler_asm\n");
106 
107 void gs_handler(struct gs_cb *this_cb)
108 {
109 	guarded = 1;
110 	struct gs_epl *gs_epl = (struct gs_epl *) this_cb->gs_epl_a;
111 	printf("gs_handler called for %016lx at %016lx\n",
112 	       gs_epl->gs_eir, gs_epl->gs_eia);
113 }
114 
115 /* Test if load guarded gets intercepted. */
116 static void test_load(void)
117 {
118 	unsigned long v;
119 
120 	guarded = 0;
121 	v = load_guarded(&gs_area);
122 	report(guarded, "load guarded %ld", v);
123 	guarded = 0;
124 }
125 
126 /* Test gs instructions without enablement resulting in an exception */
127 static void test_special(void)
128 {
129 	report_prefix_push("disabled gs");
130 	report_prefix_push("load gs");
131 	expect_pgm_int();
132 	load_gs_cb(&gs_cb);
133 	check_pgm_int_code(PGM_INT_CODE_SPECIAL_OPERATION);
134 	report_prefix_pop();
135 
136 	report_prefix_push("store gs");
137 	expect_pgm_int();
138 	store_gs_cb(&gs_cb);
139 	check_pgm_int_code(PGM_INT_CODE_SPECIAL_OPERATION);
140 	report_prefix_pop();
141 
142 	report_prefix_pop();
143 }
144 
145 static void init(void)
146 {
147 	/* Enable control bit for gs */
148 	ctl_set_bit(2, 4);
149 
150 	/* Setup gs registers to guard the gs_area */
151 	gs_cb.gsd = gs_area | 25;
152 
153 	/* Check all 512kb slots for events */
154 	gs_cb.gssm = 0xffffffffffffffffULL;
155 	gs_cb.gs_epl_a =  (unsigned long) &gs_epl;
156 
157 	/* Register handler */
158 	gs_epl.gs_eha = (unsigned long) gs_handler_asm;
159 	load_gs_cb(&gs_cb);
160 }
161 
162 int main(void)
163 {
164 	bool has_gs = test_facility(133);
165 
166 	report_prefix_push("gs");
167 	if (!has_gs) {
168 		report_skip("Guarded storage is not available");
169 		goto done;
170 	}
171 
172 	test_special();
173 	init();
174 	test_load();
175 
176 done:
177 	report_prefix_pop();
178 	return report_summary();
179 }
180