On 20.03.2018 12:19, Janosch Frank wrote: > Guarded storage was introduced with IBM z14. Loads with the special > instruction LOAD GUARDED are suspect to access controls if they fall > into a guarded area. A handler is called if such an access is > detected. The test checks for exceptions if the instructions are > executed without cr2 enablement and tests handler execution on load > guarded. > > The initial test case is once again from Martin Schwidefsky with minor > adaptions by me for kvm-unit-tests. > > Signed-off-by: Janosch Frank <frankja@xxxxxxxxxxxxxxxxxx> > --- > s390x/Makefile | 1 + > s390x/gs.c | 170 ++++++++++++++++++++++++++++++++++++++++++++++++++++ > s390x/unittests.cfg | 3 + > 3 files changed, 174 insertions(+) > create mode 100644 s390x/gs.c > > diff --git a/s390x/Makefile b/s390x/Makefile > index 47013d1..b44efb5 100644 > --- a/s390x/Makefile > +++ b/s390x/Makefile > @@ -8,6 +8,7 @@ tests += $(TEST_DIR)/diag10.elf > tests += $(TEST_DIR)/pfmf.elf > tests += $(TEST_DIR)/cmm.elf > tests += $(TEST_DIR)/vector.elf > +tests += $(TEST_DIR)/gs.elf > > all: directories test_cases > > diff --git a/s390x/gs.c b/s390x/gs.c > new file mode 100644 > index 0000000..ea66697 > --- /dev/null > +++ b/s390x/gs.c > @@ -0,0 +1,170 @@ > +/* > + * Tests guarded storage support. > + * > + * Copyright 2018 IBM Corp. > + * > + * Authors: > + * Martin Schwidefsky <schwidefsky@xxxxxxxxxx> > + * Janosch Frank <frankja@xxxxxxxxxx> > + * > + * This code is free software; you can redistribute it and/or modify it > + * under the terms of the GNU Library General Public License version 2. > + */ > +#include <libcflat.h> > +#include <asm/page.h> > +#include <asm/facility.h> > +#include <asm/interrupt.h> > +#include <asm-generic/barrier.h> > + > +struct gs_cb { > + uint64_t reserved; > + uint64_t gsd; > + uint64_t gssm; > + uint64_t gs_epl_a; > +}; > + > +struct gs_epl { > + uint8_t pad1; > + union { > + uint8_t gs_eam; > + struct { > + uint8_t : 6; > + uint8_t e : 1; > + uint8_t b : 1; > + }; > + }; > + union { > + uint8_t gs_eci; > + struct { > + uint8_t tx : 1; > + uint8_t cx : 1; > + uint8_t : 5; > + uint8_t in : 1; > + }; > + }; > + union { > + uint8_t gs_eai; > + struct { > + uint8_t : 1; > + uint8_t t : 1; > + uint8_t as : 2; > + uint8_t ar : 4; > + }; > + }; > + uint32_t pad2; > + uint64_t gs_eha; > + uint64_t gs_eia; > + uint64_t gs_eoa; > + uint64_t gs_eir; > + uint64_t gs_era; > +}; > + > +static volatile int guarded = 0; > +static struct gs_cb gs_cb; > +static struct gs_epl gs_epl; > +static unsigned long gs_area = 0x2000000; > + > +static inline void load_gs_cb(struct gs_cb *gs_cb) > +{ > + asm volatile(".insn rxy,0xe3000000004d,0,%0" : : "Q" (*gs_cb)); > +} > + > +static inline void store_gs_cb(struct gs_cb *gs_cb) > +{ > + asm volatile(".insn rxy,0xe30000000049,0,%0" : : "Q" (*gs_cb)); > +} > + > +static inline unsigned long load_guarded(unsigned long *p) > +{ > + unsigned long v; > + > + asm(".insn rxy,0xe3000000004c, %0,%1" > + : "=d" (v) > + : "m" (*p) > + : "r14", "memory"); > + return v; > +} > + > +/* guarded-storage event handler and finally it calls gs_handler */ > +extern void gs_handler_asm(void); > + asm(".globl gs_handler_asm\n" > + "gs_handler_asm:\n" > + " lgr %r14,%r15\n" /* Save current stack address in r14 */ > + " aghi %r15,-320\n" /* Allocate stack frame */ > + " stmg %r0,%r14,192(%r15)\n" /* Store regs to save area */ Not sure, but I think r0 to r13 would be enough here? Since r14 is overwritten with the value from GSERA below? > + " stg %r14,312(%r15)\n" > + " la %r2,160(%r15)\n" /* Store gscb address in this_cb */ > + " .insn rxy,0xe30000000049,0,160(%r15)\n" /* stgsc */ > + " lg %r14,24(%r2)\n" /* Get GSEPLA from GSCB*/ > + " lg %r14,40(%r14)\n" /* Get GSERA from GSEPL*/ > + " stg %r14,304(%r15)\n" /* Store GSEPL in r14 of reg save area */ s/GSEPL/GSERA/ in above comment? > + " brasl %r14,gs_handler\n" /* Jump to gs_handler */ > + " lmg %r0,%r15,192(%r15)\n" /* Restore regs */ > + " aghi %r14, 6\n" /* Add lgg instr len to GSERA */ > + " br %r14\n" /* Jump to next instruction after lgg */ > + " .size gs_handler_asm,.-gs_handler_asm\n"); > + > +void gs_handler(struct gs_cb *this_cb) > +{ > + guarded = 1; > + struct gs_epl *gs_epl = (struct gs_epl *) this_cb->gs_epl_a; > + printf("gs_handler called for %016lx at %016lx\n", > + gs_epl->gs_eir, gs_epl->gs_eia); > +} > + > +/* Test if load guarded gets intercepted. */ > +static void test_load(void) > +{ > + unsigned long v; > + > + guarded = 0; > + v = load_guarded(&gs_area); > + report("load guarded %ld", guarded, v); > + guarded = 0; > +} > + > +/* Test gs instructions without enablement resulting in an exception */ > +static void test_special(void) > +{ > + expect_pgm_int(); > + load_gs_cb(&gs_cb); > + check_pgm_int_code(PGM_INT_CODE_SPECIAL_OPERATION); > + expect_pgm_int(); > + store_gs_cb(&gs_cb); > + check_pgm_int_code(PGM_INT_CODE_SPECIAL_OPERATION); > +} > + > +static void init(void) > +{ > + /* Enable control bit for gs */ > + ctl_set_bit(2, 4); > + > + /* Setup gs registers to guard the gs_area */ > + gs_cb.gsd = gs_area | 25; > + > + /* Check all 512kb slots for events */ > + gs_cb.gssm = 0xFFFFFFFFFFFFFFFF; It's rather just cosmetical here, but please add a "ULL" suffix to the value. > + gs_cb.gs_epl_a = (unsigned long) &gs_epl; > + > + /* Register handler */ > + gs_epl.gs_eha = (unsigned long) gs_handler_asm; > + load_gs_cb(&gs_cb); > +} > + > +int main(void) > +{ > + bool has_gs = test_facility(133); > + > + report_prefix_push("gs"); > + report_xfail("Guarded storage available", !has_gs, has_gs); > + if (!has_gs) > + goto done; > + > + test_special(); > + init(); > + test_load(); > + > +done: > + report_prefix_pop(); > + return report_summary(); > +} Apart from the nits, this looks good to me. When you fixed the nits: Reviewed-by: Thomas Huth <thuth@xxxxxxxxxx>