[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [PATCH 2/2] xen/arm: Support runstate crossing pages
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> --- 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; -- 2.17.1
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |