Message ID | 20221031180045.3581757-5-dmatlack@google.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | KVM: selftests: Fix and clean up emulator_error_test | expand |
On Mon, Oct 31, 2022, David Matlack wrote: > Move the flds instruction emulation failure handling code to a header > so it can be re-used in an upcoming test. > > No functional change intended. > > Signed-off-by: David Matlack <dmatlack@google.com> > --- > .../selftests/kvm/x86_64/flds_emulation.h | 59 +++++++++++++++++++ > .../smaller_maxphyaddr_emulation_test.c | 45 ++------------ > 2 files changed, 64 insertions(+), 40 deletions(-) > create mode 100644 tools/testing/selftests/kvm/x86_64/flds_emulation.h > > diff --git a/tools/testing/selftests/kvm/x86_64/flds_emulation.h b/tools/testing/selftests/kvm/x86_64/flds_emulation.h > new file mode 100644 > index 000000000000..be0b4e0dd722 > --- /dev/null > +++ b/tools/testing/selftests/kvm/x86_64/flds_emulation.h > @@ -0,0 +1,59 @@ > +/* SPDX-License-Identifier: GPL-2.0-only */ > +#ifndef SELFTEST_KVM_FLDS_EMULATION_H > +#define SELFTEST_KVM_FLDS_EMULATION_H > + > +#include "kvm_util.h" > + > +#define FLDS_MEM_EAX ".byte 0xd9, 0x00" > + > +/* > + * flds is an instruction that the KVM instruction emulator is known not to > + * support. This can be used in guest code along with a mechanism to force > + * KVM to emulate the instruction (e.g. by providing an MMIO address) to > + * exercise emulation failures. > + */ > +static inline void flds(uint64_t address) > +{ > + __asm__ __volatile__(FLDS_MEM_EAX :: "a"(address)); > +} > + > +static inline void assert_exit_for_flds_emulation_failure(struct kvm_vcpu *vcpu) I think it makes sense to keeping the bundling of the assert+skip. As written, the last test doesn't need to skip, but that may not always hold true, e.g. if the test adds more stages to verify KVM handles page splits correctly, and even when a skip is required, it does no harm. I can't think of a scenario where a test would want an FLDS emulation error but wouldn't want to skip the instruction, e.g. injecting a fault from userspace is largely an orthogonal test. Maybe this as a helper name? I don't think it's necessary to include "assert" anywhere in the name, the idea being that "emulated" provides a hint that it's a non-trivial helper. static inline void skip_emulated_flds(struct kvm_vcpu *vcpu) or skip_emulated_flds_instruction() if we're concerned that it might not be obvious "flds" is an instruction mnemonic.
On Mon, Oct 31, 2022 at 11:28 AM Sean Christopherson <seanjc@google.com> wrote: > > On Mon, Oct 31, 2022, David Matlack wrote: > > + > > +static inline void assert_exit_for_flds_emulation_failure(struct kvm_vcpu *vcpu) > > I think it makes sense to keeping the bundling of the assert+skip. As written, > the last test doesn't need to skip, but that may not always hold true, e.g. if > the test adds more stages to verify KVM handles page splits correctly, and even > when a skip is required, it does no harm. I can't think of a scenario where a > test would want an FLDS emulation error but wouldn't want to skip the instruction, > e.g. injecting a fault from userspace is largely an orthogonal test. > > Maybe this as a helper name? I don't think it's necessary to include "assert" > anywhere in the name, the idea being that "emulated" provides a hint that it's a > non-trivial helper. > > static inline void skip_emulated_flds(struct kvm_vcpu *vcpu) > > or skip_emulated_flds_instruction() if we're concerned that it might not be obvious > "flds" is an instruction mnemonic. I kept them separate for readability, but otherwise I have no argument against bundling. I find skip_emulated*() somewhat misleading since flds is not actually emulated (successfully). I'm trending toward something like handle_flds_emulation_failure_exit() for v4.
On Wed, Nov 02, 2022, David Matlack wrote: > On Mon, Oct 31, 2022 at 11:28 AM Sean Christopherson <seanjc@google.com> wrote: > > > > On Mon, Oct 31, 2022, David Matlack wrote: > > > + > > > +static inline void assert_exit_for_flds_emulation_failure(struct kvm_vcpu *vcpu) > > > > I think it makes sense to keeping the bundling of the assert+skip. As written, > > the last test doesn't need to skip, but that may not always hold true, e.g. if > > the test adds more stages to verify KVM handles page splits correctly, and even > > when a skip is required, it does no harm. I can't think of a scenario where a > > test would want an FLDS emulation error but wouldn't want to skip the instruction, > > e.g. injecting a fault from userspace is largely an orthogonal test. > > > > Maybe this as a helper name? I don't think it's necessary to include "assert" > > anywhere in the name, the idea being that "emulated" provides a hint that it's a > > non-trivial helper. > > > > static inline void skip_emulated_flds(struct kvm_vcpu *vcpu) > > > > or skip_emulated_flds_instruction() if we're concerned that it might not be obvious > > "flds" is an instruction mnemonic. > > I kept them separate for readability, Ha, and of course I found assert_exit_for_flds_emulation_failure() hard to read :-) > but otherwise I have no argument against bundling. I find skip_emulated*() > somewhat misleading since flds is not actually emulated (successfully). I'm > trending toward something like handle_flds_emulation_failure_exit() for v4. How about "skip_flds_on_emulation_failure_exit()"? "handle" is quite generic and doesn't provide any hints as to what the function actually does under the hood.
On Wed, Nov 2, 2022 at 12:03 PM Sean Christopherson <seanjc@google.com> wrote: > > On Wed, Nov 02, 2022, David Matlack wrote: > > On Mon, Oct 31, 2022 at 11:28 AM Sean Christopherson <seanjc@google.com> wrote: > > > > > > On Mon, Oct 31, 2022, David Matlack wrote: > > > > + > > > > +static inline void assert_exit_for_flds_emulation_failure(struct kvm_vcpu *vcpu) > > > > > > I think it makes sense to keeping the bundling of the assert+skip. As written, > > > the last test doesn't need to skip, but that may not always hold true, e.g. if > > > the test adds more stages to verify KVM handles page splits correctly, and even > > > when a skip is required, it does no harm. I can't think of a scenario where a > > > test would want an FLDS emulation error but wouldn't want to skip the instruction, > > > e.g. injecting a fault from userspace is largely an orthogonal test. > > > > > > Maybe this as a helper name? I don't think it's necessary to include "assert" > > > anywhere in the name, the idea being that "emulated" provides a hint that it's a > > > non-trivial helper. > > > > > > static inline void skip_emulated_flds(struct kvm_vcpu *vcpu) > > > > > > or skip_emulated_flds_instruction() if we're concerned that it might not be obvious > > > "flds" is an instruction mnemonic. > > > > I kept them separate for readability, > > Ha, and of course I found assert_exit_for_flds_emulation_failure() hard to read :-) > > > but otherwise I have no argument against bundling. I find skip_emulated*() > > somewhat misleading since flds is not actually emulated (successfully). I'm > > trending toward something like handle_flds_emulation_failure_exit() for v4. > > How about "skip_flds_on_emulation_failure_exit()"? "handle" is quite generic and > doesn't provide any hints as to what the function actually does under the hood. LGTM. Paolo can you apply the name change when queueing v4 (assuming there are no other comments)? If not I'd be happy to send a v5.
diff --git a/tools/testing/selftests/kvm/x86_64/flds_emulation.h b/tools/testing/selftests/kvm/x86_64/flds_emulation.h new file mode 100644 index 000000000000..be0b4e0dd722 --- /dev/null +++ b/tools/testing/selftests/kvm/x86_64/flds_emulation.h @@ -0,0 +1,59 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef SELFTEST_KVM_FLDS_EMULATION_H +#define SELFTEST_KVM_FLDS_EMULATION_H + +#include "kvm_util.h" + +#define FLDS_MEM_EAX ".byte 0xd9, 0x00" + +/* + * flds is an instruction that the KVM instruction emulator is known not to + * support. This can be used in guest code along with a mechanism to force + * KVM to emulate the instruction (e.g. by providing an MMIO address) to + * exercise emulation failures. + */ +static inline void flds(uint64_t address) +{ + __asm__ __volatile__(FLDS_MEM_EAX :: "a"(address)); +} + +static inline void assert_exit_for_flds_emulation_failure(struct kvm_vcpu *vcpu) +{ + struct kvm_run *run = vcpu->run; + uint8_t *insn_bytes; + uint64_t flags; + + TEST_ASSERT(run->exit_reason == KVM_EXIT_INTERNAL_ERROR, + "Unexpected exit reason: %u (%s)", + run->exit_reason, + exit_reason_str(run->exit_reason)); + + TEST_ASSERT(run->emulation_failure.suberror == KVM_INTERNAL_ERROR_EMULATION, + "Unexpected suberror: %u", + run->emulation_failure.suberror); + + flags = run->emulation_failure.flags; + TEST_ASSERT(run->emulation_failure.ndata >= 3 && + flags & KVM_INTERNAL_ERROR_EMULATION_FLAG_INSTRUCTION_BYTES, + "run->emulation_failure is missing instruction bytes"); + + TEST_ASSERT(run->emulation_failure.insn_size >= 2, + "Expected a 2-byte opcode for 'flds', got %d bytes", + run->emulation_failure.insn_size); + + insn_bytes = run->emulation_failure.insn_bytes; + TEST_ASSERT(insn_bytes[0] == 0xd9 && insn_bytes[1] == 0, + "Expected 'flds [eax]', opcode '0xd9 0x00', got opcode 0x%02x 0x%02x\n", + insn_bytes[0], insn_bytes[1]); +} + +static inline void skip_flds_instruction(struct kvm_vcpu *vcpu) +{ + struct kvm_regs regs; + + vcpu_regs_get(vcpu, ®s); + regs.rip += 2; + vcpu_regs_set(vcpu, ®s); +} + +#endif /* !SELFTEST_KVM_FLDS_EMULATION_H */ 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 f9fdf365dff7..f438a98e8bb7 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 @@ -8,6 +8,8 @@ #define _GNU_SOURCE /* for program_invocation_short_name */ +#include "flds_emulation.h" + #include "test_util.h" #include "kvm_util.h" #include "vmx.h" @@ -19,50 +21,12 @@ #define MEM_REGION_SLOT 10 #define MEM_REGION_SIZE PAGE_SIZE -#define FLDS_MEM_EAX ".byte 0xd9, 0x00" - static void guest_code(void) { - __asm__ __volatile__(FLDS_MEM_EAX :: "a"(MEM_REGION_GVA)); - + flds(MEM_REGION_GVA); GUEST_DONE(); } -static void process_exit_on_emulation_error(struct kvm_vcpu *vcpu) -{ - struct kvm_run *run = vcpu->run; - struct kvm_regs regs; - uint8_t *insn_bytes; - uint64_t flags; - - TEST_ASSERT(run->exit_reason == KVM_EXIT_INTERNAL_ERROR, - "Unexpected exit reason: %u (%s)", - run->exit_reason, - exit_reason_str(run->exit_reason)); - - TEST_ASSERT(run->emulation_failure.suberror == KVM_INTERNAL_ERROR_EMULATION, - "Unexpected suberror: %u", - run->emulation_failure.suberror); - - flags = run->emulation_failure.flags; - TEST_ASSERT(run->emulation_failure.ndata >= 3 && - flags & KVM_INTERNAL_ERROR_EMULATION_FLAG_INSTRUCTION_BYTES, - "run->emulation_failure is missing instruction bytes"); - - TEST_ASSERT(run->emulation_failure.insn_size >= 2, - "Expected a 2-byte opcode for 'flds', got %d bytes", - run->emulation_failure.insn_size); - - insn_bytes = run->emulation_failure.insn_bytes; - TEST_ASSERT(insn_bytes[0] == 0xd9 && insn_bytes[1] == 0, - "Expected 'flds [eax]', opcode '0xd9 0x00', got opcode 0x%02x 0x%02x\n", - insn_bytes[0], insn_bytes[1]); - - vcpu_regs_get(vcpu, ®s); - regs.rip += 2; - vcpu_regs_set(vcpu, ®s); -} - int main(int argc, char *argv[]) { struct kvm_vcpu *vcpu; @@ -97,7 +61,8 @@ int main(int argc, char *argv[]) vm_set_page_table_entry(vm, vcpu, MEM_REGION_GVA, pte | (1ull << 36)); vcpu_run(vcpu); - process_exit_on_emulation_error(vcpu); + assert_exit_for_flds_emulation_failure(vcpu); + skip_flds_instruction(vcpu); vcpu_run(vcpu); ASSERT_EQ(get_ucall(vcpu, NULL), UCALL_DONE);
Move the flds instruction emulation failure handling code to a header so it can be re-used in an upcoming test. No functional change intended. Signed-off-by: David Matlack <dmatlack@google.com> --- .../selftests/kvm/x86_64/flds_emulation.h | 59 +++++++++++++++++++ .../smaller_maxphyaddr_emulation_test.c | 45 ++------------ 2 files changed, 64 insertions(+), 40 deletions(-) create mode 100644 tools/testing/selftests/kvm/x86_64/flds_emulation.h