On 14.03.2018 05:59, Thomas Huth wrote: > On 13.03.2018 13:01, Janosch Frank wrote: >> Perform Frame Management Functions (pfmf) is an instruction that sets >> storage keys or clears memory for frames in the size of 4k, 1m and >> 2g. Hence it's quite complex and deserves some testing. >> >> Signed-off-by: Janosch Frank <frankja@xxxxxxxxxxxxxxxxxx> >> --- >> s390x/Makefile | 1 + >> s390x/pfmf.c | 143 ++++++++++++++++++++++++++++++++++++++++++++++++++++ >> s390x/unittests.cfg | 3 ++ >> 3 files changed, 147 insertions(+) >> create mode 100644 s390x/pfmf.c >> >> diff --git a/s390x/Makefile b/s390x/Makefile >> index bc5dd91..438c6b2 100644 >> --- a/s390x/Makefile >> +++ b/s390x/Makefile >> @@ -5,6 +5,7 @@ tests += $(TEST_DIR)/sieve.elf >> tests += $(TEST_DIR)/sthyi.elf >> tests += $(TEST_DIR)/skey.elf >> tests += $(TEST_DIR)/diag10.elf >> +tests += $(TEST_DIR)/pfmf.elf >> >> all: directories test_cases >> >> diff --git a/s390x/pfmf.c b/s390x/pfmf.c >> new file mode 100644 >> index 0000000..fe31a82 >> --- /dev/null >> +++ b/s390x/pfmf.c >> @@ -0,0 +1,143 @@ >> +/* >> + * Perform Frame Management Function (pfmf) tests >> + * >> + * Copyright (c) 2017 IBM >> + * >> + * 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> >> + >> +#define FSC_4K 0 >> +#define FSC_1M 1 >> +#define FSC_2G 3 > > According to my version of the PoP, FSC_2G should be 2 instead? Yes, it should be 2. Well it seems, I never tested 2G and it came to haunt me. > >> +union r1 { >> + struct { >> + unsigned long pad0 : 32; >> + unsigned long pad1 : 12; >> + unsigned long pad_fmfi : 2; >> + unsigned long sk : 1; /* set key*/ >> + unsigned long cf : 1; /* clear frame */ >> + unsigned long ui : 1; /* usage indication */ >> + unsigned long fsc : 3; >> + unsigned long pad2 : 1; >> + unsigned long mr : 1; >> + unsigned long mc : 1; >> + unsigned long pad3 : 1; >> + unsigned long key : 8; /* storage keys */ >> + } reg; >> + unsigned long val; >> +}; >> + >> +static uint8_t pagebuf[PAGE_SIZE * 256] __attribute__((aligned(PAGE_SIZE * 256))); >> + >> +static inline unsigned long pfmf(unsigned long r1, unsigned long paddr) >> +{ >> + register uint64_t addr asm("1") = paddr; >> + >> + asm volatile(".insn rrf,0xb9af0000,%[r1],%[addr],0,0" > > PFMF is only "rre", not "rrf". Then you can also omit the ",0,0" here. > >> + : [addr] "+a" (addr) : [r1] "d" (r1)); > > Since pfmf can be used to clear memory, you should add "memory" to the > clobber list. Good catch > >> + return addr; >> +} >> + >> +static void test_priv(void) >> +{ >> + expect_pgm_int(); >> + enter_pstate(); >> + pfmf(0, (unsigned long) pagebuf); >> + check_pgm_int_code(PGM_INT_CODE_PRIVILEGED_OPERATION); >> +} >> + >> +static void test_4k_key(void) >> +{ >> + union r1 r1; >> + union skey skey; >> + >> + r1.val = 0; >> + r1.reg.sk = 1; >> + r1.reg.fsc = FSC_4K; >> + r1.reg.key = 0x30; >> + pfmf(r1.val, (unsigned long) pagebuf); >> + skey.val = get_storage_key((unsigned long) pagebuf); >> + report("set 4k", skey.val == 0x30); >> +} >> + >> +static void test_1m_key(void) >> +{ >> + int i; >> + union r1 r1; >> + >> + if (!test_facility(8)) >> + return; > > You already checked that in the main() function, no need to check it > here again. Ugh, yes. > >> + r1.val = 0; >> + r1.reg.sk = 1; >> + r1.reg.fsc = FSC_1M; >> + r1.reg.key = 0x30; >> + pfmf(r1.val, (unsigned long) pagebuf); >> + for (i = 0; i < 256; i++) { >> + if (get_storage_key((unsigned long) pagebuf + i * PAGE_SIZE) != 0x30) { >> + report("set 1M", false); >> + return; >> + } >> + } >> + report("set 1M", true); >> +} >> + >> +static void test_4k_clear(void) >> +{ >> + union r1 r1; >> + >> + r1.val = 0; >> + r1.reg.cf = 1; >> + r1.reg.fsc = FSC_4K; >> + >> + memset(pagebuf, 42, PAGE_SIZE); >> + pfmf(r1.val, (unsigned long) pagebuf); >> + report("clear 4k", !memcmp(pagebuf, pagebuf + PAGE_SIZE, PAGE_SIZE)); >> +} >> + >> +static void test_1m_clear(void) >> +{ >> + int i; >> + union r1 r1; >> + unsigned long sum = 0; >> + >> + r1.val = 0; >> + r1.reg.cf = 1; >> + r1.reg.fsc = FSC_1M; >> + >> + memset(pagebuf, 42, PAGE_SIZE * 256); >> + pfmf(r1.val, (unsigned long) pagebuf); >> + for (i = 0; i < PAGE_SIZE * 256; i++) >> + sum += pagebuf[i]; > > Maybe better use "|=" instead of "+=" to avoid that the sum wraps around > to 0 again by accident. Sure > >> + report("clear 1m", !sum); >> +} >> + >> +int main(void) >> +{ >> + if (!test_facility(8)) { >> + printf("EDAT facility not available, hence pfmf is not available."); >> + return 0; >> + } >> + >> + report_prefix_push("pfmf"); >> + test_priv(); >> + /* Force the buffer pages in */ >> + memset(pagebuf, 0, PAGE_SIZE * 256); >> + >> + test_4k_key(); >> + test_1m_key(); >> + test_4k_clear(); >> + test_1m_clear(); >> + return report_summary(); >> +} > > Thomas >
Attachment:
signature.asc
Description: OpenPGP digital signature