Int3 (#BP) and INTO (#OF) are unusual, in that they are reported as "software exception" rather than "hardware exception" in the VM-exit interruption information field of the VMCS. Signed-off-by: Jim Mattson <jmattson@xxxxxxxxxx> --- lib/x86/processor.h | 5 ++++ x86/vmx.h | 19 ++++++++++++++ x86/vmx_tests.c | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 100 insertions(+) diff --git a/lib/x86/processor.h b/lib/x86/processor.h index ee7f180..895d992 100644 --- a/lib/x86/processor.h +++ b/lib/x86/processor.h @@ -41,6 +41,11 @@ #define X86_IA32_EFER 0xc0000080 #define X86_EFER_LMA (1UL << 8) +struct far_pointer32 { + u32 offset; + u16 selector; +} __attribute__((packed)); + struct descriptor_table_ptr { u16 limit; ulong base; diff --git a/x86/vmx.h b/x86/vmx.h index 432ffa6..a2bacd3 100644 --- a/x86/vmx.h +++ b/x86/vmx.h @@ -377,6 +377,25 @@ enum Ctrl1 { CPU_RDRAND = 1ul << 11, }; +enum Intr_type { + VMX_INTR_TYPE_EXT_INTR = 0, + VMX_INTR_TYPE_NMI_INTR = 2, + VMX_INTR_TYPE_HARD_EXCEPTION = 3, + VMX_INTR_TYPE_SOFT_INTR = 4, + VMX_INTR_TYPE_SOFT_EXCEPTION = 6, +}; + +/* + * Interruption-information format + */ +#define INTR_INFO_VECTOR_MASK 0xff /* 7:0 */ +#define INTR_INFO_INTR_TYPE_MASK 0x700 /* 10:8 */ +#define INTR_INFO_DELIVER_CODE_MASK 0x800 /* 11 */ +#define INTR_INFO_UNBLOCK_NMI_MASK 0x1000 /* 12 */ +#define INTR_INFO_VALID_MASK 0x80000000 /* 31 */ + +#define INTR_INFO_INTR_TYPE_SHIFT 8 + #define SAVE_GPR \ "xchg %rax, regs\n\t" \ "xchg %rbx, regs+0x8\n\t" \ diff --git a/x86/vmx_tests.c b/x86/vmx_tests.c index 5aba999..5fd9570 100644 --- a/x86/vmx_tests.c +++ b/x86/vmx_tests.c @@ -1742,6 +1742,80 @@ static int disable_rdtscp_exit_handler(void) return VMX_TEST_VMEXIT; } +int int3_init() +{ + vmcs_write(EXC_BITMAP, ~0u); + return VMX_TEST_START; +} + +void int3_guest_main() +{ + asm volatile ("int3"); +} + +int int3_exit_handler() +{ + u32 reason = vmcs_read(EXI_REASON); + u32 intr_info = vmcs_read(EXI_INTR_INFO); + + report("L1 intercepts #BP", reason == VMX_EXC_NMI && + (intr_info & INTR_INFO_VALID_MASK) && + (intr_info & INTR_INFO_VECTOR_MASK) == BP_VECTOR && + ((intr_info & INTR_INFO_INTR_TYPE_MASK) >> + INTR_INFO_INTR_TYPE_SHIFT) == VMX_INTR_TYPE_SOFT_EXCEPTION); + + return VMX_TEST_VMEXIT; +} + +int into_init() +{ + vmcs_write(EXC_BITMAP, ~0u); + return VMX_TEST_START; +} + +void into_guest_main() +{ + struct far_pointer32 fp = { + .offset = (uintptr_t)&&into, + .selector = KERNEL_CS32, + }; + register uintptr_t rsp asm("rsp"); + + if (fp.offset != (uintptr_t)&&into) { + printf("Code address too high.\n"); + return; + } + if ((u32)rsp != rsp) { + printf("Stack address too high.\n"); + return; + } + + asm goto ("lcall *%0" : : "m" (fp) : "rax" : into); + return; +into: + asm volatile (".code32;" + "movl $0x7fffffff, %eax;" + "addl %eax, %eax;" + "into;" + "lret;" + ".code64"); + __builtin_unreachable(); +} + +int into_exit_handler() +{ + u32 reason = vmcs_read(EXI_REASON); + u32 intr_info = vmcs_read(EXI_INTR_INFO); + + report("L1 intercepts #OF", reason == VMX_EXC_NMI && + (intr_info & INTR_INFO_VALID_MASK) && + (intr_info & INTR_INFO_VECTOR_MASK) == OF_VECTOR && + ((intr_info & INTR_INFO_INTR_TYPE_MASK) >> + INTR_INFO_INTR_TYPE_SHIFT) == VMX_INTR_TYPE_SOFT_EXCEPTION); + + return VMX_TEST_VMEXIT; +} + /* name/init/guest_main/exit_handler/syscall_handler/guest_regs */ struct vmx_test vmx_tests[] = { { "null", NULL, basic_guest_main, basic_exit_handler, NULL, {0} }, @@ -1769,5 +1843,7 @@ struct vmx_test vmx_tests[] = { { "vmmcall", vmmcall_init, vmmcall_main, vmmcall_exit_handler, NULL, {0} }, { "disable RDTSCP", disable_rdtscp_init, disable_rdtscp_main, disable_rdtscp_exit_handler, NULL, {0} }, + { "int3", int3_init, int3_guest_main, int3_exit_handler, NULL, {0} }, + { "into", into_init, into_guest_main, into_exit_handler, NULL, {0} }, { NULL, NULL, NULL, NULL, NULL, {0} }, }; -- 2.8.0.rc3.226.g39d4020 -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html