diff options
author | neel <neel@FreeBSD.org> | 2012-09-25 22:31:35 +0000 |
---|---|---|
committer | neel <neel@FreeBSD.org> | 2012-09-25 22:31:35 +0000 |
commit | bc269b51afe43aab28df7ea0d543c167bb7c7d2e (patch) | |
tree | bcd31b7f03fe25c622c8a7edf72d8163a4023b8c /sys/amd64/vmm/io/vlapic.c | |
parent | ebdd69568d7fa97153aa47a86afe367476a0a1de (diff) | |
download | FreeBSD-src-bc269b51afe43aab28df7ea0d543c167bb7c7d2e.zip FreeBSD-src-bc269b51afe43aab28df7ea0d543c167bb7c7d2e.tar.gz |
Add support for trapping MMIO writes to local apic registers and emulating them.
The default behavior is still to present the local apic to the guest in the
x2apic mode.
Diffstat (limited to 'sys/amd64/vmm/io/vlapic.c')
-rw-r--r-- | sys/amd64/vmm/io/vlapic.c | 39 |
1 files changed, 34 insertions, 5 deletions
diff --git a/sys/amd64/vmm/io/vlapic.c b/sys/amd64/vmm/io/vlapic.c index 9b7d3cb..aedc692 100644 --- a/sys/amd64/vmm/io/vlapic.c +++ b/sys/amd64/vmm/io/vlapic.c @@ -87,7 +87,7 @@ static MALLOC_DEFINE(M_VLAPIC, "vlapic", "vlapic"); #define VLAPIC_VERSION (16) #define VLAPIC_MAXLVT_ENTRIES (5) -#define x2apic(vlapic) ((vlapic)->msr_apicbase & APICBASE_X2APIC) +#define x2apic(vlapic) (((vlapic)->msr_apicbase & APICBASE_X2APIC) ? 1 : 0) enum boot_state { BS_INIT, @@ -433,7 +433,10 @@ lapic_process_icr(struct vlapic *vlapic, uint64_t icrval) struct vlapic *vlapic2; struct vm_exit *vmexit; - dest = icrval >> 32; + if (x2apic(vlapic)) + dest = icrval >> 32; + else + dest = icrval >> (32 + 24); vec = icrval & APIC_VECTOR_MASK; mode = icrval & APIC_DELMODE_MASK; @@ -703,8 +706,18 @@ vlapic_op_mem_write(void* dev, uint64_t gpa, opsize_t size, uint64_t data) lapic->svr = data; break; case APIC_OFFSET_ICR_LOW: + if (!x2apic(vlapic)) { + data &= 0xffffffff; + data |= (uint64_t)lapic->icr_hi << 32; + } retval = lapic_process_icr(vlapic, data); break; + case APIC_OFFSET_ICR_HI: + if (!x2apic(vlapic)) { + retval = 0; + lapic->icr_hi = data; + } + break; case APIC_OFFSET_TIMER_LVT ... APIC_OFFSET_ERROR_LVT: reg = vlapic_get_lvt(vlapic, offset); if (!(lapic->svr & APIC_SVR_ENABLE)) { @@ -810,19 +823,26 @@ static struct io_region vlapic_mmio[VM_MAXCPU]; struct vlapic * vlapic_init(struct vm *vm, int vcpuid) { + int err; + enum x2apic_state state; struct vlapic *vlapic; + err = vm_get_x2apic_state(vm, vcpuid, &state); + if (err) + panic("vlapic_set_apicbase: err %d fetching x2apic state", err); + vlapic = malloc(sizeof(struct vlapic), M_VLAPIC, M_WAITOK | M_ZERO); vlapic->vm = vm; vlapic->vcpuid = vcpuid; - vlapic->msr_apicbase = DEFAULT_APIC_BASE | - APICBASE_ENABLED | - APICBASE_X2APIC; + vlapic->msr_apicbase = DEFAULT_APIC_BASE | APICBASE_ENABLED; if (vcpuid == 0) vlapic->msr_apicbase |= APICBASE_BSP; + if (state == X2APIC_ENABLED) + vlapic->msr_apicbase |= APICBASE_X2APIC; + vlapic->ops = &vlapic_dev_ops; vlapic->mmio = vlapic_mmio + vcpuid; @@ -856,6 +876,15 @@ vlapic_get_apicbase(struct vlapic *vlapic) void vlapic_set_apicbase(struct vlapic *vlapic, uint64_t val) { + int err; + enum x2apic_state state; + + err = vm_get_x2apic_state(vlapic->vm, vlapic->vcpuid, &state); + if (err) + panic("vlapic_set_apicbase: err %d fetching x2apic state", err); + + if (state == X2APIC_DISABLED) + val &= ~APICBASE_X2APIC; vlapic->msr_apicbase = val; } |