new file mode 100644
@@ -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
@@ -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
new file mode 100644
@@ -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();
+}
@@ -37,3 +37,6 @@ timeout = 600
[sthyi]
file = sthyi.elf
+
+[skey]
+file = skey.elf