mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 18:50:05 +01:00
xen/arm: avoid overflow when setting vtimer in context switch
virt_vtimer_save() will calculate the next deadline when the vCPU is scheduled out. At the moment, Xen will use the following equation: virt_timer.cval + virt_time_base.offset - boot_count The three values are 64-bit and one (cval) is controlled by domain. In theory, it would be possible that the domain has started a long time after the system boot. So virt_time_base.offset - boot_count may be a large numbers. This means a domain may inadvertently set a cval so the result would overflow. Consequently, the deadline would be set very far in the future. This could result to loss of timer interrupts or the vCPU getting block "forever". One way to solve the problem, would be to separately 1) compute when the domain was created in ns 2) convert cval to ns 3) Add 1 and 2 together The first part of the equation never change (the value is set/known at domain creation). So take the opportunity to store it in domain structure. Signed-off-by: Jiamei Xie <jiamei.xie@arm.com> Reviewed-by: Julien Grall <jgrall@amazon.com> Reviewed-by: Bertrand Marquis <bertrand.marquis@arm.com>
This commit is contained in:
1 parent
d8cb7e0f06
commit
6655eb8109
2 files changed
+7
-3
No files matched your search
@@ -71,6 +71,7 @@ struct arch_domain
|
||||
|
||||
struct {
|
||||
uint64_t offset;
|
||||
s_time_t nanoseconds;
|
||||
} virt_timer_base;
|
||||
|
||||
struct vgic_dist vgic;
|
||||
|
||||
@@ -63,7 +63,9 @@ static void virt_timer_expired(void *data)
|
||||
int domain_vtimer_init(struct domain *d, struct xen_arch_domainconfig *config)
|
||||
{
|
||||
d->arch.virt_timer_base.offset = get_cycles();
|
||||
d->time_offset.seconds = ticks_to_ns(d->arch.virt_timer_base.offset - boot_count);
|
||||
d->arch.virt_timer_base.nanoseconds =
|
||||
ticks_to_ns(d->arch.virt_timer_base.offset - boot_count);
|
||||
d->time_offset.seconds = d->arch.virt_timer_base.nanoseconds;
|
||||
do_div(d->time_offset.seconds, 1000000000);
|
||||
|
||||
config->clock_frequency = timer_dt_clock_frequency;
|
||||
@@ -144,8 +146,9 @@ void virt_timer_save(struct vcpu *v)
|
||||
if ( (v->arch.virt_timer.ctl & CNTx_CTL_ENABLE) &&
|
||||
!(v->arch.virt_timer.ctl & CNTx_CTL_MASK))
|
||||
{
|
||||
set_timer(&v->arch.virt_timer.timer, ticks_to_ns(v->arch.virt_timer.cval +
|
||||
v->domain->arch.virt_timer_base.offset - boot_count));
|
||||
set_timer(&v->arch.virt_timer.timer,
|
||||
v->domain->arch.virt_timer_base.nanoseconds +
|
||||
ticks_to_ns(v->arch.virt_timer.cval));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||