linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/1] selftest for SPP feature
@ 2019-06-19  2:02 Weijiang Yang
  2019-06-19  2:03 ` [PATCH 1/1] kvm: selftests: add " Weijiang Yang
  0 siblings, 1 reply; 2+ messages in thread
From: Weijiang Yang @ 2019-06-19  2:02 UTC (permalink / raw)
  To: kvm, linux-kernel, pbonzini, mst, rkrcmar, jmattson, yu.c.zhang
  Cc: Yang Weijiang

From: Yang Weijiang <weijiang.yang@intel.com>

Sub-Page Permission(SPP) is to protect finer granularity subpages
(128Byte each) within a 4KB page. 
There're three specific ioctls for the feature in KVM:
KVM_INIT_SPP - initialize SPP runtime environment 
KVM_SUBPAGES_SET_ACCESS - set SPP protection for guest page
KVM_SUBPAGES_GET_ACCESS - get SPP permission bits for guest page
This selftest uses these ioctls to verify whether SPP is working
on SPP powered platforms.

test results:
--------------------------------------------------------------------------
SPP protected zone: size = 4096, gva = 0x700000, gpa = 0x10001000, hva =
0x0x7f6ff3b92000
SPP initialized successfully.
set spp protection info: gfn = 0x10001, access = 0x0, npages = 1
get spp protection info: gfn = 0x10001, access = 0x0, npages = 1
got matched subpage permission vector.
expect VM exits caused by SPP below.
1 - exit reason: SPP
2 - exit reason: SPP
3 - exit reason: SPP
4 - exit reason: SPP
5 - exit reason: SPP
6 - exit reason: SPP
7 - exit reason: SPP
8 - exit reason: SPP
9 - exit reason: SPP
10 - exit reason: SPP
11 - exit reason: SPP
12 - exit reason: SPP
13 - exit reason: SPP
14 - exit reason: SPP
15 - exit reason: SPP
16 - exit reason: SPP
17 - exit reason: SPP
18 - exit reason: SPP
19 - exit reason: SPP
20 - exit reason: SPP
21 - exit reason: SPP
22 - exit reason: SPP
23 - exit reason: SPP
24 - exit reason: SPP
25 - exit reason: SPP
26 - exit reason: SPP
27 - exit reason: SPP
28 - exit reason: SPP
29 - exit reason: SPP
30 - exit reason: SPP
31 - exit reason: SPP
32 - exit reason: SPP
total EPT violation count: 32
unset SPP protection at gfn: 0x10001
expect NO VM exits caused by SPP below.
completed SPP test successfully!
------------------------------------------------------------------------


Yang Weijiang (1):
  kvm: selftests: add selftest for SPP feature

 tools/testing/selftests/kvm/Makefile          |   1 +
 tools/testing/selftests/kvm/lib/kvm_util.c    |   1 +
 tools/testing/selftests/kvm/x86_64/spp_test.c | 206 ++++++++++++++++++
 3 files changed, 208 insertions(+)
 create mode 100644 tools/testing/selftests/kvm/x86_64/spp_test.c

-- 
2.17.2


^ permalink raw reply	[flat|nested] 2+ messages in thread

* [PATCH 1/1] kvm: selftests: add selftest for SPP feature
  2019-06-19  2:02 [PATCH 0/1] selftest for SPP feature Weijiang Yang
@ 2019-06-19  2:03 ` Weijiang Yang
  0 siblings, 0 replies; 2+ messages in thread
From: Weijiang Yang @ 2019-06-19  2:03 UTC (permalink / raw)
  To: kvm, linux-kernel, pbonzini, mst, rkrcmar, jmattson, yu.c.zhang
  Cc: Yang Weijiang

From: Yang Weijiang <weijiang.yang@intel.com>

Sub-Page Permission(SPP) is to protect finer granularity subpages
(128Byte each) within a 4KB page. It's not enabled in KVM by default,
the test first initializes the SPP runtime environment with
KVM_INIT_SPP ioctl, then sets protection with KVM_SUBPAGES_SET_ACCESS
for the target guest page, check permissions with KVM_SUBPAGES_GET_ACCESS
to make sure they are set as expected.

There're two steps in guest code to very whether SPP is working:
1) protect all 128byte subpages, write data to each subpage
to see if SPP induced EPT violation happening. 2)unprotect all
subpages, again write data to each subpage to see if SPP still
works or not.

Signed-off-by: Yang Weijiang <weijiang.yang@intel.com>
---
 tools/testing/selftests/kvm/Makefile          |   1 +
 tools/testing/selftests/kvm/lib/kvm_util.c    |   1 +
 tools/testing/selftests/kvm/x86_64/spp_test.c | 206 ++++++++++++++++++
 3 files changed, 208 insertions(+)
 create mode 100644 tools/testing/selftests/kvm/x86_64/spp_test.c

diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile
index f8588cca2bef..5e82376016fc 100644
--- a/tools/testing/selftests/kvm/Makefile
+++ b/tools/testing/selftests/kvm/Makefile
@@ -20,6 +20,7 @@ TEST_GEN_PROGS_x86_64 += x86_64/evmcs_test
 TEST_GEN_PROGS_x86_64 += x86_64/hyperv_cpuid
 TEST_GEN_PROGS_x86_64 += x86_64/vmx_close_while_nested_test
 TEST_GEN_PROGS_x86_64 += x86_64/smm_test
+TEST_GEN_PROGS_x86_64 += x86_64/spp_test
 TEST_GEN_PROGS_x86_64 += dirty_log_test
 TEST_GEN_PROGS_x86_64 += clear_dirty_log_test
 
diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c
index 4ca96b228e46..04533144da53 100644
--- a/tools/testing/selftests/kvm/lib/kvm_util.c
+++ b/tools/testing/selftests/kvm/lib/kvm_util.c
@@ -1422,6 +1422,7 @@ static struct exit_reason {
 	{KVM_EXIT_UNKNOWN, "UNKNOWN"},
 	{KVM_EXIT_EXCEPTION, "EXCEPTION"},
 	{KVM_EXIT_IO, "IO"},
+	{KVM_EXIT_SPP, "SPP"},
 	{KVM_EXIT_HYPERCALL, "HYPERCALL"},
 	{KVM_EXIT_DEBUG, "DEBUG"},
 	{KVM_EXIT_HLT, "HLT"},
diff --git a/tools/testing/selftests/kvm/x86_64/spp_test.c b/tools/testing/selftests/kvm/x86_64/spp_test.c
new file mode 100644
index 000000000000..f8425a5a6b49
--- /dev/null
+++ b/tools/testing/selftests/kvm/x86_64/spp_test.c
@@ -0,0 +1,206 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Sub-Page Permission test
+ *
+ * Copyright (C) 2019, Intel Corp.
+ *
+ */
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+
+#include "test_util.h"
+#include "kvm_util.h"
+#include "processor.h"
+#include "../../lib/kvm_util_internal.h"
+
+#define VCPU_ID           1
+#define PAGE_SIZE         (4096)
+#define SPP_GUARD_SIZE    (16 * PAGE_SIZE)
+#define SPP_GUARD_MEMSLOT (1)
+#define SPP_GUARD_PAGES   (SPP_GUARD_SIZE / PAGE_SIZE)
+#define SPP_GUARD_GPA      0x10000000
+
+#define SUBPAGE_ACCESS_DEFAULT   (0x0)
+#define SUBPAGE_ACCESS_FULL      (0xFFFFFFFF)
+#define START_SPP_VM_ADDR        (0x700000)
+#define SUBPAGE_SIZE             (128)
+
+vm_vaddr_t vspp_start;
+vm_paddr_t pspp_start;
+
+void guest_code(void)
+{
+	uint8_t *iterator = (uint8_t *)vspp_start;
+	int count;
+
+	GUEST_SYNC(1);
+	/*
+	 * expect EPT violation induced by SPP in each interation since
+	 * the full page is protected by SPP.
+	 */
+	for (count = 0; count < PAGE_SIZE / SUBPAGE_SIZE; count++) {
+		*(uint32_t *)(iterator) = 0x99;
+		iterator += SUBPAGE_SIZE;
+	}
+	GUEST_SYNC(2);
+	iterator = (uint8_t *)vspp_start;
+
+	/*
+	 * don't expect EPT violation happen since SPP is disabled
+	 * for the page
+	 */
+	for (count = 0; count < PAGE_SIZE / SUBPAGE_SIZE; count++) {
+		*(uint32_t *)(iterator) = 0x99;
+		iterator += SUBPAGE_SIZE;
+	}
+}
+
+void prepare_test(struct kvm_vm **g_vm, struct kvm_run **g_run)
+{
+	void *spp_hva;
+	struct kvm_vm *vm;
+	struct kvm_run *run;
+	/* Create VM, SPP is only valid for 4KB page mode */
+	*g_vm = vm_create_default(VCPU_ID, 0, guest_code);
+	vm = *g_vm;
+
+	*g_run = vcpu_state(vm, VCPU_ID);
+	run = *g_run;
+
+	vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, SPP_GUARD_GPA,
+				    SPP_GUARD_MEMSLOT, SPP_GUARD_PAGES, 0);
+
+	pspp_start = vm_phy_pages_alloc(vm, 1, SPP_GUARD_GPA,
+					SPP_GUARD_MEMSLOT);
+
+	memset(addr_gpa2hva(vm, SPP_GUARD_GPA), 0x0, PAGE_SIZE);
+
+	virt_map(vm, START_SPP_VM_ADDR, SPP_GUARD_GPA, PAGE_SIZE, 0);
+
+	vspp_start = vm_vaddr_alloc(vm, PAGE_SIZE, START_SPP_VM_ADDR,
+				    SPP_GUARD_MEMSLOT, 0);
+
+	spp_hva = addr_gva2hva(vm, vspp_start);
+
+	pspp_start = addr_hva2gpa(vm, spp_hva);
+
+	printf("SPP protected zone: size = %d, gva = 0x%llx, gpa = 0x%llx, "
+	       "hva = 0x%p\n", PAGE_SIZE, vspp_start, pspp_start, spp_hva);
+
+	/* make sure the virtual address is visible to VM. */
+	sync_global_to_guest(vm, vspp_start);
+
+	_vcpu_run(vm, VCPU_ID);
+
+	TEST_ASSERT(run->exit_reason == KVM_EXIT_IO,
+		    "exit reason: %u (%s),\n", run->exit_reason,
+		     exit_reason_str(run->exit_reason));
+}
+
+void setup_spp(struct kvm_vm *vm)
+{
+	struct kvm_subpage spp_info = {0};
+	int ret;
+
+	/* initialize the SPP runtime environment.*/
+	ret = ioctl(vm->fd, KVM_INIT_SPP, 0);
+
+	TEST_ASSERT(ret == 0, "KVM_INIT_SPP failed.");
+
+	printf("SPP initialized successfully.\n");
+
+	/* set up SPP protection for the page. */
+	spp_info.npages = 1;
+	spp_info.base_gfn = pspp_start >> 12;
+	spp_info.access_map[0] = SUBPAGE_ACCESS_DEFAULT;
+	ret = ioctl(vm->fd, KVM_SUBPAGES_SET_ACCESS, &spp_info);
+
+	TEST_ASSERT(ret == 1, "KVM_SUBPAGES_SET_ACCESS failed. ret = 0x%x, "
+		    "base_gfn = 0x%llx\n", ret, spp_info.base_gfn);
+	printf("set spp protection info: gfn = 0x%llx, access = 0x%lx, "
+	       "npages = %d\n", spp_info.base_gfn, spp_info.access_map[0],
+	       spp_info.npages);
+
+	/* make sure the SPP permission bits are actully set as expected. */
+	memset(&spp_info, 0, sizeof(spp_info));
+	spp_info.npages = 1;
+	spp_info.base_gfn = pspp_start >> 12;
+
+	ret = ioctl(vm->fd, KVM_SUBPAGES_GET_ACCESS, &spp_info);
+
+	TEST_ASSERT(ret == 1, "KVM_SUBPAGES_GET_ACCESS failed.");
+
+	TEST_ASSERT(spp_info.access_map[0] == SUBPAGE_ACCESS_DEFAULT,
+		    "subpage access didn't match.");
+	printf("get spp protection info: gfn = 0x%llx, access = 0x%lx, "
+	       "npages = %d\n", spp_info.base_gfn,
+	       spp_info.access_map[0], spp_info.npages);
+
+	printf("got matched subpage permission vector.\n");
+	printf("expect VM exits caused by SPP below.\n");
+}
+
+void unset_spp(struct kvm_vm *vm)
+{
+	struct kvm_subpage spp_info = {0};
+	int ret;
+
+	/* now unprotect the SPP to the page.*/
+	spp_info.base_gfn = pspp_start >> 12;
+	spp_info.access_map[0] = SUBPAGE_ACCESS_FULL;
+	ret = ioctl(vm->fd, KVM_SUBPAGES_SET_ACCESS, &spp_info);
+
+	printf("unset SPP protection at gfn: 0x%llx\n", spp_info.base_gfn);
+	printf("expect NO VM exits caused by SPP below.\n");
+}
+
+void run_test(struct kvm_vm *vm, struct kvm_run *run)
+{
+	int loop;
+	int ept_fault;
+
+	_vcpu_run(vm, VCPU_ID);
+
+	for (loop = 0; loop < PAGE_SIZE / SUBPAGE_SIZE; loop++) {
+		/*
+		 * if everything goes correctly, should get VM exit
+		 * with KVM_EXIT_SPP.
+		 */
+		TEST_ASSERT(run->exit_reason == KVM_EXIT_SPP,
+			    "exit reason: %u (%s),\n", run->exit_reason,
+			    exit_reason_str(run->exit_reason));
+		printf("%d - exit reason: %s\n", loop + 1,
+		       exit_reason_str(run->exit_reason));
+		ept_fault++;
+		_vcpu_run(vm, VCPU_ID);
+	}
+
+	printf("total EPT violation count: %d\n", ept_fault);
+}
+
+int main(int argc, char *argv[])
+{
+	struct kvm_vm *vm;
+	struct kvm_run *run;
+
+	prepare_test(&vm, &run);
+
+	setup_spp(vm);
+
+	run_test(vm, run);
+
+	unset_spp(vm);
+
+	_vcpu_run(vm, VCPU_ID);
+
+	printf("completed SPP test successfully!\n");
+
+	kvm_vm_free(vm);
+
+	return 0;
+}
+
-- 
2.17.2


^ permalink raw reply related	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2019-06-19  2:04 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-06-19  2:02 [PATCH 0/1] selftest for SPP feature Weijiang Yang
2019-06-19  2:03 ` [PATCH 1/1] kvm: selftests: add " Weijiang Yang

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).