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@linux.ibm.com>
10 */
11 #include <libcflat.h>
12 #include <asm/asm-offsets.h>
13 #include <asm/page.h>
14 #include <asm/facility.h>
15 #include <asm/interrupt.h>
16 #include <asm-generic/barrier.h>
17 #include <gs.h>
18
19 static volatile int guarded = 0;
20 static struct gs_cb gs_cb;
21 static struct gs_epl gs_epl;
22 static unsigned long gs_area = 0x2000000;
23
24 void gs_handler(struct gs_cb *this_cb);
25
load_guarded(unsigned long * p)26 static inline unsigned long load_guarded(unsigned long *p)
27 {
28 unsigned long v;
29
30 asm(".insn rxy,0xe3000000004c, %0,%1"
31 : "=d" (v)
32 : "m" (*p)
33 : "r14", "memory");
34 return v;
35 }
36
37 /* guarded-storage event handler and finally it calls gs_handler */
38 extern void gs_handler_asm(void);
39 asm ( ".macro STGSC args:vararg\n"
40 " .insn rxy,0xe30000000049,\\args\n"
41 " .endm\n"
42 " .globl gs_handler_asm\n"
43 "gs_handler_asm:\n"
44 " lgr %r14,%r15\n" /* Save current stack address in r14 */
45 ".Lgs_handler_frame = 16*8+32+" xstr(STACK_FRAME_SIZE) "\n"
46 " aghi %r15,-(.Lgs_handler_frame)\n" /* Allocate stack frame */
47 " stmg %r0,%r13,192(%r15)\n" /* Store regs to save area */
48 " stg %r14,312(%r15)\n"
49 " la %r2," xstr(STACK_FRAME_SIZE) "(%r15)\n" /* Store gscb address in this_cb */
50 " STGSC %r0," xstr(STACK_FRAME_SIZE) "(%r15)\n"
51 " lg %r14,24(%r2)\n" /* Get GSEPLA from GSCB*/
52 " lg %r14,40(%r14)\n" /* Get GSERA from GSEPL*/
53 " stg %r14,304(%r15)\n" /* Store GSERA in r14 of reg save area */
54 " brasl %r14,gs_handler\n" /* Jump to gs_handler */
55 " lmg %r0,%r15,192(%r15)\n" /* Restore regs */
56 " aghi %r14, 6\n" /* Add lgg instr len to GSERA */
57 " br %r14\n" /* Jump to next instruction after lgg */
58 ".size gs_handler_asm,.-gs_handler_asm\n"
59 );
60
gs_handler(struct gs_cb * this_cb)61 void gs_handler(struct gs_cb *this_cb)
62 {
63 guarded = 1;
64 struct gs_epl *gs_epl = (struct gs_epl *) this_cb->gs_epl_a;
65 printf("gs_handler called for %016lx at %016lx\n",
66 gs_epl->gs_eir, gs_epl->gs_eia);
67 }
68
69 /* Test if load guarded gets intercepted. */
test_load(void)70 static void test_load(void)
71 {
72 unsigned long v;
73
74 guarded = 0;
75 v = load_guarded(&gs_area);
76 report(guarded, "load guarded %ld", v);
77 guarded = 0;
78 }
79
80 /* Test gs instructions without enablement resulting in an exception */
test_special(void)81 static void test_special(void)
82 {
83 report_prefix_push("disabled gs");
84 report_prefix_push("load gs");
85 expect_pgm_int();
86 load_gs_cb(&gs_cb);
87 check_pgm_int_code(PGM_INT_CODE_SPECIAL_OPERATION);
88 report_prefix_pop();
89
90 report_prefix_push("store gs");
91 expect_pgm_int();
92 store_gs_cb(&gs_cb);
93 check_pgm_int_code(PGM_INT_CODE_SPECIAL_OPERATION);
94 report_prefix_pop();
95
96 report_prefix_pop();
97 }
98
init(void)99 static void init(void)
100 {
101 /* Enable control bit for gs */
102 ctl_set_bit(2, CTL2_GUARDED_STORAGE);
103
104 /* Setup gs registers to guard the gs_area */
105 gs_cb.gsd = gs_area | 25;
106
107 /* Check all 512kb slots for events */
108 gs_cb.gssm = 0xffffffffffffffffULL;
109 gs_cb.gs_epl_a = (unsigned long) &gs_epl;
110
111 /* Register handler */
112 gs_epl.gs_eha = (unsigned long) gs_handler_asm;
113 load_gs_cb(&gs_cb);
114 }
115
main(void)116 int main(void)
117 {
118 bool has_gs = test_facility(133);
119
120 report_prefix_push("gs");
121 if (!has_gs) {
122 report_skip("Guarded storage is not available");
123 goto done;
124 }
125
126 test_special();
127 init();
128 test_load();
129
130 done:
131 report_prefix_pop();
132 return report_summary();
133 }
134