[kvm-unit-tests,PULL,3/8] s390x: Add storage keys tests
diff mbox

Message ID 1522222784-7709-4-git-send-email-thuth@redhat.com
State New
Headers show

Commit Message

Thomas Huth March 28, 2018, 7:39 a.m. UTC
From: Janosch Frank <frankja@linux.vnet.ibm.com>

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@linux.vnet.ibm.com>
Reviewed-by: Thomas Huth <thuth@redhat.com>
Signed-off-by: Thomas Huth <thuth@redhat.com>
---
 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

Patch
diff mbox

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@de.ibm.com>
+ *
+ * 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 f68d8a7..c860ed8 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@linux.vnet.ibm.com>
+ *
+ * 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 258189e..c98cddd 100644
--- a/s390x/unittests.cfg
+++ b/s390x/unittests.cfg
@@ -37,3 +37,6 @@  timeout = 600
 
 [sthyi]
 file = sthyi.elf
+
+[skey]
+file = skey.elf