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