diff mbox series

[v2,7/8] KVM: selftests: Expect #PF(RSVD) when TDP is disabled

Message ID 20221018214612.3445074-8-dmatlack@google.com (mailing list archive)
State New, archived
Headers show
Series KVM: selftests: Fix and clean up emulator_error_test | expand

Commit Message

David Matlack Oct. 18, 2022, 9:46 p.m. UTC
Change smaller_maxphyaddr_emulation_test to expect a #PF(RSVD), rather
than an emulation failure, when TDP is disabled. KVM only needs to
emulate instructions to emulate a smaller guest.MAXPHYADDR when TDP is
enabled.

Fixes: 39bbcc3a4e39 ("selftests: kvm: Allows userspace to handle emulation errors.")
Signed-off-by: David Matlack <dmatlack@google.com>
---
 .../smaller_maxphyaddr_emulation_test.c       | 45 +++++++++++++++++--
 1 file changed, 41 insertions(+), 4 deletions(-)

Comments

Sean Christopherson Oct. 28, 2022, 12:31 a.m. UTC | #1
On Tue, Oct 18, 2022, David Matlack wrote:
> @@ -50,6 +73,9 @@ int main(int argc, char *argv[])
>  	TEST_REQUIRE(kvm_has_cap(KVM_CAP_SMALLER_MAXPHYADDR));
>  
>  	vm = vm_create_with_one_vcpu(&vcpu, guest_code);
> +	vm_init_descriptor_tables(vm);
> +	vcpu_init_descriptor_tables(vcpu);
> +	vm_install_exception_handler(vm, PF_VECTOR, guest_page_fault_handler);

Instead of installing an exception handler,

	u8 vector = kvm_asm_safe(KVM_ASM_SAFE(FLDS_MEM_EAX),
				 "a"(MEM_REGION_GVA));

then the guest/test can provide more precise information if a #PF doesn't occur.
David Matlack Oct. 28, 2022, 11:51 p.m. UTC | #2
On Thu, Oct 27, 2022 at 5:31 PM Sean Christopherson <seanjc@google.com> wrote:
>
> On Tue, Oct 18, 2022, David Matlack wrote:
> > @@ -50,6 +73,9 @@ int main(int argc, char *argv[])
> >       TEST_REQUIRE(kvm_has_cap(KVM_CAP_SMALLER_MAXPHYADDR));
> >
> >       vm = vm_create_with_one_vcpu(&vcpu, guest_code);
> > +     vm_init_descriptor_tables(vm);
> > +     vcpu_init_descriptor_tables(vcpu);
> > +     vm_install_exception_handler(vm, PF_VECTOR, guest_page_fault_handler);
>
> Instead of installing an exception handler,
>
>         u8 vector = kvm_asm_safe(KVM_ASM_SAFE(FLDS_MEM_EAX),
>                                  "a"(MEM_REGION_GVA));
>
> then the guest/test can provide more precise information if a #PF doesn't occur.

I gave this a shot and realized this would prevent checking that it is
a reserved #PF, since kvm_asm_safe() only returns the vector.

It's probably more important to have more precise testing rather than
more precise failure reporting. But what did you have in mind
specifically? Maybe there's another way.
Sean Christopherson Oct. 31, 2022, 4:47 p.m. UTC | #3
On Fri, Oct 28, 2022, David Matlack wrote:
> On Thu, Oct 27, 2022 at 5:31 PM Sean Christopherson <seanjc@google.com> wrote:
> >
> > On Tue, Oct 18, 2022, David Matlack wrote:
> > > @@ -50,6 +73,9 @@ int main(int argc, char *argv[])
> > >       TEST_REQUIRE(kvm_has_cap(KVM_CAP_SMALLER_MAXPHYADDR));
> > >
> > >       vm = vm_create_with_one_vcpu(&vcpu, guest_code);
> > > +     vm_init_descriptor_tables(vm);
> > > +     vcpu_init_descriptor_tables(vcpu);
> > > +     vm_install_exception_handler(vm, PF_VECTOR, guest_page_fault_handler);
> >
> > Instead of installing an exception handler,
> >
> >         u8 vector = kvm_asm_safe(KVM_ASM_SAFE(FLDS_MEM_EAX),
> >                                  "a"(MEM_REGION_GVA));
> >
> > then the guest/test can provide more precise information if a #PF doesn't occur.
> 
> I gave this a shot and realized this would prevent checking that it is
> a reserved #PF, since kvm_asm_safe() only returns the vector.
> 
> It's probably more important to have more precise testing rather than
> more precise failure reporting. But what did you have in mind
> specifically? Maybe there's another way.

I didn't have anything in mind, I just overlooked the error code.  That said, this
is a good excuse to expand KVM_ASM_SAFE() to provide the error code.  There's
already a clobbered scratch register (two, actually) that can be used to propagate
the error code from the exception handler back to the asm blob, so it's easy to
squeeze into the existing framework.

Patches attached.
diff mbox series

Patch

diff --git a/tools/testing/selftests/kvm/x86_64/smaller_maxphyaddr_emulation_test.c b/tools/testing/selftests/kvm/x86_64/smaller_maxphyaddr_emulation_test.c
index 91a85a00b692..afa9e0b3dd8a 100644
--- a/tools/testing/selftests/kvm/x86_64/smaller_maxphyaddr_emulation_test.c
+++ b/tools/testing/selftests/kvm/x86_64/smaller_maxphyaddr_emulation_test.c
@@ -21,6 +21,12 @@ 
 #define MEM_REGION_SLOT	10
 #define MEM_REGION_SIZE PAGE_SIZE
 
+static void guest_page_fault_handler(struct ex_regs *regs)
+{
+	GUEST_ASSERT(regs->error_code & PFERR_RSVD_MASK);
+	GUEST_SYNC(PF_VECTOR);
+}
+
 static void guest_code(void)
 {
 	flds(MEM_REGION_GVA);
@@ -36,6 +42,23 @@  static void assert_ucall_done(struct kvm_vcpu *vcpu)
 		    uc.cmd, UCALL_DONE);
 }
 
+static void assert_reserved_page_fault(struct kvm_vcpu *vcpu)
+{
+	struct ucall uc;
+
+	switch (get_ucall(vcpu, &uc)) {
+	case UCALL_ABORT:
+		REPORT_GUEST_ASSERT(uc);
+		break;
+	case UCALL_SYNC:
+		TEST_ASSERT(uc.args[1] == PF_VECTOR,
+			    "Unexpected UCALL_SYNC: %lu", uc.args[1]);
+		break;
+	default:
+		TEST_FAIL("Unrecognized ucall: %lu\n", uc.cmd);
+	}
+}
+
 int main(int argc, char *argv[])
 {
 	struct kvm_vcpu *vcpu;
@@ -50,6 +73,9 @@  int main(int argc, char *argv[])
 	TEST_REQUIRE(kvm_has_cap(KVM_CAP_SMALLER_MAXPHYADDR));
 
 	vm = vm_create_with_one_vcpu(&vcpu, guest_code);
+	vm_init_descriptor_tables(vm);
+	vcpu_init_descriptor_tables(vcpu);
+	vm_install_exception_handler(vm, PF_VECTOR, guest_page_fault_handler);
 
 	vcpu_set_cpuid_maxphyaddr(vcpu, MAXPHYADDR);
 
@@ -70,10 +96,21 @@  int main(int argc, char *argv[])
 	vm_set_page_table_entry(vm, vcpu, MEM_REGION_GVA, pte | (1ull << 36));
 
 	vcpu_run(vcpu);
-	assert_exit_for_flds_emulation_failure(vcpu);
-	skip_flds_instruction(vcpu);
-	vcpu_run(vcpu);
-	assert_ucall_done(vcpu);
+
+	/*
+	 * When TDP is enabled, KVM must emulate the flds instruction, which
+	 * results in an emulation failure out to userspace. Otherwise, no
+	 * instruction emulation is required so check that the instruction
+	 * generates #PF(RSVD).
+	 */
+	if (kvm_is_tdp_enabled()) {
+		assert_exit_for_flds_emulation_failure(vcpu);
+		skip_flds_instruction(vcpu);
+		vcpu_run(vcpu);
+		assert_ucall_done(vcpu);
+	} else {
+		assert_reserved_page_fault(vcpu);
+	}
 
 	kvm_vm_free(vm);