[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [PATCH 2/2] xen/arm: Support runstate crossing pages
On Thu, 11 Jun 2020, Bertrand Marquis wrote: > Add support for runstate area register with the structure crossing pages > The code is storing up to 2 pages reference during the hypercall. > During a context switch, the code is computing where the > state_entry_time is and is breaking the memcpy in 2 parts when it is > required. > > Signed-off-by: Bertrand Marquis <bertrand.marquis@xxxxxxx> Clearly a lot of efforts went into this patch, thanks you Bertrand. The change is complex for the feature it adds. I wonder if we could use ioremap (or maybe something similar but using a different virtual space) to simplify it. Julien, do you have good ideas? Otherwise I don't think there is much we can do to make this patch simpler. As ugly as it is (sorry Bertrand, it is not your fault!) the patch looks correct. > --- > xen/arch/arm/domain.c | 101 +++++++++++++++++++++++++---------- > xen/include/asm-arm/domain.h | 5 +- > 2 files changed, 76 insertions(+), 30 deletions(-) > > diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c > index 739059234f..d847cb00f2 100644 > --- a/xen/arch/arm/domain.c > +++ b/xen/arch/arm/domain.c > @@ -280,11 +280,16 @@ void arch_cleanup_runstate_guest(struct vcpu *v) > { > spin_lock(&v->arch.runstate_guest.lock); > > - /* cleanup previous page if any */ > - if ( v->arch.runstate_guest.page ) > + /* cleanup previous pages if any */ > + if ( v->arch.runstate_guest.page[0] ) > { > - put_page_and_type(v->arch.runstate_guest.page); > - v->arch.runstate_guest.page = NULL; > + put_page_and_type(v->arch.runstate_guest.page[0]); > + v->arch.runstate_guest.page[0] = NULL; > + if ( v->arch.runstate_guest.page[1] ) > + { > + put_page_and_type(v->arch.runstate_guest.page[1]); > + v->arch.runstate_guest.page[1] = NULL; > + } > v->arch.runstate_guest.offset = 0; > } > > @@ -294,26 +299,25 @@ void arch_cleanup_runstate_guest(struct vcpu *v) > int arch_setup_runstate_guest(struct vcpu *v, > struct vcpu_register_runstate_memory_area area) > { > - struct page_info *page; > + struct page_info *page[2] = {NULL,NULL}; > unsigned offset; > > spin_lock(&v->arch.runstate_guest.lock); > > - /* cleanup previous page if any */ > - if ( v->arch.runstate_guest.page ) > + /* cleanup previous pages if any */ > + if ( v->arch.runstate_guest.page[0] ) > { > - put_page_and_type(v->arch.runstate_guest.page); > - v->arch.runstate_guest.page = NULL; > + put_page_and_type(v->arch.runstate_guest.page[0]); > + v->arch.runstate_guest.page[0] = NULL; > + if ( v->arch.runstate_guest.page[1] ) > + { > + put_page_and_type(v->arch.runstate_guest.page[1]); > + v->arch.runstate_guest.page[1] = NULL; > + } > v->arch.runstate_guest.offset = 0; > } > > offset = ((vaddr_t)area.addr.v) & ~PAGE_MASK; > - if ( offset > (PAGE_SIZE - sizeof(struct vcpu_runstate_info)) ) > - { > - spin_unlock(&v->arch.runstate_guest.lock); > - gprintk(XENLOG_DEBUG, "Runstate is crossing pages\n"); > - return -EINVAL; > - } > > /* provided address must be aligned to a 64bit */ > if ( offset % alignof(struct vcpu_runstate_info) ) > @@ -323,15 +327,30 @@ int arch_setup_runstate_guest(struct vcpu *v, > return -EINVAL; > } > > - page = get_page_from_gva(v, (vaddr_t)area.addr.v, GV2M_WRITE); > - if ( !page ) > + page[0] = get_page_from_gva(v, (vaddr_t)area.addr.v, GV2M_WRITE); > + if ( !page[0] ) > { > spin_unlock(&v->arch.runstate_guest.lock); > gprintk(XENLOG_DEBUG, "Runstate pointer is not mapped\n"); > return -EINVAL; > } > > - v->arch.runstate_guest.page = page; > + if ( offset > (PAGE_SIZE - sizeof(struct vcpu_runstate_info)) ) > + { > + /* guest area is crossing pages */ > + page[1] = get_page_from_gva(v, (vaddr_t)area.addr.v + PAGE_SIZE, > + GV2M_WRITE); > + if ( !page[1] ) > + { > + put_page_and_type(v->arch.runstate_guest.page[0]); > + spin_unlock(&v->arch.runstate_guest.lock); > + gprintk(XENLOG_DEBUG, "Runstate pointer is not fully mapped\n"); > + return -EINVAL; > + } > + } > + > + v->arch.runstate_guest.page[0] = page[0]; > + v->arch.runstate_guest.page[1] = page[1]; > v->arch.runstate_guest.offset = offset; > > spin_unlock(&v->arch.runstate_guest.lock); > @@ -343,34 +362,60 @@ int arch_setup_runstate_guest(struct vcpu *v, > /* Update per-VCPU guest runstate shared memory area (if registered). */ > static void update_runstate_area(struct vcpu *v) > { > - struct vcpu_runstate_info *guest_runstate; > - void *p; > + void *p[2]; > + unsigned offset, time_offset; > + uint64_t *state_entry_time; > > spin_lock(&v->arch.runstate_guest.lock); > > - if ( v->arch.runstate_guest.page ) > + if ( v->arch.runstate_guest.page[0] ) > { > - p = __map_domain_page(v->arch.runstate_guest.page); > - guest_runstate = p + v->arch.runstate_guest.offset; > + p[0] = __map_domain_page(v->arch.runstate_guest.page[0]); > + if ( v->arch.runstate_guest.page[1] ) > + p[1] = __map_domain_page(v->arch.runstate_guest.page[1]); > + else > + p[1] = NULL; > + offset = v->arch.runstate_guest.offset; > > if ( VM_ASSIST(v->domain, runstate_update_flag) ) > { > + time_offset = offset + > + offsetof(struct vcpu_runstate_info, state_entry_time); > + > + if ( time_offset < PAGE_SIZE ) > + state_entry_time = p[0] + time_offset; > + else > + state_entry_time = p[1] + (time_offset - PAGE_SIZE); > + > v->runstate.state_entry_time |= XEN_RUNSTATE_UPDATE; > - guest_runstate->state_entry_time |= XEN_RUNSTATE_UPDATE; > + *state_entry_time |= XEN_RUNSTATE_UPDATE; > smp_wmb(); > } > + else > + state_entry_time = NULL; > + > + if ( p[1] ) > + { > + memcpy(p[0] + offset, &v->runstate, PAGE_SIZE - offset); > + memcpy(p[1], &v->runstate + (PAGE_SIZE - offset), > + sizeof(v->runstate) - (PAGE_SIZE - offset)); > + } > + else > + memcpy(p[0] + offset, &v->runstate, sizeof(v->runstate)); > > - memcpy(guest_runstate, &v->runstate, sizeof(v->runstate)); > + /* copy must be done before switching the bit */ > smp_wmb(); > > - if ( VM_ASSIST(v->domain, runstate_update_flag) ) > + if ( state_entry_time ) > { > v->runstate.state_entry_time &= ~XEN_RUNSTATE_UPDATE; > - guest_runstate->state_entry_time &= ~XEN_RUNSTATE_UPDATE; > + *state_entry_time &= ~XEN_RUNSTATE_UPDATE; > smp_wmb(); > } > > - unmap_domain_page(p); > + unmap_domain_page(p[0]); > + if ( p[1] ) > + unmap_domain_page(p[1]); > } > > spin_unlock(&v->arch.runstate_guest.lock); > diff --git a/xen/include/asm-arm/domain.h b/xen/include/asm-arm/domain.h > index 3a7f53e13d..61e32f1ed5 100644 > --- a/xen/include/asm-arm/domain.h > +++ b/xen/include/asm-arm/domain.h > @@ -209,8 +209,9 @@ struct arch_vcpu > > /* runstate guest info */ > struct { > - struct page_info *page; /* guest page */ > - unsigned offset; /* offset in page */ > + /* we need 2 pages in case the guest area is crossing pages */ > + struct page_info *page[2]; /* guest pages */ > + unsigned offset; /* offset in first page */ > spinlock_t lock; /* lock to access page */ > } runstate_guest;
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |