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