Add reserved bit checking when doing %CR8 emulation and inject #GP if required.

Pointed out by:	grehan
Reviewed by:	tychon
This commit is contained in:
Neel Natu 2014-06-09 20:51:08 +00:00
parent 00c37433f4
commit 051f2bd19d
3 changed files with 51 additions and 25 deletions

View File

@ -1602,20 +1602,23 @@ vmx_emulate_cr4_access(struct vmx *vmx, int vcpu, uint64_t exitqual)
static int
vmx_emulate_cr8_access(struct vmx *vmx, int vcpu, uint64_t exitqual)
{
uint64_t regval;
struct vlapic *vlapic;
uint64_t cr8;
int regnum;
/* We only handle mov %cr8 to/from a register at this time. */
if ((exitqual & 0xe0) != 0x00) {
return (UNHANDLED);
}
vlapic = vm_lapic(vmx->vm, vcpu);
regnum = (exitqual >> 8) & 0xf;
if (exitqual & 0x10) {
regval = vlapic_get_tpr(vm_lapic(vmx->vm, vcpu));
vmx_set_guest_reg(vmx, vcpu, (exitqual >> 8) & 0xf,
regval >> 4);
cr8 = vlapic_get_cr8(vlapic);
vmx_set_guest_reg(vmx, vcpu, regnum, cr8);
} else {
regval = vmx_get_guest_reg(vmx, vcpu, (exitqual >> 8) & 0xf);
vlapic_set_tpr(vm_lapic(vmx->vm, vcpu), regval << 4);
cr8 = vmx_get_guest_reg(vmx, vcpu, regnum);
vlapic_set_cr8(vlapic, cr8);
}
return (HANDLED);

View File

@ -906,6 +906,46 @@ vlapic_calcdest(struct vm *vm, cpuset_t *dmask, uint32_t dest, bool phys,
static VMM_STAT_ARRAY(IPIS_SENT, VM_MAXCPU, "ipis sent to vcpu");
static void
vlapic_set_tpr(struct vlapic *vlapic, uint8_t val)
{
struct LAPIC *lapic = vlapic->apic_page;
lapic->tpr = val;
vlapic_update_ppr(vlapic);
}
static uint8_t
vlapic_get_tpr(struct vlapic *vlapic)
{
struct LAPIC *lapic = vlapic->apic_page;
return (lapic->tpr);
}
void
vlapic_set_cr8(struct vlapic *vlapic, uint64_t val)
{
uint8_t tpr;
if (val & ~0xf) {
vm_inject_gp(vlapic->vm, vlapic->vcpuid);
return;
}
tpr = val << 4;
vlapic_set_tpr(vlapic, tpr);
}
uint64_t
vlapic_get_cr8(struct vlapic *vlapic)
{
uint8_t tpr;
tpr = vlapic_get_tpr(vlapic);
return (tpr >> 4);
}
int
vlapic_icrlo_write_handler(struct vlapic *vlapic, bool *retu)
{
@ -1610,20 +1650,3 @@ vlapic_set_tmr_level(struct vlapic *vlapic, uint32_t dest, bool phys,
VLAPIC_CTR1(vlapic, "vector %d set to level-triggered", vector);
vlapic_set_tmr(vlapic, vector, true);
}
void
vlapic_set_tpr(struct vlapic *vlapic, uint8_t val)
{
struct LAPIC *lapic = vlapic->apic_page;
lapic->tpr = val;
vlapic_update_ppr(vlapic);
}
uint8_t
vlapic_get_tpr(struct vlapic *vlapic)
{
struct LAPIC *lapic = vlapic->apic_page;
return (lapic->tpr);
}

View File

@ -92,8 +92,8 @@ void vlapic_reset_tmr(struct vlapic *vlapic);
void vlapic_set_tmr_level(struct vlapic *vlapic, uint32_t dest, bool phys,
int delmode, int vector);
void vlapic_set_tpr(struct vlapic *vlapic, uint8_t val);
uint8_t vlapic_get_tpr(struct vlapic *vlapic);
void vlapic_set_cr8(struct vlapic *vlapic, uint64_t val);
uint64_t vlapic_get_cr8(struct vlapic *vlapic);
/* APIC write handlers */
void vlapic_id_write_handler(struct vlapic *vlapic);