Restructure the x2apic access code in preparation for supporting memory mapped

access to the local apic.

The vlapic code is now aware of the mode that the guest is using to access the
local apic.

Reviewed by: grehan@
This commit is contained in:
Neel Natu 2012-09-21 03:09:23 +00:00
parent 177fd53318
commit 2d3a73ed6d
5 changed files with 108 additions and 59 deletions

View File

@ -36,6 +36,7 @@ __FBSDID("$FreeBSD$");
#include <sys/smp.h>
#include <machine/clock.h>
#include <x86/specialreg.h>
#include <x86/apicreg.h>
#include <machine/vmm.h>
@ -86,6 +87,8 @@ static MALLOC_DEFINE(M_VLAPIC, "vlapic", "vlapic");
#define VLAPIC_VERSION (16)
#define VLAPIC_MAXLVT_ENTRIES (5)
#define x2apic(vlapic) ((vlapic)->msr_apicbase & APICBASE_X2APIC)
struct vlapic {
struct vm *vm;
int vcpuid;
@ -107,6 +110,8 @@ struct vlapic {
*/
uint8_t isrvec_stk[ISRVEC_STK_SIZE];
int isrvec_stk_top;
uint64_t msr_apicbase;
};
static void
@ -161,7 +166,6 @@ vlapic_op_reset(void* dev)
struct LAPIC *lapic = &vlapic->apic;
memset(lapic, 0, sizeof(*lapic));
lapic->id = vlapic->vcpuid << 24;
lapic->apr = vlapic->vcpuid;
vlapic_init_ipi(vlapic);
@ -542,7 +546,10 @@ vlapic_op_mem_read(void* dev, uint64_t gpa, opsize_t size, uint64_t *data)
switch(offset)
{
case APIC_OFFSET_ID:
*data = lapic->id;
if (x2apic(vlapic))
*data = vlapic->vcpuid;
else
*data = vlapic->vcpuid << 24;
break;
case APIC_OFFSET_VER:
*data = lapic->version;
@ -631,7 +638,6 @@ vlapic_op_mem_write(void* dev, uint64_t gpa, opsize_t size, uint64_t data)
switch(offset)
{
case APIC_OFFSET_ID:
lapic->id = data;
break;
case APIC_OFFSET_TPR:
lapic->tpr = data & 0xff;
@ -760,6 +766,14 @@ vlapic_init(struct vm *vm, int vcpuid)
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;
if (vcpuid == 0)
vlapic->msr_apicbase |= APICBASE_BSP;
vlapic->ops = &vlapic_dev_ops;
vlapic->mmio = vlapic_mmio + vcpuid;
@ -782,3 +796,17 @@ vlapic_cleanup(struct vlapic *vlapic)
vdev_unregister(vlapic);
free(vlapic, M_VLAPIC);
}
uint64_t
vlapic_get_apicbase(struct vlapic *vlapic)
{
return (vlapic->msr_apicbase);
}
void
vlapic_set_apicbase(struct vlapic *vlapic, uint64_t val)
{
vlapic->msr_apicbase = val;
}

View File

@ -102,4 +102,7 @@ void vlapic_intr_accepted(struct vlapic *vlapic, int vector);
void vlapic_set_intr_ready(struct vlapic *vlapic, int vector);
void vlapic_timer_tick(struct vlapic *vlapic);
uint64_t vlapic_get_apicbase(struct vlapic *vlapic);
void vlapic_set_apicbase(struct vlapic *vlapic, uint64_t val);
#endif /* _VLAPIC_H_ */

View File

@ -33,20 +33,18 @@ __FBSDID("$FreeBSD$");
#include <sys/systm.h>
#include <sys/smp.h>
#include <x86/specialreg.h>
#include <machine/vmm.h>
#include "vmm_ipi.h"
#include "vmm_lapic.h"
#include "vlapic.h"
int
lapic_write(struct vm *vm, int cpu, u_int offset, uint64_t val)
static int
lapic_write(struct vlapic *vlapic, u_int offset, uint64_t val)
{
int handled;
struct vlapic *vlapic;
vlapic = vm_lapic(vm, cpu);
if (vlapic_op_mem_write(vlapic, offset, DWORD, val) == 0)
handled = 1;
else
@ -55,15 +53,11 @@ lapic_write(struct vm *vm, int cpu, u_int offset, uint64_t val)
return (handled);
}
int
lapic_read(struct vm *vm, int cpu, u_int offset, uint64_t *rv)
static int
lapic_read(struct vlapic *vlapic, u_int offset, uint64_t *rv)
{
int handled;
struct vlapic *vlapic;
vlapic = vm_lapic(vm, cpu);
if (vlapic_op_mem_read(vlapic, offset, DWORD, rv) == 0)
handled = 1;
else
@ -120,3 +114,63 @@ lapic_timer_tick(struct vm *vm, int cpu)
vlapic_timer_tick(vlapic);
}
static boolean_t
x2apic_msr(u_int msr)
{
if (msr >= 0x800 && msr <= 0xBFF)
return (TRUE);
else
return (FALSE);
}
static u_int
x2apic_msr_to_regoff(u_int msr)
{
return ((msr - 0x800) << 4);
}
boolean_t
lapic_msr(u_int msr)
{
if (x2apic_msr(msr) || (msr == MSR_APICBASE))
return (TRUE);
else
return (FALSE);
}
int
lapic_rdmsr(struct vm *vm, int cpu, u_int msr, uint64_t *rval)
{
int handled;
struct vlapic *vlapic;
vlapic = vm_lapic(vm, cpu);
if (msr == MSR_APICBASE) {
*rval = vlapic_get_apicbase(vlapic);
handled = 1;
} else
handled = lapic_read(vlapic, x2apic_msr_to_regoff(msr), rval);
return (handled);
}
int
lapic_wrmsr(struct vm *vm, int cpu, u_int msr, uint64_t val)
{
int handled;
struct vlapic *vlapic;
vlapic = vm_lapic(vm, cpu);
if (msr == MSR_APICBASE) {
vlapic_set_apicbase(vlapic, val);
handled = 1;
} else
handled = lapic_write(vlapic, x2apic_msr_to_regoff(msr), val);
return (handled);
}

View File

@ -31,8 +31,10 @@
struct vm;
int lapic_write(struct vm *vm, int cpu, u_int offset, uint64_t val);
int lapic_read(struct vm *vm, int cpu, u_int offset, uint64_t *retval);
boolean_t lapic_msr(u_int num);
int lapic_rdmsr(struct vm *vm, int cpu, u_int msr, uint64_t *rval);
int lapic_wrmsr(struct vm *vm, int cpu, u_int msr, uint64_t wval);
void lapic_timer_tick(struct vm *vm, int cpu);
/*

View File

@ -34,7 +34,6 @@ __FBSDID("$FreeBSD$");
#include <sys/smp.h>
#include <machine/specialreg.h>
#include <x86/apicreg.h>
#include <machine/vmm.h>
#include "vmm_lapic.h"
@ -56,7 +55,6 @@ static struct vmm_msr vmm_msr[] = {
{ MSR_STAR, 0 },
{ MSR_SF_MASK, 0 },
{ MSR_PAT, VMM_MSR_F_EMULATE | VMM_MSR_F_INVALID },
{ MSR_APICBASE, VMM_MSR_F_EMULATE },
{ MSR_BIOS_SIGN,VMM_MSR_F_EMULATE },
{ MSR_MCG_CAP, VMM_MSR_F_EMULATE | VMM_MSR_F_READONLY },
};
@ -107,12 +105,6 @@ guest_msrs_init(struct vm *vm, int cpu)
case MSR_MCG_CAP:
guest_msrs[i] = 0;
break;
case MSR_APICBASE:
guest_msrs[i] = DEFAULT_APIC_BASE | APICBASE_ENABLED |
APICBASE_X2APIC;
if (cpu == 0)
guest_msrs[i] |= APICBASE_BSP;
break;
case MSR_PAT:
guest_msrs[i] = PAT_VALUE(0, PAT_WRITE_BACK) |
PAT_VALUE(1, PAT_WRITE_THROUGH) |
@ -130,29 +122,6 @@ guest_msrs_init(struct vm *vm, int cpu)
}
}
static boolean_t
x2apic_msr(u_int num)
{
if (num >= 0x800 && num <= 0xBFF)
return (TRUE);
else
return (FALSE);
}
static u_int
x2apic_msr_to_regoff(u_int msr)
{
return ((msr - 0x800) << 4);
}
static boolean_t
x2apic_msr_id(u_int num)
{
return (num == 0x802);
}
static int
msr_num_to_idx(u_int num)
{
@ -173,8 +142,8 @@ emulate_wrmsr(struct vm *vm, int cpu, u_int num, uint64_t val)
handled = 0;
if (x2apic_msr(num))
return (lapic_write(vm, cpu, x2apic_msr_to_regoff(num), val));
if (lapic_msr(num))
return (lapic_wrmsr(vm, cpu, num, val));
idx = msr_num_to_idx(num);
if (idx < 0)
@ -208,15 +177,8 @@ emulate_rdmsr(struct vm *vm, int cpu, u_int num)
handled = 0;
if (x2apic_msr(num)) {
handled = lapic_read(vm, cpu, x2apic_msr_to_regoff(num),
&result);
/*
* The version ID needs to be massaged
*/
if (x2apic_msr_id(num)) {
result = result >> 24;
}
if (lapic_msr(num)) {
handled = lapic_rdmsr(vm, cpu, num, &result);
goto done;
}