[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH RFC v2 2/9] xen/arm: Implement save and restore for gic, vtimer, and ptimer
In save/load of hvm context, add registers for gic, vtimer, and ptimer. Signed-off-by: Jaeyong Yoo <jaeyong.yoo@xxxxxxxxxxx> Singed-off-by: Evgeny Fedotov <e.fedotov@xxxxxxxxxxx> --- xen/arch/arm/domctl.c | 80 ++++++++++++++++++- xen/arch/arm/hvm/hvm.c | 142 +++++++++++++++++++++++++++++++++ xen/common/Makefile | 2 + xen/include/public/arch-arm/hvm/save.h | 38 +++++++++ 4 files changed, 261 insertions(+), 1 deletion(-) diff --git a/xen/arch/arm/domctl.c b/xen/arch/arm/domctl.c index 851ee40..0203501 100644 --- a/xen/arch/arm/domctl.c +++ b/xen/arch/arm/domctl.c @@ -9,12 +9,90 @@ #include <xen/lib.h> #include <xen/errno.h> #include <xen/sched.h> +#include <xen/hvm/save.h> +#include <xen/guest_access.h> #include <public/domctl.h> long arch_do_domctl(struct xen_domctl *domctl, struct domain *d, XEN_GUEST_HANDLE_PARAM(xen_domctl_t) u_domctl) { - return -ENOSYS; + long ret = 0; + bool_t copyback = 0; + + switch ( domctl->cmd ) + { + case XEN_DOMCTL_sethvmcontext: + { + struct hvm_domain_context c = { .size = domctl->u.hvmcontext.size }; + + ret = -ENOMEM; + if ( (c.data = xmalloc_bytes(c.size)) == NULL ) + goto sethvmcontext_out; + + ret = -EFAULT; + if ( copy_from_guest(c.data, domctl->u.hvmcontext.buffer, c.size) != 0) + goto sethvmcontext_out; + + domain_pause(d); + ret = hvm_load(d, &c); + domain_unpause(d); + + sethvmcontext_out: + if ( c.data != NULL ) + xfree(c.data); + } + break; + case XEN_DOMCTL_gethvmcontext: + { + struct hvm_domain_context c = { 0 }; + + ret = -EINVAL; + + c.size = hvm_save_size(d); + + if ( guest_handle_is_null(domctl->u.hvmcontext.buffer) ) + { + /* Client is querying for the correct buffer size */ + domctl->u.hvmcontext.size = c.size; + ret = 0; + goto gethvmcontext_out; + } + + /* Check that the client has a big enough buffer */ + ret = -ENOSPC; + if ( domctl->u.hvmcontext.size < c.size ) + { + printk("(gethvmcontext) size error: %d and %d\n", + domctl->u.hvmcontext.size, c.size ); + goto gethvmcontext_out; + } + + domain_pause(d); + ret = hvm_save(d, &c); + domain_unpause(d); + + domctl->u.hvmcontext.size = c.cur; + if ( copy_to_guest(domctl->u.hvmcontext.buffer, c.data, c.size) != 0 ) + { + printk("(gethvmcontext) copy to guest failed\n"); + ret = -EFAULT; + } + + gethvmcontext_out: + copyback = 1; + + if ( c.data != NULL ) + xfree(c.data); + } + break; + default: + return -EINVAL; + } + + if ( copyback && __copy_to_guest(u_domctl, domctl, 1) ) + ret = -EFAULT; + + return ret; } void arch_get_info_guest(struct vcpu *v, vcpu_guest_context_u c) diff --git a/xen/arch/arm/hvm/hvm.c b/xen/arch/arm/hvm/hvm.c index 471c4cd..e95a794 100644 --- a/xen/arch/arm/hvm/hvm.c +++ b/xen/arch/arm/hvm/hvm.c @@ -7,9 +7,11 @@ #include <xsm/xsm.h> +#include <xen/hvm/save.h> #include <public/xen.h> #include <public/hvm/params.h> #include <public/hvm/hvm_op.h> +#include <public/arch-arm/hvm/save.h> #include <asm/hypercall.h> @@ -65,3 +67,143 @@ long do_hvm_op(unsigned long op, XEN_GUEST_HANDLE_PARAM(void) arg) return rc; } + +static int gic_save(struct domain *d, hvm_domain_context_t *h) +{ + struct hvm_hw_gic ctxt; + struct vcpu *v; + + /* Save the state of GICs */ + for_each_vcpu( d, v ) + { + ctxt.gic_hcr = v->arch.gic_hcr; + ctxt.gic_vmcr = v->arch.gic_vmcr; + ctxt.gic_apr = v->arch.gic_apr; + + if ( hvm_save_entry(GIC, v->vcpu_id, h, &ctxt) != 0 ) + return 1; + } + return 0; +} + +static int gic_load(struct domain *d, hvm_domain_context_t *h) +{ + int vcpuid; + struct hvm_hw_gic ctxt; + struct vcpu *v; + + /* Which vcpu is this? */ + vcpuid = hvm_load_instance(h); + if ( vcpuid >= d->max_vcpus || (v = d->vcpu[vcpuid]) == NULL ) + { + dprintk(XENLOG_G_ERR, "HVM restore: dom%u has no vcpu%u\n", + d->domain_id, vcpuid); + return -EINVAL; + } + + if ( hvm_load_entry(GIC, h, &ctxt) != 0 ) + return -EINVAL; + + v->arch.gic_hcr = ctxt.gic_hcr; + v->arch.gic_vmcr = ctxt.gic_vmcr; + v->arch.gic_apr = ctxt.gic_apr; + + return 0; +} + +HVM_REGISTER_SAVE_RESTORE(GIC, gic_save, gic_load, 1, HVMSR_PER_VCPU); + +static int vtimer_save(struct domain *d, hvm_domain_context_t *h) +{ + struct hvm_hw_vtimer ctxt; + struct vcpu *v; + + ctxt.vtb_offset = d->arch.virt_timer_base.offset; + + /* Save the state of vtimer */ + for_each_vcpu( d, v ) + { + ctxt.cval = v->arch.virt_timer.cval; + ctxt.ctl = v->arch.virt_timer.ctl; + if ( hvm_save_entry(VTIMER, v->vcpu_id, h, &ctxt) != 0 ) + return 1; + } + + return 0; +} + +static int vtimer_load(struct domain *d, hvm_domain_context_t *h) +{ + int vcpuid; + struct hvm_hw_vtimer ctxt; + struct vcpu *v; + /* Which vcpu is this? */ + vcpuid = hvm_load_instance(h); + if ( vcpuid >= d->max_vcpus || (v = d->vcpu[vcpuid]) == NULL ) + { + dprintk(XENLOG_G_ERR, "HVM restore: dom%u has no vcpu%u\n", + d->domain_id, vcpuid); + return -EINVAL; + } + + if ( hvm_load_entry(VTIMER, h, &ctxt) != 0 ) + return -EINVAL; + + v->arch.virt_timer.cval = ctxt.cval; + v->arch.virt_timer.ctl = ctxt.ctl; + v->arch.virt_timer.v = v; + + d->arch.virt_timer_base.offset = ctxt.vtb_offset; + + return 0; +} + +HVM_REGISTER_SAVE_RESTORE(VTIMER, vtimer_save, vtimer_load, 1, HVMSR_PER_VCPU); + +static int ptimer_save(struct domain *d, hvm_domain_context_t *h) +{ + struct hvm_hw_ptimer ctxt; + struct vcpu *v; + + ctxt.ptb_offset = d->arch.phys_timer_base.offset; + + /* Save the state of ptimer */ + for_each_vcpu( d, v ) + { + ctxt.p_cval = v->arch.phys_timer.cval; + ctxt.p_ctl = v->arch.phys_timer.ctl; + + if ( hvm_save_entry(PTIMER, v->vcpu_id, h, &ctxt) != 0 ) + return 1; + } + + return 0; +} + +static int ptimer_load(struct domain *d, hvm_domain_context_t *h) +{ + int vcpuid; + struct hvm_hw_ptimer ctxt; + struct vcpu *v; + /* Which vcpu is this? */ + vcpuid = hvm_load_instance(h); + if ( vcpuid >= d->max_vcpus || (v = d->vcpu[vcpuid]) == NULL ) + { + dprintk(XENLOG_G_ERR, "HVM restore: dom%u has no vcpu%u\n", + d->domain_id, vcpuid); + return -EINVAL; + } + + if ( hvm_load_entry(PTIMER, h, &ctxt) != 0 ) + return -EINVAL; + + v->arch.phys_timer.cval = ctxt.p_cval; + v->arch.phys_timer.ctl = ctxt.p_ctl; + v->arch.phys_timer.v = v; + + d->arch.phys_timer_base.offset = ctxt.ptb_offset; + + return 0; +} + +HVM_REGISTER_SAVE_RESTORE(PTIMER, ptimer_save, ptimer_load, 1, HVMSR_PER_VCPU); diff --git a/xen/common/Makefile b/xen/common/Makefile index 0dc2050..956cf29 100644 --- a/xen/common/Makefile +++ b/xen/common/Makefile @@ -60,6 +60,8 @@ subdir-$(CONFIG_COMPAT) += compat subdir-$(x86_64) += hvm +subdir-$(CONFIG_ARM) += hvm + subdir-$(coverage) += gcov subdir-y += libelf diff --git a/xen/include/public/arch-arm/hvm/save.h b/xen/include/public/arch-arm/hvm/save.h index fbfb2db..a84f49e 100644 --- a/xen/include/public/arch-arm/hvm/save.h +++ b/xen/include/public/arch-arm/hvm/save.h @@ -43,6 +43,44 @@ struct hvm_save_header DECLARE_HVM_SAVE_TYPE(HEADER, 1, struct hvm_save_header); +struct hvm_hw_gic +{ + uint32_t gic_hcr; + uint32_t gic_vmcr; + uint32_t gic_apr; +}; + +DECLARE_HVM_SAVE_TYPE(GIC, 3, struct hvm_hw_gic); + +struct hvm_hw_vtimer +{ + uint64_t vtb_offset; + uint64_t vtb_cval; + + uint32_t ctl; + uint64_t offset; + uint64_t cval; +}; + +DECLARE_HVM_SAVE_TYPE(VTIMER, 4, struct hvm_hw_vtimer); + +struct hvm_hw_ptimer +{ + uint64_t ptb_offset; + uint64_t ptb_cval; + + uint32_t p_ctl; + uint64_t p_offset; + uint64_t p_cval; +}; + +DECLARE_HVM_SAVE_TYPE(PTIMER, 5, struct hvm_hw_ptimer); + +/* + * Largest type-code in use + */ +#define HVM_SAVE_CODE_MAX 19 + #endif /* -- 1.8.1.2 _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx http://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |