On 20.03.2018 12:19, Janosch Frank wrote: > Storage keys are not used by Linux anymore, so let's show them some > love and test if the basics still work. > > Signed-off-by: Janosch Frank <frankja@xxxxxxxxxxxxxxxxxx> > --- > lib/s390x/asm/mem.h | 52 +++++++++++++++++++++++++++++ > s390x/Makefile | 1 + > s390x/skey.c | 94 +++++++++++++++++++++++++++++++++++++++++++++++++++++ > s390x/unittests.cfg | 3 ++ > 4 files changed, 150 insertions(+) > create mode 100644 lib/s390x/asm/mem.h > create mode 100644 s390x/skey.c > > diff --git a/lib/s390x/asm/mem.h b/lib/s390x/asm/mem.h > new file mode 100644 > index 0000000..909e6d4 > --- /dev/null > +++ b/lib/s390x/asm/mem.h > @@ -0,0 +1,52 @@ > +/* > + * Physical memory management related functions and definitions. > + * > + * Copyright IBM Corp. 2018 > + * Author(s): 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. > + */ > +#ifndef _ASM_S390_MEM_H > +#define _ASM_S390_MEM_H > + > +union skey { > + struct { > + uint8_t acc : 4; > + uint8_t fp : 1; > + uint8_t rf : 1; > + uint8_t ch : 1; > + uint8_t pad : 1; > + } str; > + uint8_t val; > +}; > + > +static inline void set_storage_key(unsigned long addr, > + unsigned char skey, > + int nq) > +{ > + if (nq) > + asm volatile(".insn rrf,0xb22b0000,%0,%1,8,0" > + : : "d" (skey), "a" (addr)); > + else > + asm volatile("sske %0,%1" : : "d" (skey), "a" (addr)); > +} > + > +static inline unsigned long set_storage_key_mb(unsigned long addr, > + unsigned char skey) > +{ > + assert(test_facility(8)); > + > + asm volatile(".insn rrf,0xb22b0000,%[skey],%[addr],1,0" > + : [addr] "+a" (addr) : [skey] "d" (skey)); > + return addr; > +} > + > +static inline unsigned char get_storage_key(unsigned long addr) > +{ > + unsigned char skey; > + > + asm volatile("iske %0,%1" : "=d" (skey) : "a" (addr)); > + return skey; > +} > +#endif > diff --git a/s390x/Makefile b/s390x/Makefile > index e062727..b73031d 100644 > --- a/s390x/Makefile > +++ b/s390x/Makefile > @@ -3,6 +3,7 @@ tests += $(TEST_DIR)/intercept.elf > tests += $(TEST_DIR)/emulator.elf > tests += $(TEST_DIR)/sieve.elf > tests += $(TEST_DIR)/sthyi.elf > +tests += $(TEST_DIR)/skey.elf > > all: directories test_cases > > diff --git a/s390x/skey.c b/s390x/skey.c > new file mode 100644 > index 0000000..e4c2a43 > --- /dev/null > +++ b/s390x/skey.c > @@ -0,0 +1,94 @@ > +/* > + * Storage key tests > + * > + * Copyright (c) 2018 IBM Corp > + * > + * Authors: > + * Janosch Frank <frankja@xxxxxxxxxxxxxxxxxx> > + * > + * 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/asm-offsets.h> > +#include <asm/interrupt.h> > +#include <asm/page.h> > +#include <asm/facility.h> > +#include <asm/mem.h> > + > + > +static uint8_t pagebuf[PAGE_SIZE * 2] __attribute__((aligned(PAGE_SIZE * 2))); > +const unsigned long page0 = (unsigned long)pagebuf; > +const unsigned long page1 = (unsigned long)(pagebuf + PAGE_SIZE); > + > +static void test_set_mb(void) > +{ > + union skey skey, ret1, ret2; > + unsigned long addr = 0x10000 - 2 * PAGE_SIZE; > + unsigned long end = 0x10000; > + > + /* Multi block support came with EDAT 1 */ > + if (!test_facility(8)) > + return; > + > + skey.val = 0x30; > + while (addr < end) > + addr = set_storage_key_mb(addr, skey.val); > + > + ret1.val = get_storage_key(end - PAGE_SIZE); > + ret2.val = get_storage_key(end - PAGE_SIZE * 2); > + report("multi block", ret1.val == ret2.val && ret1.val == skey.val); > +} > + > +static void test_chg(void) > +{ > + union skey skey1, skey2; > + > + skey1.val = 0x30; > + set_storage_key(page0, skey1.val, 0); > + skey1.val = get_storage_key(page0); > + pagebuf[0] = 3; > + skey2.val = get_storage_key(page0); > + report("chg bit test", !skey1.str.ch && skey2.str.ch); > +} > + > +static void test_set(void) > +{ > + union skey skey, ret; > + > + skey.val = 0x30; > + ret.val = get_storage_key(page0); > + set_storage_key(page0, skey.val, 0); > + ret.val = get_storage_key(page0); > + report("set key test", skey.val == ret.val); > +} > + > +static void test_priv(void) > +{ > + union skey skey; > + > + memset(pagebuf, 0, PAGE_SIZE * 2); > + expect_pgm_int(); > + enter_pstate(); > + set_storage_key(page0, 0x30, 0); > + check_pgm_int_code(PGM_INT_CODE_PRIVILEGED_OPERATION); > + > + skey.val = get_storage_key(page0); > + report("skey did not change on exception", skey.str.acc != 3); > + > + expect_pgm_int(); > + enter_pstate(); > + get_storage_key(page0); > + check_pgm_int_code(PGM_INT_CODE_PRIVILEGED_OPERATION); > +} > + > +int main(void) > +{ > + report_prefix_push("skey"); > + test_priv(); > + test_set(); > + test_set_mb(); > + test_chg(); > + report_prefix_pop(); > + return report_summary(); > +} > diff --git a/s390x/unittests.cfg b/s390x/unittests.cfg > index 506891a..8321e9b 100644 > --- a/s390x/unittests.cfg > +++ b/s390x/unittests.cfg > @@ -38,3 +38,6 @@ timeout = 600 > [sthyi] > file = sthyi.elf > accel = kvm > + > +[skey] > +file = skey.elf > Reviewed-by: Thomas Huth <thuth@xxxxxxxxxx>