@@ -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;
@@ -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" \
@@ -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} },
};
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@google.com> --- lib/x86/processor.h | 5 ++++ x86/vmx.h | 19 ++++++++++++++ x86/vmx_tests.c | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 100 insertions(+)