mirror of
https://github.com/projectacrn/acrn-hypervisor.git
synced 2025-06-19 12:12:16 +00:00
hv: vlapic_timer: refine vlapic tscdeadline timer
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>
This commit is contained in:
parent
ea54216116
commit
9dd7d27737
@ -107,6 +107,8 @@ apicv_batch_set_tmr(struct vlapic *vlapic);
|
|||||||
*/
|
*/
|
||||||
static void vlapic_set_error(struct vlapic *vlapic, uint32_t mask);
|
static void vlapic_set_error(struct vlapic *vlapic, uint32_t mask);
|
||||||
|
|
||||||
|
static int vlapic_timer_expired(void *data);
|
||||||
|
|
||||||
static struct vlapic *
|
static struct vlapic *
|
||||||
vm_lapic_from_vcpu_id(struct vm *vm, int vcpu_id)
|
vm_lapic_from_vcpu_id(struct vm *vm, int vcpu_id)
|
||||||
{
|
{
|
||||||
@ -255,6 +257,58 @@ vlapic_lvtt_masked(struct vlapic *vlapic)
|
|||||||
return !!(vlapic->apic_page->lvt_timer & APIC_LVTT_M);
|
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)
|
static uint32_t vlapic_get_ccr(__unused struct vlapic *vlapic)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
@ -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
|
static void
|
||||||
vlapic_esr_write_handler(struct vlapic *vlapic)
|
vlapic_esr_write_handler(struct vlapic *vlapic)
|
||||||
{
|
{
|
||||||
@ -451,7 +545,9 @@ vlapic_lvt_write_handler(struct vlapic *vlapic, uint32_t offset)
|
|||||||
"vpic wire mode -> NULL");
|
"vpic wire mode -> NULL");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} else if (offset == APIC_OFFSET_TIMER_LVT)
|
||||||
|
vlapic_update_lvtt(vlapic, val);
|
||||||
|
|
||||||
*lvtptr = val;
|
*lvtptr = val;
|
||||||
atomic_store_rel_32(&vlapic->lvt_last[idx], val);
|
atomic_store_rel_32(&vlapic->lvt_last[idx], val);
|
||||||
}
|
}
|
||||||
@ -703,10 +799,6 @@ vlapic_trigger_lvt(struct vlapic *vlapic, int vector)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void vlapic_icrtmr_write_handler(__unused struct vlapic *vlapic)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This function populates 'dmask' with the set of vcpus that match the
|
* This function populates 'dmask' with the set of vcpus that match the
|
||||||
* addressing specified by the (dest, phys, lowprio) tuple.
|
* addressing specified by the (dest, phys, lowprio) tuple.
|
||||||
@ -1332,12 +1424,11 @@ vlapic_reset(struct vlapic *vlapic)
|
|||||||
vlapic_mask_lvts(vlapic);
|
vlapic_mask_lvts(vlapic);
|
||||||
vlapic_reset_tmr(vlapic);
|
vlapic_reset_tmr(vlapic);
|
||||||
|
|
||||||
|
lapic->icr_timer = 0;
|
||||||
lapic->dcr_timer = 0;
|
lapic->dcr_timer = 0;
|
||||||
vlapic_dcr_write_handler(vlapic);
|
vlapic_reset_timer(vlapic);
|
||||||
|
|
||||||
vlapic->svr_last = lapic->svr;
|
vlapic->svr_last = lapic->svr;
|
||||||
|
|
||||||
initialize_timer(&vlapic->timer, NULL, NULL, 0, 0, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -1359,6 +1450,8 @@ vlapic_init(struct vlapic *vlapic)
|
|||||||
if (vlapic->vcpu->vcpu_id == 0)
|
if (vlapic->vcpu->vcpu_id == 0)
|
||||||
vlapic->msr_apicbase |= APICBASE_BSP;
|
vlapic->msr_apicbase |= APICBASE_BSP;
|
||||||
|
|
||||||
|
vlapic_create_timer(vlapic);
|
||||||
|
|
||||||
vlapic_reset(vlapic);
|
vlapic_reset(vlapic);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1655,7 +1748,7 @@ vlapic_msr(uint32_t msr)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* interrupt context */
|
/* interrupt context */
|
||||||
static int tsc_periodic_time(void *data)
|
static int vlapic_timer_expired(void *data)
|
||||||
{
|
{
|
||||||
struct vcpu *vcpu = (struct vcpu *)data;
|
struct vcpu *vcpu = (struct vcpu *)data;
|
||||||
struct vlapic *vlapic;
|
struct vlapic *vlapic;
|
||||||
@ -1668,6 +1761,9 @@ static int tsc_periodic_time(void *data)
|
|||||||
if (!vlapic_lvtt_masked(vlapic))
|
if (!vlapic_lvtt_masked(vlapic))
|
||||||
vlapic_intr_edge(vcpu, lapic->lvt_timer & APIC_LVTT_VECTOR);
|
vlapic_intr_edge(vcpu, lapic->lvt_timer & APIC_LVTT_VECTOR);
|
||||||
|
|
||||||
|
if (!vlapic_lvtt_period(vlapic))
|
||||||
|
vlapic->vlapic_timer.timer.fire_tsc = 0;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1686,6 +1782,10 @@ vlapic_rdmsr(struct vcpu *vcpu, uint32_t msr, uint64_t *rval)
|
|||||||
*rval = vlapic_get_apicbase(vlapic);
|
*rval = vlapic_get_apicbase(vlapic);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case MSR_IA32_TSC_DEADLINE:
|
||||||
|
*rval = vlapic_get_tsc_deadline_msr(vlapic);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
offset = x2apic_msr_to_regoff(msr);
|
offset = x2apic_msr_to_regoff(msr);
|
||||||
error = vlapic_read(vlapic, 0, offset, rval);
|
error = vlapic_read(vlapic, 0, offset, rval);
|
||||||
@ -1698,7 +1798,7 @@ vlapic_rdmsr(struct vcpu *vcpu, uint32_t msr, uint64_t *rval)
|
|||||||
int
|
int
|
||||||
vlapic_wrmsr(struct vcpu *vcpu, uint32_t msr, uint64_t val)
|
vlapic_wrmsr(struct vcpu *vcpu, uint32_t msr, uint64_t val)
|
||||||
{
|
{
|
||||||
int error;
|
int error = 0;
|
||||||
uint32_t offset;
|
uint32_t offset;
|
||||||
struct vlapic *vlapic;
|
struct vlapic *vlapic;
|
||||||
|
|
||||||
@ -1710,26 +1810,7 @@ vlapic_wrmsr(struct vcpu *vcpu, uint32_t msr, uint64_t val)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case MSR_IA32_TSC_DEADLINE:
|
case MSR_IA32_TSC_DEADLINE:
|
||||||
error = 0;
|
vlapic_set_tsc_deadline_msr(vlapic, val);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -1881,7 +1962,7 @@ void vlapic_free(struct vcpu *vcpu)
|
|||||||
if (vlapic == NULL)
|
if (vlapic == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
del_timer(&vlapic->timer);
|
del_timer(&vlapic->vlapic_timer.timer);
|
||||||
|
|
||||||
if (!is_vapic_supported()) {
|
if (!is_vapic_supported()) {
|
||||||
unregister_mmio_emulation_handler(vcpu->vm,
|
unregister_mmio_emulation_handler(vcpu->vm,
|
||||||
|
@ -108,6 +108,13 @@ struct vlapic_ops {
|
|||||||
void (*enable_x2apic_mode)(struct vlapic *vlapic);
|
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 vlapic {
|
||||||
struct vm *vm;
|
struct vm *vm;
|
||||||
struct vcpu *vcpu;
|
struct vcpu *vcpu;
|
||||||
@ -118,7 +125,7 @@ struct vlapic {
|
|||||||
uint32_t esr_pending;
|
uint32_t esr_pending;
|
||||||
int esr_firing;
|
int esr_firing;
|
||||||
|
|
||||||
struct timer timer;
|
struct vlapic_timer vlapic_timer;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The 'isrvec_stk' is a stack of vectors injected by the local apic.
|
* The 'isrvec_stk' is a stack of vectors injected by the local apic.
|
||||||
|
@ -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)
|
static void enable_msr_interception(uint8_t *bitmap, uint32_t msr)
|
||||||
{
|
{
|
||||||
uint8_t *read_map;
|
uint8_t *read_map;
|
||||||
@ -185,7 +175,7 @@ int rdmsr_vmexit_handler(struct vcpu *vcpu)
|
|||||||
switch (msr) {
|
switch (msr) {
|
||||||
case MSR_IA32_TSC_DEADLINE:
|
case MSR_IA32_TSC_DEADLINE:
|
||||||
{
|
{
|
||||||
v = vcpu->guest_msrs[IDX_TSC_DEADLINE];
|
vlapic_rdmsr(vcpu, msr, &v);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case MSR_IA32_TIME_STAMP_COUNTER:
|
case MSR_IA32_TIME_STAMP_COUNTER:
|
||||||
@ -280,7 +270,6 @@ int wrmsr_vmexit_handler(struct vcpu *vcpu)
|
|||||||
case MSR_IA32_TSC_DEADLINE:
|
case MSR_IA32_TSC_DEADLINE:
|
||||||
{
|
{
|
||||||
vlapic_wrmsr(vcpu, msr, v);
|
vlapic_wrmsr(vcpu, msr, v);
|
||||||
vcpu->guest_msrs[IDX_TSC_DEADLINE] = v;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case MSR_IA32_TIME_STAMP_COUNTER:
|
case MSR_IA32_TIME_STAMP_COUNTER:
|
||||||
|
@ -45,6 +45,17 @@
|
|||||||
(idx < vm->hw.num_vcpus) & (vcpu != NULL); \
|
(idx < vm->hw.num_vcpus) & (vcpu != NULL); \
|
||||||
idx++, vcpu = vm->hw.vcpu_array[idx])
|
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;
|
struct vhm_request;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
Loading…
Reference in New Issue
Block a user