Skip to content

Commit

Permalink
hv: vlapic_timer: refine vlapic tscdeadline timer
Browse files Browse the repository at this point in the history
Add vlapic_create_timer/vlapic_reset_timer to setup/reset a timer.
Add vlapic_update_lvtt to disarm timer when mode changes.

Signed-off-by: Li, Fei1 <fei1.li@intel.com>
Acked-by: Eddie Dong <eddie.dong@intel.com>
  • Loading branch information
lifeix authored and jren1 committed May 15, 2018
1 parent ea54216 commit 9dd7d27
Show file tree
Hide file tree
Showing 4 changed files with 132 additions and 44 deletions.
143 changes: 112 additions & 31 deletions hypervisor/arch/x86/guest/vlapic.c
Expand Up @@ -107,6 +107,8 @@ apicv_batch_set_tmr(struct vlapic *vlapic);
*/
static void vlapic_set_error(struct vlapic *vlapic, uint32_t mask);

static int vlapic_timer_expired(void *data);

static struct vlapic *
vm_lapic_from_vcpu_id(struct vm *vm, int vcpu_id)
{
Expand Down Expand Up @@ -255,6 +257,58 @@ vlapic_lvtt_masked(struct vlapic *vlapic)
return !!(vlapic->apic_page->lvt_timer & APIC_LVTT_M);
}

static void vlapic_create_timer(struct vlapic *vlapic)
{
struct vlapic_timer *vlapic_timer;

if (vlapic == NULL)
return;

vlapic_timer = &vlapic->vlapic_timer;
memset(vlapic_timer, 0, sizeof(struct vlapic_timer));

initialize_timer(&vlapic_timer->timer,
vlapic_timer_expired, vlapic->vcpu,
0, 0, 0);
}

static void vlapic_reset_timer(struct vlapic *vlapic)
{
struct timer *timer;

if (vlapic == NULL)
return;

timer = &vlapic->vlapic_timer.timer;
del_timer(timer);
timer->mode = 0;
timer->fire_tsc = 0;
timer->period_in_cycle = 0;
}

static void vlapic_update_lvtt(struct vlapic *vlapic,
uint32_t val)
{
uint32_t timer_mode = val & APIC_LVTT_TM;
struct vlapic_timer *vlapic_timer = &vlapic->vlapic_timer;

if (vlapic_timer->mode != timer_mode) {
struct timer *timer = &vlapic_timer->timer;

/*
* A write to the LVT Timer Register that changes
* the timer mode disarms the local APIC timer.
*/
del_timer(timer);
timer->mode = (timer_mode == APIC_LVTT_TM_PERIODIC) ?
TICK_MODE_PERIODIC: TICK_MODE_ONESHOT;
timer->fire_tsc = 0;
timer->period_in_cycle = 0;

vlapic_timer->mode = timer_mode;
}
}

static uint32_t vlapic_get_ccr(__unused struct vlapic *vlapic)
{
return 0;
Expand All @@ -264,6 +318,46 @@ static void vlapic_dcr_write_handler(__unused struct vlapic *vlapic)
{
}

static void vlapic_icrtmr_write_handler(__unused struct vlapic *vlapic)
{
}


static uint64_t vlapic_get_tsc_deadline_msr(struct vlapic *vlapic)
{
if (!vlapic_lvtt_tsc_deadline(vlapic))
return 0;

return (vlapic->vlapic_timer.timer.fire_tsc == 0) ? 0 :
vlapic->vcpu->guest_msrs[IDX_TSC_DEADLINE];

}

static void vlapic_set_tsc_deadline_msr(struct vlapic *vlapic,
uint64_t val)
{
struct timer *timer;

if (!vlapic_lvtt_tsc_deadline(vlapic))
return;

vlapic->vcpu->guest_msrs[IDX_TSC_DEADLINE] = val;

timer = &vlapic->vlapic_timer.timer;
del_timer(timer);

if (val != 0UL) {
struct vcpu_arch *arch = &vlapic->vcpu->arch_vcpu;

/* transfer guest tsc to host tsc */
val -= arch->contexts[arch->cur_context].tsc_offset;
timer->fire_tsc = val;

add_timer(timer);
} else
timer->fire_tsc = 0;
}

static void
vlapic_esr_write_handler(struct vlapic *vlapic)
{
Expand Down Expand Up @@ -451,7 +545,9 @@ vlapic_lvt_write_handler(struct vlapic *vlapic, uint32_t offset)
"vpic wire mode -> NULL");
}
}
}
} else if (offset == APIC_OFFSET_TIMER_LVT)
vlapic_update_lvtt(vlapic, val);

*lvtptr = val;
atomic_store_rel_32(&vlapic->lvt_last[idx], val);
}
Expand Down Expand Up @@ -703,10 +799,6 @@ vlapic_trigger_lvt(struct vlapic *vlapic, int vector)
return 0;
}

static void vlapic_icrtmr_write_handler(__unused struct vlapic *vlapic)
{
}

/*
* This function populates 'dmask' with the set of vcpus that match the
* addressing specified by the (dest, phys, lowprio) tuple.
Expand Down Expand Up @@ -1332,12 +1424,11 @@ vlapic_reset(struct vlapic *vlapic)
vlapic_mask_lvts(vlapic);
vlapic_reset_tmr(vlapic);

lapic->icr_timer = 0;
lapic->dcr_timer = 0;
vlapic_dcr_write_handler(vlapic);
vlapic_reset_timer(vlapic);

vlapic->svr_last = lapic->svr;

initialize_timer(&vlapic->timer, NULL, NULL, 0, 0, 0);
}

void
Expand All @@ -1359,6 +1450,8 @@ vlapic_init(struct vlapic *vlapic)
if (vlapic->vcpu->vcpu_id == 0)
vlapic->msr_apicbase |= APICBASE_BSP;

vlapic_create_timer(vlapic);

vlapic_reset(vlapic);
}

Expand Down Expand Up @@ -1655,7 +1748,7 @@ vlapic_msr(uint32_t msr)
}

/* interrupt context */
static int tsc_periodic_time(void *data)
static int vlapic_timer_expired(void *data)
{
struct vcpu *vcpu = (struct vcpu *)data;
struct vlapic *vlapic;
Expand All @@ -1668,6 +1761,9 @@ static int tsc_periodic_time(void *data)
if (!vlapic_lvtt_masked(vlapic))
vlapic_intr_edge(vcpu, lapic->lvt_timer & APIC_LVTT_VECTOR);

if (!vlapic_lvtt_period(vlapic))
vlapic->vlapic_timer.timer.fire_tsc = 0;

return 0;
}

Expand All @@ -1686,6 +1782,10 @@ vlapic_rdmsr(struct vcpu *vcpu, uint32_t msr, uint64_t *rval)
*rval = vlapic_get_apicbase(vlapic);
break;

case MSR_IA32_TSC_DEADLINE:
*rval = vlapic_get_tsc_deadline_msr(vlapic);
break;

default:
offset = x2apic_msr_to_regoff(msr);
error = vlapic_read(vlapic, 0, offset, rval);
Expand All @@ -1698,7 +1798,7 @@ vlapic_rdmsr(struct vcpu *vcpu, uint32_t msr, uint64_t *rval)
int
vlapic_wrmsr(struct vcpu *vcpu, uint32_t msr, uint64_t val)
{
int error;
int error = 0;
uint32_t offset;
struct vlapic *vlapic;

Expand All @@ -1710,26 +1810,7 @@ vlapic_wrmsr(struct vcpu *vcpu, uint32_t msr, uint64_t val)
break;

case MSR_IA32_TSC_DEADLINE:
error = 0;
if (!vlapic_lvtt_tsc_deadline(vlapic))
return error;

del_timer(&vlapic->timer);
if (val != 0UL) {
/* transfer guest tsc to host tsc */
val -= vcpu->arch_vcpu.contexts[vcpu->
arch_vcpu.cur_context].tsc_offset;

initialize_timer(&vlapic->timer,
tsc_periodic_time, (void *)vcpu,
val, TICK_MODE_ONESHOT, 0);

if (add_timer(&vlapic->timer) != 0) {
pr_err("failed to add timer on VM %d",
vcpu->vm->attr.id);
error = -1;
}
}
vlapic_set_tsc_deadline_msr(vlapic, val);
break;

default:
Expand Down Expand Up @@ -1881,7 +1962,7 @@ void vlapic_free(struct vcpu *vcpu)
if (vlapic == NULL)
return;

del_timer(&vlapic->timer);
del_timer(&vlapic->vlapic_timer.timer);

if (!is_vapic_supported()) {
unregister_mmio_emulation_handler(vcpu->vm,
Expand Down
9 changes: 8 additions & 1 deletion hypervisor/arch/x86/guest/vlapic_priv.h
Expand Up @@ -108,6 +108,13 @@ struct vlapic_ops {
void (*enable_x2apic_mode)(struct vlapic *vlapic);
};

struct vlapic_timer {
struct timer timer;
uint32_t mode;
uint32_t tmicr;
uint32_t divisor;
};

struct vlapic {
struct vm *vm;
struct vcpu *vcpu;
Expand All @@ -118,7 +125,7 @@ struct vlapic {
uint32_t esr_pending;
int esr_firing;

struct timer timer;
struct vlapic_timer vlapic_timer;

/*
* The 'isrvec_stk' is a stack of vectors injected by the local apic.
Expand Down
13 changes: 1 addition & 12 deletions hypervisor/arch/x86/guest/vmsr.c
Expand Up @@ -51,16 +51,6 @@ static const uint32_t emulated_msrs[] = {
*/
};

/* the index is matched with emulated msrs array*/
enum {
IDX_TSC_DEADLINE,
IDX_BIOS_UPDT_TRIG,
IDX_BIOS_SIGN_ID,
IDX_TSC,

IDX_MAX_MSR
};

static void enable_msr_interception(uint8_t *bitmap, uint32_t msr)
{
uint8_t *read_map;
Expand Down Expand Up @@ -185,7 +175,7 @@ int rdmsr_vmexit_handler(struct vcpu *vcpu)
switch (msr) {
case MSR_IA32_TSC_DEADLINE:
{
v = vcpu->guest_msrs[IDX_TSC_DEADLINE];
vlapic_rdmsr(vcpu, msr, &v);
break;
}
case MSR_IA32_TIME_STAMP_COUNTER:
Expand Down Expand Up @@ -280,7 +270,6 @@ int wrmsr_vmexit_handler(struct vcpu *vcpu)
case MSR_IA32_TSC_DEADLINE:
{
vlapic_wrmsr(vcpu, msr, v);
vcpu->guest_msrs[IDX_TSC_DEADLINE] = v;
break;
}
case MSR_IA32_TIME_STAMP_COUNTER:
Expand Down
11 changes: 11 additions & 0 deletions hypervisor/include/arch/x86/guest/guest.h
Expand Up @@ -45,6 +45,17 @@
(idx < vm->hw.num_vcpus) & (vcpu != NULL); \
idx++, vcpu = vm->hw.vcpu_array[idx])


/* the index is matched with emulated msrs array*/
enum {
IDX_TSC_DEADLINE,
IDX_BIOS_UPDT_TRIG,
IDX_BIOS_SIGN_ID,
IDX_TSC,

IDX_MAX_MSR
};

struct vhm_request;

/*
Expand Down

0 comments on commit 9dd7d27

Please sign in to comment.