diff --git a/xen/arch/arm/p2m.c b/xen/arch/arm/p2m.c index 1fc6ca3bb2..626376090d 100644 --- a/xen/arch/arm/p2m.c +++ b/xen/arch/arm/p2m.c @@ -130,6 +130,7 @@ void p2m_restore_state(struct vcpu *n) { register_t hcr; struct p2m_domain *p2m = &n->domain->arch.p2m; + uint8_t *last_vcpu_ran; if ( is_idle_vcpu(n) ) return; @@ -149,6 +150,17 @@ void p2m_restore_state(struct vcpu *n) WRITE_SYSREG(hcr, HCR_EL2); isb(); + + last_vcpu_ran = &p2m->last_vcpu_ran[smp_processor_id()]; + + /* + * Flush local TLB for the domain to prevent wrong TLB translation + * when running multiple vCPU of the same domain on a single pCPU. + */ + if ( *last_vcpu_ran != INVALID_VCPU_ID && *last_vcpu_ran != n->vcpu_id ) + flush_tlb_local(); + + *last_vcpu_ran = n->vcpu_id; } static void p2m_flush_tlb(struct p2m_domain *p2m) @@ -1247,6 +1259,7 @@ int p2m_init(struct domain *d) { struct p2m_domain *p2m = &d->arch.p2m; int rc = 0; + unsigned int cpu; rwlock_init(&p2m->lock); INIT_PAGE_LIST_HEAD(&p2m->pages); @@ -1275,6 +1288,17 @@ int p2m_init(struct domain *d) rc = p2m_alloc_table(d); + /* + * Make sure that the type chosen to is able to store the an vCPU ID + * between 0 and the maximum of virtual CPUS supported as long as + * the INVALID_VCPU_ID. + */ + BUILD_BUG_ON((1 << (sizeof(p2m->last_vcpu_ran[0]) * 8)) < MAX_VIRT_CPUS); + BUILD_BUG_ON((1 << (sizeof(p2m->last_vcpu_ran[0])* 8)) < INVALID_VCPU_ID); + + for_each_possible_cpu(cpu) + p2m->last_vcpu_ran[cpu] = INVALID_VCPU_ID; + return rc; } diff --git a/xen/include/asm-arm/p2m.h b/xen/include/asm-arm/p2m.h index 0899523084..18c57f936e 100644 --- a/xen/include/asm-arm/p2m.h +++ b/xen/include/asm-arm/p2m.h @@ -96,6 +96,9 @@ struct p2m_domain { /* back pointer to domain */ struct domain *domain; + + /* Keeping track on which CPU this p2m was used and for which vCPU */ + uint8_t last_vcpu_ran[NR_CPUS]; }; /*