Re: [kvm-unit-tests PATCH 5/8] s390x: Add pfmf tests

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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?

> +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.

> +	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.

> +	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.

> +	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



[Index of Archives]     [KVM ARM]     [KVM ia64]     [KVM ppc]     [Virtualization Tools]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Questions]     [Linux Kernel]     [Linux SCSI]     [XFree86]

  Powered by Linux