Author: neel
Date: Wed Jul 16 21:26:26 2014
New Revision: 268777
URL: http://svnweb.freebsd.org/changeset/base/268777
Log:
Add emulation for legacy x86 task switching mechanism.
FreeBSD/i386 uses task switching to handle double fault exceptions and this
change enables that to work.
Reported by: glebius
Added:
head/usr.sbin/bhyve/task_switch.c (contents, props changed)
Modified:
head/sys/amd64/include/vmm.h
head/sys/amd64/vmm/intel/vmcs.c
head/sys/amd64/vmm/intel/vmcs.h
head/sys/amd64/vmm/intel/vmx.c
head/usr.sbin/bhyve/Makefile
head/usr.sbin/bhyve/bhyverun.c
head/usr.sbin/bhyve/bhyverun.h
Modified: head/sys/amd64/include/vmm.h
==
--- head/sys/amd64/include/vmm.hWed Jul 16 21:06:43 2014
(r268776)
+++ head/sys/amd64/include/vmm.hWed Jul 16 21:26:26 2014
(r268777)
@@ -75,6 +75,10 @@ enum vm_reg_name {
VM_REG_GUEST_GDTR,
VM_REG_GUEST_EFER,
VM_REG_GUEST_CR2,
+ VM_REG_GUEST_PDPTE0,
+ VM_REG_GUEST_PDPTE1,
+ VM_REG_GUEST_PDPTE2,
+ VM_REG_GUEST_PDPTE3,
VM_REG_LAST
};
@@ -323,6 +327,7 @@ struct seg_desc {
uint32_taccess;
};
#defineSEG_DESC_TYPE(access) ((access) 0x001f)
+#defineSEG_DESC_DPL(access)(((access) 5) 0x3)
#defineSEG_DESC_PRESENT(access)(((access) 0x0080) ? 1 : 0)
#defineSEG_DESC_DEF32(access) (((access) 0x4000) ? 1 : 0)
#defineSEG_DESC_GRANULARITY(access)(((access) 0x8000) ? 1 : 0)
@@ -415,6 +420,7 @@ enum vm_exitcode {
VM_EXITCODE_IOAPIC_EOI,
VM_EXITCODE_SUSPENDED,
VM_EXITCODE_INOUT_STR,
+ VM_EXITCODE_TASK_SWITCH,
VM_EXITCODE_MAX
};
@@ -439,6 +445,22 @@ struct vm_inout_str {
struct seg_desc seg_desc;
};
+enum task_switch_reason {
+ TSR_CALL,
+ TSR_IRET,
+ TSR_JMP,
+ TSR_IDT_GATE, /* task gate in IDT */
+};
+
+struct vm_task_switch {
+ uint16_ttsssel; /* new TSS selector */
+ int ext;/* task switch due to external event */
+ uint32_terrcode;
+ int errcode_valid; /* push 'errcode' on the new stack */
+ enum task_switch_reason reason;
+ struct vm_guest_paging paging;
+};
+
struct vm_exit {
enum vm_exitcodeexitcode;
int inst_length;/* 0 means unknown */
@@ -493,6 +515,7 @@ struct vm_exit {
struct {
enum vm_suspend_how how;
} suspended;
+ struct vm_task_switch task_switch;
} u;
};
Modified: head/sys/amd64/vmm/intel/vmcs.c
==
--- head/sys/amd64/vmm/intel/vmcs.c Wed Jul 16 21:06:43 2014
(r268776)
+++ head/sys/amd64/vmm/intel/vmcs.c Wed Jul 16 21:26:26 2014
(r268777)
@@ -103,6 +103,14 @@ vmcs_field_encoding(int ident)
return (VMCS_GUEST_LDTR_SELECTOR);
case VM_REG_GUEST_EFER:
return (VMCS_GUEST_IA32_EFER);
+ case VM_REG_GUEST_PDPTE0:
+ return (VMCS_GUEST_PDPTE0);
+ case VM_REG_GUEST_PDPTE1:
+ return (VMCS_GUEST_PDPTE1);
+ case VM_REG_GUEST_PDPTE2:
+ return (VMCS_GUEST_PDPTE2);
+ case VM_REG_GUEST_PDPTE3:
+ return (VMCS_GUEST_PDPTE3);
default:
return (-1);
}
Modified: head/sys/amd64/vmm/intel/vmcs.h
==
--- head/sys/amd64/vmm/intel/vmcs.h Wed Jul 16 21:06:43 2014
(r268776)
+++ head/sys/amd64/vmm/intel/vmcs.h Wed Jul 16 21:26:26 2014
(r268777)
@@ -346,6 +346,9 @@ vmcs_write(uint32_t encoding, uint64_t v
#defineVMCS_INTR_T_HWINTR (0 8)
#defineVMCS_INTR_T_NMI (2 8)
#defineVMCS_INTR_T_HWEXCEPTION (3 8)
+#defineVMCS_INTR_T_SWINTR (4 8)
+#defineVMCS_INTR_T_PRIV_SWEXCEPTION (5 8)
+#defineVMCS_INTR_T_SWEXCEPTION (6 8)
#defineVMCS_INTR_DEL_ERRCODE (1 11)
/*
Modified: head/sys/amd64/vmm/intel/vmx.c
==
--- head/sys/amd64/vmm/intel/vmx.c Wed Jul 16 21:06:43 2014
(r268776)
+++ head/sys/amd64/vmm/intel/vmx.c Wed Jul 16 21:26:26 2014
(r268777)
@@ -2020,6 +2020,26 @@ vmx_handle_apic_access(struct vmx *vmx,
return (UNHANDLED);
}
+static enum task_switch_reason
+vmx_task_switch_reason(uint64_t qual)
+{
+ int reason;
+
+ reason = (qual 30) 0x3;
+ switch (reason) {
+ case 0:
+ return (TSR_CALL);
+ case 1:
+ return (TSR_IRET);
+ case 2:
+ return (TSR_JMP);
+ case 3:
+ return