Index: sys/amd64/include/vmm.h =================================================================== --- sys/amd64/include/vmm.h (revision 261555) +++ sys/amd64/include/vmm.h (working copy) @@ -100,7 +100,8 @@ void vm_destroy(struct vm *vm); const char *vm_name(struct vm *vm); int vm_malloc(struct vm *vm, vm_paddr_t gpa, size_t len); -int vm_map_mmio(struct vm *vm, vm_paddr_t gpa, size_t len, vm_paddr_t hpa); +int vm_map_mmio(struct vm *vm, vm_paddr_t gpa, size_t len, vm_paddr_t hpa, + vm_memattr_t memattr); int vm_unmap_mmio(struct vm *vm, vm_paddr_t gpa, size_t len); void *vm_gpa_hold(struct vm *, vm_paddr_t gpa, size_t len, int prot, void **cookie); Index: sys/amd64/vmm/intel/vmx.c =================================================================== --- sys/amd64/vmm/intel/vmx.c (revision 261555) +++ sys/amd64/vmm/intel/vmx.c (working copy) @@ -113,6 +113,9 @@ #define guest_msr_rw(vmx, msr) \ msr_bitmap_change_access((vmx)->msr_bitmap, (msr), MSR_BITMAP_ACCESS_RW) +#define guest_msr_ro(vmx, msr) \ + msr_bitmap_change_access((vmx)->msr_bitmap, (msr), MSR_BITMAP_ACCESS_READ) + #define HANDLED 1 #define UNHANDLED 0 @@ -155,6 +158,10 @@ static int cap_monitor_trap; static int cap_invpcid; +static int x2apic_virtualization; +SYSCTL_INT(_hw_vmm_vmx, OID_AUTO, x2apic_virtualization, CTLFLAG_RD, + &x2apic_virtualization, 0, "APICv x2apic virtualization"); + static int virtual_interrupt_delivery; SYSCTL_INT(_hw_vmm_vmx, OID_AUTO, virtual_interrupt_delivery, CTLFLAG_RD, &virtual_interrupt_delivery, 0, "APICv virtual interrupt delivery support"); @@ -301,6 +308,74 @@ } #endif /* KTR */ +static __inline bool +virtualize_apic_accesses(void) +{ + + if (virtual_interrupt_delivery && !x2apic_virtualization) + return (true); + else + return (false); +} + +static __inline bool +virtualize_x2apic_mode(void) +{ + + if (virtual_interrupt_delivery && x2apic_virtualization) + return (true); + else + return (false); +} + +static int +vmx_allow_x2apic_msrs(struct vmx *vmx) +{ + int i, error; + + error = 0; + + /* + * Allow readonly access to the following x2APIC MSRs from the guest. + */ + error += guest_msr_ro(vmx, MSR_APIC_ID); + error += guest_msr_ro(vmx, MSR_APIC_VERSION); + error += guest_msr_ro(vmx, MSR_APIC_LDR); + error += guest_msr_ro(vmx, MSR_APIC_SVR); + + for (i = 0; i < 8; i++) + error += guest_msr_ro(vmx, MSR_APIC_ISR0 + i); + + for (i = 0; i < 8; i++) + error += guest_msr_ro(vmx, MSR_APIC_TMR0 + i); + + for (i = 0; i < 8; i++) + error += guest_msr_ro(vmx, MSR_APIC_IRR0 + i); + + error += guest_msr_ro(vmx, MSR_APIC_ESR); + error += guest_msr_ro(vmx, MSR_APIC_LVT_TIMER); + error += guest_msr_ro(vmx, MSR_APIC_LVT_THERMAL); + error += guest_msr_ro(vmx, MSR_APIC_LVT_PCINT); + error += guest_msr_ro(vmx, MSR_APIC_LVT_LINT0); + error += guest_msr_ro(vmx, MSR_APIC_LVT_LINT1); + error += guest_msr_ro(vmx, MSR_APIC_LVT_ERROR); + error += guest_msr_ro(vmx, MSR_APIC_ICR_TIMER); + error += guest_msr_ro(vmx, MSR_APIC_DCR_TIMER); + error += guest_msr_ro(vmx, MSR_APIC_ICR); + + /* + * Allow TPR, EOI and SELF_IPI MSRs to be read and written by the guest. + * + * These registers get special treatment described in the section + * "Virtualizing MSR-Based APIC Accesses". + */ + error += guest_msr_rw(vmx, MSR_APIC_TPR); + error += guest_msr_rw(vmx, MSR_APIC_EOI); + error += guest_msr_rw(vmx, MSR_APIC_SELF_IPI); + + return (error); +} + u_long vmx_fix_cr0(u_long cr0) { @@ -632,9 +707,14 @@ } if (virtual_interrupt_delivery) { + TUNABLE_INT_FETCH("hw.vmm.vmx.use_x2apic_virtualization", + &x2apic_virtualization); procbased_ctls |= PROCBASED_USE_TPR_SHADOW; procbased_ctls2 |= procbased2_vid_bits; - procbased_ctls2 &= ~PROCBASED2_VIRTUALIZE_X2APIC_MODE; + if (x2apic_virtualization) + procbased_ctls2 &= ~PROCBASED2_VIRTUALIZE_APIC_ACCESSES; + else + procbased_ctls2 &= ~PROCBASED2_VIRTUALIZE_X2APIC_MODE; /* * Check for Posted Interrupts only if Virtual Interrupt @@ -831,12 +911,16 @@ vpid_alloc(vpid, VM_MAXCPU); - if (virtual_interrupt_delivery) { + error = 0; + if (virtualize_apic_accesses()) { error = vm_map_mmio(vm, DEFAULT_APIC_BASE, PAGE_SIZE, - APIC_ACCESS_ADDRESS); - /* XXX this should really return an error to the caller */ - KASSERT(error == 0, ("vm_map_mmio(apicbase) error %d", error)); + APIC_ACCESS_ADDRESS, VM_MEMATTR_WRITE_BACK); + } else if (virtualize_x2apic_mode()) { + error = vmx_allow_x2apic_msrs(vmx); } + /* XXX this should really return an error to the caller */ + KASSERT(error == 0, ("vmx_vminit: error %d initializing apic register " + "virtualization", error)); for (i = 0; i < VM_MAXCPU; i++) { vmcs = &vmx->vmcs[i]; @@ -861,8 +945,11 @@ error += vmwrite(VMCS_ENTRY_CTLS, entry_ctls); error += vmwrite(VMCS_MSR_BITMAP, vtophys(vmx->msr_bitmap)); error += vmwrite(VMCS_VPID, vpid[i]); + + if (virtualize_apic_accesses()) + error += vmwrite(VMCS_APIC_ACCESS, APIC_ACCESS_ADDRESS); + if (virtual_interrupt_delivery) { - error += vmwrite(VMCS_APIC_ACCESS, APIC_ACCESS_ADDRESS); error += vmwrite(VMCS_VIRTUAL_APIC, vtophys(&vmx->apic_page[i])); error += vmwrite(VMCS_EOI_EXIT0, 0); @@ -870,6 +957,7 @@ error += vmwrite(VMCS_EOI_EXIT2, 0); error += vmwrite(VMCS_EOI_EXIT3, 0); } + if (posted_interrupts) { error += vmwrite(VMCS_PIR_VECTOR, pirvec); error += vmwrite(VMCS_PIR_DESC, @@ -1411,7 +1499,7 @@ int error, handled, offset; bool retu; - if (!virtual_interrupt_delivery) + if (!virtualize_apic_accesses()) return (UNHANDLED); handled = 1; @@ -1459,7 +1547,7 @@ apic_access_fault(uint64_t gpa) { - if (virtual_interrupt_delivery && + if (virtualize_apic_accesses() && (gpa >= DEFAULT_APIC_BASE && gpa < DEFAULT_APIC_BASE + PAGE_SIZE)) return (true); else @@ -1472,7 +1560,7 @@ uint64_t qual; int access_type, offset, allowed; - if (!virtual_interrupt_delivery) + if (!virtualize_apic_accesses()) return (UNHANDLED); qual = vmexit->u.vmx.exit_qualification; @@ -1993,7 +2081,7 @@ int i, error; struct vmx *vmx = arg; - if (virtual_interrupt_delivery) + if (virtualize_apic_accesses()) vm_unmap_mmio(vmx->vm, DEFAULT_APIC_BASE, PAGE_SIZE); for (i = 0; i < VM_MAXCPU; i++) Index: sys/amd64/vmm/io/ppt.c =================================================================== --- sys/amd64/vmm/io/ppt.c (revision 261555) +++ sys/amd64/vmm/io/ppt.c (working copy) @@ -44,6 +44,7 @@ #include #include +#include #include #include @@ -409,7 +410,8 @@ for (i = 0; i < MAX_MMIOSEGS; i++) { seg = &ppt->mmio[i]; if (seg->len == 0) { - error = vm_map_mmio(vm, gpa, len, hpa); + error = vm_map_mmio(vm, gpa, len, hpa, + VM_MEMATTR_UNCACHEABLE); if (error == 0) { seg->gpa = gpa; seg->len = len; Index: sys/amd64/vmm/io/vlapic.c =================================================================== --- sys/amd64/vmm/io/vlapic.c (revision 261555) +++ sys/amd64/vmm/io/vlapic.c (working copy) @@ -1281,6 +1281,9 @@ default: // Read only. break; + /* + * XXX deal with writes of offset 0x3F0 (self IPI MSR) + */ } return (retval); Index: sys/amd64/vmm/vmm.c =================================================================== --- sys/amd64/vmm/vmm.c (revision 261555) +++ sys/amd64/vmm/vmm.c (working copy) @@ -400,11 +400,12 @@ } int -vm_map_mmio(struct vm *vm, vm_paddr_t gpa, size_t len, vm_paddr_t hpa) +vm_map_mmio(struct vm *vm, vm_paddr_t gpa, size_t len, vm_paddr_t hpa, + vm_memattr_t attr) { vm_object_t obj; - if ((obj = vmm_mmio_alloc(vm->vmspace, gpa, len, hpa)) == NULL) + if ((obj = vmm_mmio_alloc(vm->vmspace, gpa, len, hpa, attr)) == NULL) return (ENOMEM); else return (0); Index: sys/amd64/vmm/vmm_mem.c =================================================================== --- sys/amd64/vmm/vmm_mem.c (revision 261555) +++ sys/amd64/vmm/vmm_mem.c (working copy) @@ -57,7 +57,7 @@ vm_object_t vmm_mmio_alloc(struct vmspace *vmspace, vm_paddr_t gpa, size_t len, - vm_paddr_t hpa) + vm_paddr_t hpa, vm_memattr_t memattr) { int error; vm_object_t obj; @@ -77,7 +77,7 @@ * this object to be mapped as uncacheable. */ VM_OBJECT_WLOCK(obj); - error = vm_object_set_memattr(obj, VM_MEMATTR_UNCACHEABLE); + error = vm_object_set_memattr(obj, memattr); VM_OBJECT_WUNLOCK(obj); if (error != KERN_SUCCESS) { panic("vmm_mmio_alloc: vm_object_set_memattr error %d", Index: sys/amd64/vmm/vmm_mem.h =================================================================== --- sys/amd64/vmm/vmm_mem.h (revision 261555) +++ sys/amd64/vmm/vmm_mem.h (working copy) @@ -35,7 +35,7 @@ int vmm_mem_init(void); struct vm_object *vmm_mem_alloc(struct vmspace *, vm_paddr_t gpa, size_t size); struct vm_object *vmm_mmio_alloc(struct vmspace *, vm_paddr_t gpa, size_t len, - vm_paddr_t hpa); + vm_paddr_t hpa, vm_memattr_t attr); void vmm_mem_free(struct vmspace *, vm_paddr_t gpa, size_t size); void vmm_mmio_free(struct vmspace *, vm_paddr_t gpa, size_t size); vm_paddr_t vmm_mem_maxaddr(void);