From: Dan Wu <dan1.wu@intel.com>
To: seanjc@google.com, pbonzini@redhat.com, kvm@vger.kernel.org
Cc: xiaoyao.li@intel.com, dan1.wu@intel.com
Subject: [kvm-unit-tests PATCH v1 2/3] x86: Add async page fault int test
Date: Tue, 12 Dec 2023 14:27:07 +0800 [thread overview]
Message-ID: <20231212062708.16509-3-dan1.wu@intel.com> (raw)
In-Reply-To: <20231212062708.16509-1-dan1.wu@intel.com>
KVM switched to use interrupt for 'page ready' APF event since Linux v5.10 and
the legacy mechanism using #PF was deprecated. Add a new test for interrupt
based 'page ready' APF event delivery.
Signed-off-by: Dan Wu <dan1.wu@intel.com>
Reviewed-by: Xiaoyao Li <xiaoyao.li@intel.com>
---
The test is based on asyncpf.c and simplifies implementation.
---
ci/cirrus-ci-fedora.yml | 1 +
lib/x86/processor.h | 6 ++
x86/Makefile.common | 3 +-
x86/asyncpf_int.c | 127 ++++++++++++++++++++++++++++++++++++++++
x86/unittests.cfg | 4 ++
5 files changed, 140 insertions(+), 1 deletion(-)
create mode 100644 x86/asyncpf_int.c
diff --git a/ci/cirrus-ci-fedora.yml b/ci/cirrus-ci-fedora.yml
index 918c9a36..52cb10c6 100644
--- a/ci/cirrus-ci-fedora.yml
+++ b/ci/cirrus-ci-fedora.yml
@@ -22,6 +22,7 @@ fedora_task:
- ./run_tests.sh
access
asyncpf
+ asyncpf_int
debug
emulator
ept
diff --git a/lib/x86/processor.h b/lib/x86/processor.h
index 44f4fd1e..1a0f1243 100644
--- a/lib/x86/processor.h
+++ b/lib/x86/processor.h
@@ -263,6 +263,12 @@ static inline bool is_intel(void)
#define X86_FEATURE_ARCH_CAPABILITIES (CPUID(0x7, 0, EDX, 29))
#define X86_FEATURE_PKS (CPUID(0x7, 0, ECX, 31))
+/*
+ * KVM defined leafs
+ */
+#define KVM_FEATURE_ASYNC_PF (CPUID(0x40000001, 0, EAX, 4))
+#define KVM_FEATURE_ASYNC_PF_INT (CPUID(0x40000001, 0, EAX, 14))
+
/*
* Extended Leafs, a.k.a. AMD defined
*/
diff --git a/x86/Makefile.common b/x86/Makefile.common
index 4ae9a557..c4b309e3 100644
--- a/x86/Makefile.common
+++ b/x86/Makefile.common
@@ -90,7 +90,8 @@ tests-common = $(TEST_DIR)/vmexit.$(exe) $(TEST_DIR)/tsc.$(exe) \
$(TEST_DIR)/emulator.$(exe) \
$(TEST_DIR)/eventinj.$(exe) \
$(TEST_DIR)/smap.$(exe) \
- $(TEST_DIR)/umip.$(exe)
+ $(TEST_DIR)/umip.$(exe) \
+ $(TEST_DIR)/asyncpf_int.$(exe)
# The following test cases are disabled when building EFI tests because they
# use absolute addresses in their inline assembly code, which cannot compile
diff --git a/x86/asyncpf_int.c b/x86/asyncpf_int.c
new file mode 100644
index 00000000..84268f6b
--- /dev/null
+++ b/x86/asyncpf_int.c
@@ -0,0 +1,127 @@
+/*
+ * Async PF Int test. For the test to actually do anything it needs to be started
+ * in memory cgroup with 512M of memory and with more than 1G memory provided
+ * to the guest.
+ *
+ * To identify the cgroup version on Linux:
+ * stat -fc %T /sys/fs/cgroup/
+ *
+ * If the output is tmpfs, your system is using cgroup v1:
+ * To create cgroup do as root:
+ * mkdir /dev/cgroup
+ * mount -t cgroup none -omemory /dev/cgroup
+ * chmod a+rxw /dev/cgroup/
+ * From a shell you will start qemu from:
+ * mkdir /dev/cgroup/1
+ * echo $$ > /dev/cgroup/1/tasks
+ * echo 512M > /dev/cgroup/1/memory.limit_in_bytes
+ *
+ * If the output is cgroup2fs, your system is using cgroup v2:
+ * mkdir /sys/fs/cgroup/cg1
+ * echo $$ > /sys/fs/cgroup/cg1/cgroup.procs
+ * echo 512M > /sys/fs/cgroup/cg1/memory.max
+ *
+ */
+#include "x86/processor.h"
+#include "x86/apic.h"
+#include "x86/isr.h"
+#include "x86/vm.h"
+#include "alloc.h"
+#include "vmalloc.h"
+#include "asyncpf.h"
+
+struct kvm_vcpu_pv_apf_data apf_reason;
+
+char *buf;
+void* virt;
+volatile uint64_t i;
+volatile uint64_t phys;
+volatile uint32_t saved_token;
+volatile uint32_t asyncpf_num;
+
+static inline uint32_t get_and_clear_apf_reason(void)
+{
+ uint32_t r = apf_reason.flags;
+ apf_reason.flags = 0;
+ return r;
+}
+
+static void handle_interrupt(isr_regs_t *regs)
+{
+ uint32_t apf_token = apf_reason.token;
+
+ apf_reason.token = 0;
+ wrmsr(MSR_KVM_ASYNC_PF_ACK, 1);
+
+ if (apf_token == 0xffffffff) {
+ report_pass("Wakeup all, got token 0x%x", apf_token);
+ } else if (apf_token == saved_token) {
+ asyncpf_num++;
+ install_pte(phys_to_virt(read_cr3()), 1, virt, phys | PT_PRESENT_MASK | PT_WRITABLE_MASK, 0);
+ phys = 0;
+ } else {
+ report_fail("unexpected async pf int token 0x%x", apf_token);
+ }
+
+ eoi();
+}
+
+static void handle_pf(struct ex_regs *r)
+{
+ virt = (void*)((ulong)(buf+i) & ~(PAGE_SIZE-1));
+ uint32_t reason = get_and_clear_apf_reason();
+ switch (reason) {
+ case 0:
+ report_fail("unexpected #PF at %#lx", read_cr2());
+ exit(report_summary());
+ case KVM_PV_REASON_PAGE_NOT_PRESENT:
+ phys = virt_to_pte_phys(phys_to_virt(read_cr3()), virt);
+ install_pte(phys_to_virt(read_cr3()), 1, virt, phys, 0);
+ write_cr3(read_cr3());
+ saved_token = read_cr2();
+ while (phys) {
+ safe_halt(); /* enables irq */
+ }
+ break;
+ default:
+ report_fail("unexpected async pf with reason 0x%x", reason);
+ exit(report_summary());
+ }
+}
+
+#define MEM (1ull*1024*1024*1024)
+
+int main(int ac, char **av)
+{
+ if (!this_cpu_has(KVM_FEATURE_ASYNC_PF)) {
+ report_skip("KVM_FEATURE_ASYNC_PF is not supported\n");
+ return report_summary();
+ }
+
+ if (!this_cpu_has(KVM_FEATURE_ASYNC_PF_INT)) {
+ report_skip("KVM_FEATURE_ASYNC_PF_INT is not supported\n");
+ return report_summary();
+ }
+
+ setup_vm();
+
+ handle_exception(PF_VECTOR, handle_pf);
+ handle_irq(HYPERVISOR_CALLBACK_VECTOR, handle_interrupt);
+ memset(&apf_reason, 0, sizeof(apf_reason));
+
+ wrmsr(MSR_KVM_ASYNC_PF_INT, HYPERVISOR_CALLBACK_VECTOR);
+ wrmsr(MSR_KVM_ASYNC_PF_EN, virt_to_phys((void*)&apf_reason) |
+ KVM_ASYNC_PF_SEND_ALWAYS | KVM_ASYNC_PF_ENABLED | KVM_ASYNC_PF_DELIVERY_AS_INT);
+
+ buf = malloc(MEM);
+ sti();
+
+ /* access a lot of memory to make host swap it out */
+ for (i = 0; i < MEM; i += 4096)
+ buf[i] = 1;
+
+ cli();
+ report(asyncpf_num > 0, "get %d async pf events ('page not present' #PF event with matched "
+ "'page ready' interrupt event )", asyncpf_num);
+ return report_summary();
+}
diff --git a/x86/unittests.cfg b/x86/unittests.cfg
index 3fe59449..8735ba34 100644
--- a/x86/unittests.cfg
+++ b/x86/unittests.cfg
@@ -174,6 +174,10 @@ extra_params = -cpu max
file = asyncpf.flat
extra_params = -m 2048
+[asyncpf_int]
+file = asyncpf_int.flat
+extra_params = -cpu host -m 2048
+
[emulator]
file = emulator.flat
--
2.39.3
next prev parent reply other threads:[~2023-12-12 6:27 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-12-12 6:27 [kvm-unit-tests PATCH v1 0/3] x86: fix async page fault issues Dan Wu
2023-12-12 6:27 ` [kvm-unit-tests PATCH v1 1/3] x86: Add a common header asyncpf.h Dan Wu
2023-12-12 6:27 ` Dan Wu [this message]
2023-12-12 6:27 ` [kvm-unit-tests PATCH v1 3/3] x86/asyncpf: Add CPUID feature bits check to ensure feature is available Dan Wu
2023-12-12 15:17 ` [kvm-unit-tests PATCH v1 0/3] x86: fix async page fault issues Sean Christopherson
2023-12-13 1:36 ` Wu, Dan1
2023-12-13 18:20 ` Sean Christopherson
2023-12-14 2:32 ` Wu, Dan1
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=20231212062708.16509-3-dan1.wu@intel.com \
--to=dan1.wu@intel.com \
--cc=kvm@vger.kernel.org \
--cc=pbonzini@redhat.com \
--cc=seanjc@google.com \
--cc=xiaoyao.li@intel.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.