All of lore.kernel.org
 help / color / mirror / Atom feed
From: Claudio Imbrenda <imbrenda@linux.ibm.com>
To: pbonzini@redhat.com
Cc: kvm@vger.kernel.org, thuth@redhat.com, frankja@linux.ibm.com,
	Janis Schoetterl-Glausch <scgl@linux.ibm.com>
Subject: [kvm-unit-tests GIT PULL 21/28] s390x: Test effect of storage keys on some instructions
Date: Thu, 12 May 2022 11:35:16 +0200	[thread overview]
Message-ID: <20220512093523.36132-22-imbrenda@linux.ibm.com> (raw)
In-Reply-To: <20220512093523.36132-1-imbrenda@linux.ibm.com>

From: Janis Schoetterl-Glausch <scgl@linux.ibm.com>

Some instructions are emulated by KVM. Test that KVM correctly emulates
storage key checking for two of those instructions (STORE CPU ADDRESS,
SET PREFIX).
Test success and error conditions, including coverage of storage and
fetch protection override.
Also add test for TEST PROTECTION, even if that instruction will not be
emulated by KVM under normal conditions.

Signed-off-by: Janis Schoetterl-Glausch <scgl@linux.ibm.com>
Acked-by: Thomas Huth <thuth@redhat.com>
Acked-by: Janosch Frank <frankja@linux.ibm.com>
Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
---
 lib/s390x/asm/arch_def.h |  20 ++--
 s390x/skey.c             | 249 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 260 insertions(+), 9 deletions(-)

diff --git a/lib/s390x/asm/arch_def.h b/lib/s390x/asm/arch_def.h
index 46c370e6..72553819 100644
--- a/lib/s390x/asm/arch_def.h
+++ b/lib/s390x/asm/arch_def.h
@@ -55,15 +55,17 @@ struct psw {
 #define PSW_MASK_BA			0x0000000080000000UL
 #define PSW_MASK_64			(PSW_MASK_BA | PSW_MASK_EA)
 
-#define CTL0_LOW_ADDR_PROT		(63 - 35)
-#define CTL0_EDAT			(63 - 40)
-#define CTL0_IEP			(63 - 43)
-#define CTL0_AFP			(63 - 45)
-#define CTL0_VECTOR			(63 - 46)
-#define CTL0_EMERGENCY_SIGNAL		(63 - 49)
-#define CTL0_EXTERNAL_CALL		(63 - 50)
-#define CTL0_CLOCK_COMPARATOR		(63 - 52)
-#define CTL0_SERVICE_SIGNAL		(63 - 54)
+#define CTL0_LOW_ADDR_PROT			(63 - 35)
+#define CTL0_EDAT				(63 - 40)
+#define CTL0_FETCH_PROTECTION_OVERRIDE		(63 - 38)
+#define CTL0_STORAGE_PROTECTION_OVERRIDE	(63 - 39)
+#define CTL0_IEP				(63 - 43)
+#define CTL0_AFP				(63 - 45)
+#define CTL0_VECTOR				(63 - 46)
+#define CTL0_EMERGENCY_SIGNAL			(63 - 49)
+#define CTL0_EXTERNAL_CALL			(63 - 50)
+#define CTL0_CLOCK_COMPARATOR			(63 - 52)
+#define CTL0_SERVICE_SIGNAL			(63 - 54)
 #define CR0_EXTM_MASK			0x0000000000006200UL /* Combined external masks */
 
 #define CTL2_GUARDED_STORAGE		(63 - 59)
diff --git a/s390x/skey.c b/s390x/skey.c
index edad53e9..32bf1070 100644
--- a/s390x/skey.c
+++ b/s390x/skey.c
@@ -10,6 +10,7 @@
 #include <libcflat.h>
 #include <asm/asm-offsets.h>
 #include <asm/interrupt.h>
+#include <vmalloc.h>
 #include <asm/page.h>
 #include <asm/facility.h>
 #include <asm/mem.h>
@@ -118,6 +119,249 @@ static void test_invalid_address(void)
 	report_prefix_pop();
 }
 
+static void test_test_protection(void)
+{
+	unsigned long addr = (unsigned long)pagebuf;
+
+	report_prefix_push("TPROT");
+
+	set_storage_key(pagebuf, 0x10, 0);
+	report(tprot(addr, 0) == TPROT_READ_WRITE, "zero key: no protection");
+	report(tprot(addr, 1) == TPROT_READ_WRITE, "matching key: no protection");
+
+	report_prefix_push("mismatching key");
+
+	report(tprot(addr, 2) == TPROT_READ, "no fetch protection: store protection");
+
+	set_storage_key(pagebuf, 0x18, 0);
+	report(tprot(addr, 2) == TPROT_RW_PROTECTED,
+	       "fetch protection: fetch & store protection");
+
+	report_prefix_push("fetch-protection override");
+	set_storage_key(0, 0x18, 0);
+	report(tprot(0, 2) == TPROT_RW_PROTECTED, "disabled: fetch & store protection");
+	ctl_set_bit(0, CTL0_FETCH_PROTECTION_OVERRIDE);
+	report(tprot(0, 2) == TPROT_READ, "enabled: store protection");
+	report(tprot(2048, 2) == TPROT_RW_PROTECTED, "invalid: fetch & store protection");
+	ctl_clear_bit(0, CTL0_FETCH_PROTECTION_OVERRIDE);
+	set_storage_key(0, 0x00, 0);
+	report_prefix_pop();
+
+	ctl_set_bit(0, CTL0_STORAGE_PROTECTION_OVERRIDE);
+	set_storage_key(pagebuf, 0x90, 0);
+	report(tprot(addr, 2) == TPROT_READ_WRITE,
+	       "storage-protection override: no protection");
+	ctl_clear_bit(0, CTL0_STORAGE_PROTECTION_OVERRIDE);
+
+	report_prefix_pop();
+	set_storage_key(pagebuf, 0x00, 0);
+	report_prefix_pop();
+}
+
+/*
+ * Perform STORE CPU ADDRESS (STAP) instruction while temporarily executing
+ * with access key 1.
+ */
+static void store_cpu_address_key_1(uint16_t *out)
+{
+	asm volatile (
+		"spka	0x10\n\t"
+		"stap	%0\n\t"
+		"spka	0\n"
+	     : "+Q" (*out) /* exception: old value remains in out -> + constraint */
+	);
+}
+
+static void test_store_cpu_address(void)
+{
+	uint16_t *out = (uint16_t *)pagebuf;
+	uint16_t cpu_addr;
+
+	report_prefix_push("STORE CPU ADDRESS");
+	asm ("stap %0" : "=Q" (cpu_addr));
+
+	report_prefix_push("zero key");
+	set_storage_key(pagebuf, 0x20, 0);
+	WRITE_ONCE(*out, 0xbeef);
+	asm ("stap %0" : "=Q" (*out));
+	report(*out == cpu_addr, "store occurred");
+	report_prefix_pop();
+
+	report_prefix_push("matching key");
+	set_storage_key(pagebuf, 0x10, 0);
+	*out = 0xbeef;
+	store_cpu_address_key_1(out);
+	report(*out == cpu_addr, "store occurred");
+	report_prefix_pop();
+
+	report_prefix_push("mismatching key");
+	set_storage_key(pagebuf, 0x20, 0);
+	expect_pgm_int();
+	*out = 0xbeef;
+	store_cpu_address_key_1(out);
+	check_pgm_int_code(PGM_INT_CODE_PROTECTION);
+	report(*out == 0xbeef, "no store occurred");
+	report_prefix_pop();
+
+	ctl_set_bit(0, CTL0_STORAGE_PROTECTION_OVERRIDE);
+
+	report_prefix_push("storage-protection override, invalid key");
+	set_storage_key(pagebuf, 0x20, 0);
+	expect_pgm_int();
+	*out = 0xbeef;
+	store_cpu_address_key_1(out);
+	check_pgm_int_code(PGM_INT_CODE_PROTECTION);
+	report(*out == 0xbeef, "no store occurred");
+	report_prefix_pop();
+
+	report_prefix_push("storage-protection override, override key");
+	set_storage_key(pagebuf, 0x90, 0);
+	*out = 0xbeef;
+	store_cpu_address_key_1(out);
+	report(*out == cpu_addr, "override occurred");
+	report_prefix_pop();
+
+	ctl_clear_bit(0, CTL0_STORAGE_PROTECTION_OVERRIDE);
+
+	report_prefix_push("storage-protection override disabled, override key");
+	set_storage_key(pagebuf, 0x90, 0);
+	expect_pgm_int();
+	*out = 0xbeef;
+	store_cpu_address_key_1(out);
+	check_pgm_int_code(PGM_INT_CODE_PROTECTION);
+	report(*out == 0xbeef, "no store occurred");
+	report_prefix_pop();
+
+	set_storage_key(pagebuf, 0x00, 0);
+	report_prefix_pop();
+}
+
+/*
+ * Perform SET PREFIX (SPX) instruction while temporarily executing
+ * with access key 1.
+ */
+static void set_prefix_key_1(uint32_t *prefix_ptr)
+{
+	asm volatile (
+		"spka	0x10\n\t"
+		"spx	%0\n\t"
+		"spka	0\n"
+	     :: "Q" (*prefix_ptr)
+	);
+}
+
+/*
+ * We remapped page 0, making the lowcore inaccessible, which breaks the normal
+ * handler and breaks skipping the faulting instruction.
+ * Just disable dynamic address translation to make things work.
+ */
+static void dat_fixup_pgm_int(void)
+{
+	uint64_t psw_mask = extract_psw_mask();
+
+	psw_mask &= ~PSW_MASK_DAT;
+	load_psw_mask(psw_mask);
+}
+
+#define PREFIX_AREA_SIZE (PAGE_SIZE * 2)
+static char lowcore_tmp[PREFIX_AREA_SIZE] __attribute__((aligned(PREFIX_AREA_SIZE)));
+
+/*
+ * Test accessibility of the operand to SET PREFIX given different configurations
+ * with regards to storage keys. That is, check the accessibility of the location
+ * holding the new prefix, not that of the new prefix area. The new prefix area
+ * is a valid lowcore, so that the test does not crash on failure.
+ */
+static void test_set_prefix(void)
+{
+	uint32_t *prefix_ptr = (uint32_t *)pagebuf;
+	uint32_t *no_override_prefix_ptr;
+	uint32_t old_prefix;
+	pgd_t *root;
+
+	report_prefix_push("SET PREFIX");
+	root = (pgd_t *)(stctg(1) & PAGE_MASK);
+	old_prefix = get_prefix();
+	memcpy(lowcore_tmp, 0, sizeof(lowcore_tmp));
+	assert(((uint64_t)&lowcore_tmp >> 31) == 0);
+	*prefix_ptr = (uint32_t)(uint64_t)&lowcore_tmp;
+
+	report_prefix_push("zero key");
+	set_prefix(old_prefix);
+	set_storage_key(prefix_ptr, 0x20, 0);
+	set_prefix(*prefix_ptr);
+	report(get_prefix() == *prefix_ptr, "set prefix");
+	report_prefix_pop();
+
+	report_prefix_push("matching key");
+	set_prefix(old_prefix);
+	set_storage_key(pagebuf, 0x10, 0);
+	set_prefix_key_1(prefix_ptr);
+	report(get_prefix() == *prefix_ptr, "set prefix");
+	report_prefix_pop();
+
+	report_prefix_push("mismatching key");
+
+	report_prefix_push("no fetch protection");
+	set_prefix(old_prefix);
+	set_storage_key(pagebuf, 0x20, 0);
+	set_prefix_key_1(prefix_ptr);
+	report(get_prefix() == *prefix_ptr, "set prefix");
+	report_prefix_pop();
+
+	report_prefix_push("fetch protection");
+	set_prefix(old_prefix);
+	set_storage_key(pagebuf, 0x28, 0);
+	expect_pgm_int();
+	set_prefix_key_1(prefix_ptr);
+	check_pgm_int_code(PGM_INT_CODE_PROTECTION);
+	report(get_prefix() == old_prefix, "did not set prefix");
+	report_prefix_pop();
+
+	register_pgm_cleanup_func(dat_fixup_pgm_int);
+
+	report_prefix_push("remapped page, fetch protection");
+	set_prefix(old_prefix);
+	set_storage_key(pagebuf, 0x28, 0);
+	expect_pgm_int();
+	install_page(root, virt_to_pte_phys(root, pagebuf), 0);
+	set_prefix_key_1((uint32_t *)0);
+	install_page(root, 0, 0);
+	check_pgm_int_code(PGM_INT_CODE_PROTECTION);
+	report(get_prefix() == old_prefix, "did not set prefix");
+	report_prefix_pop();
+
+	ctl_set_bit(0, CTL0_FETCH_PROTECTION_OVERRIDE);
+
+	report_prefix_push("fetch protection override applies");
+	set_prefix(old_prefix);
+	set_storage_key(pagebuf, 0x28, 0);
+	install_page(root, virt_to_pte_phys(root, pagebuf), 0);
+	set_prefix_key_1((uint32_t *)0);
+	install_page(root, 0, 0);
+	report(get_prefix() == *prefix_ptr, "set prefix");
+	report_prefix_pop();
+
+	no_override_prefix_ptr = (uint32_t *)(pagebuf + 2048);
+	WRITE_ONCE(*no_override_prefix_ptr, (uint32_t)(uint64_t)&lowcore_tmp);
+	report_prefix_push("fetch protection override does not apply");
+	set_prefix(old_prefix);
+	set_storage_key(pagebuf, 0x28, 0);
+	expect_pgm_int();
+	install_page(root, virt_to_pte_phys(root, pagebuf), 0);
+	set_prefix_key_1((uint32_t *)2048);
+	install_page(root, 0, 0);
+	check_pgm_int_code(PGM_INT_CODE_PROTECTION);
+	report(get_prefix() == old_prefix, "did not set prefix");
+	report_prefix_pop();
+
+	ctl_clear_bit(0, CTL0_FETCH_PROTECTION_OVERRIDE);
+	register_pgm_cleanup_func(NULL);
+	report_prefix_pop();
+	set_storage_key(pagebuf, 0x00, 0);
+	report_prefix_pop();
+}
+
 int main(void)
 {
 	report_prefix_push("skey");
@@ -130,6 +374,11 @@ int main(void)
 	test_set();
 	test_set_mb();
 	test_chg();
+	test_test_protection();
+	test_store_cpu_address();
+
+	setup_vm();
+	test_set_prefix();
 done:
 	report_prefix_pop();
 	return report_summary();
-- 
2.36.1


  parent reply	other threads:[~2022-05-12  9:37 UTC|newest]

Thread overview: 33+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-05-12  9:34 [kvm-unit-tests GIT PULL 00/28] storage keys, attestation, migration tests Claudio Imbrenda
2022-05-12  9:34 ` [kvm-unit-tests GIT PULL 01/28] s390x: gs: move to new header file Claudio Imbrenda
2022-05-12  9:34 ` [kvm-unit-tests GIT PULL 02/28] s390x: add test for SIGP STORE_ADTL_STATUS order Claudio Imbrenda
2022-09-20 15:53   ` Thomas Huth
2022-10-05 13:18     ` Nico Boehr
2022-10-05 13:25       ` Thomas Huth
2022-10-05 14:00         ` Nico Boehr
2022-05-12  9:34 ` [kvm-unit-tests GIT PULL 03/28] s390x: epsw: fix report_pop_prefix() when running under non-QEMU Claudio Imbrenda
2022-05-12  9:34 ` [kvm-unit-tests GIT PULL 04/28] s390x: tprot: use lib include for mmu.h Claudio Imbrenda
2022-05-12  9:35 ` [kvm-unit-tests GIT PULL 05/28] s390x: smp: make stop stopped cpu look the same as the running case Claudio Imbrenda
2022-05-12  9:35 ` [kvm-unit-tests GIT PULL 06/28] lib: s390x: hardware: Add host_is_qemu() function Claudio Imbrenda
2022-05-12  9:35 ` [kvm-unit-tests GIT PULL 07/28] s390x: css: Skip if we're not run by qemu Claudio Imbrenda
2022-05-12  9:35 ` [kvm-unit-tests GIT PULL 08/28] s390x: diag308: Only test subcode 2 under QEMU Claudio Imbrenda
2022-05-12  9:35 ` [kvm-unit-tests GIT PULL 09/28] s390x: pfmf: Initialize pfmf_r1 union on declaration Claudio Imbrenda
2022-05-12  9:35 ` [kvm-unit-tests GIT PULL 10/28] s390x: snippets: asm: Add license and copyright headers Claudio Imbrenda
2022-05-12  9:35 ` [kvm-unit-tests GIT PULL 11/28] s390x: pv-diags: Cleanup includes Claudio Imbrenda
2022-05-12  9:35 ` [kvm-unit-tests GIT PULL 12/28] s390x: css: " Claudio Imbrenda
2022-05-12  9:35 ` [kvm-unit-tests GIT PULL 13/28] s390x: iep: " Claudio Imbrenda
2022-05-12  9:35 ` [kvm-unit-tests GIT PULL 14/28] s390x: mvpg: " Claudio Imbrenda
2022-05-12  9:35 ` [kvm-unit-tests GIT PULL 15/28] s390x: uv-host: Fix pgm tests Claudio Imbrenda
2022-05-12  9:35 ` [kvm-unit-tests GIT PULL 16/28] lib: s390x: add support for SCLP console read Claudio Imbrenda
2022-05-12  9:35 ` [kvm-unit-tests GIT PULL 17/28] s390x: add support for migration tests Claudio Imbrenda
2022-05-12  9:35 ` [kvm-unit-tests GIT PULL 18/28] s390x: don't run migration tests under PV Claudio Imbrenda
2022-05-12  9:35 ` [kvm-unit-tests GIT PULL 19/28] s390x: add basic migration test Claudio Imbrenda
2022-05-12  9:35 ` [kvm-unit-tests GIT PULL 20/28] s390x: Give name to return value of tprot() Claudio Imbrenda
2022-05-12  9:35 ` Claudio Imbrenda [this message]
2022-05-12  9:35 ` [kvm-unit-tests GIT PULL 22/28] Disable s390x skey test in GitLab CI Claudio Imbrenda
2022-05-12  9:35 ` [kvm-unit-tests GIT PULL 23/28] s390x: uv-host: Add invalid command attestation check Claudio Imbrenda
2022-05-12  9:35 ` [kvm-unit-tests GIT PULL 24/28] s390x: lib: Add QUI getter Claudio Imbrenda
2022-05-12  9:35 ` [kvm-unit-tests GIT PULL 25/28] s390x: uv-guest: remove duplicated checks Claudio Imbrenda
2022-05-12  9:35 ` [kvm-unit-tests GIT PULL 26/28] s390x: uv-guest: Remove double report_prefix_pop Claudio Imbrenda
2022-05-12  9:35 ` [kvm-unit-tests GIT PULL 27/28] s390x: uv-guest: add share bit test Claudio Imbrenda
2022-05-12  9:35 ` [kvm-unit-tests GIT PULL 28/28] s390x: Add attestation tests Claudio Imbrenda

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20220512093523.36132-22-imbrenda@linux.ibm.com \
    --to=imbrenda@linux.ibm.com \
    --cc=frankja@linux.ibm.com \
    --cc=kvm@vger.kernel.org \
    --cc=pbonzini@redhat.com \
    --cc=scgl@linux.ibm.com \
    --cc=thuth@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.