From mboxrd@z Thu Jan 1 00:00:00 1970 From: Jaeyong Yoo Subject: [PATCH v5 1/6] xen/arm: Implement hvm save and restore Date: Wed, 06 Nov 2013 12:44:54 +0900 Message-ID: <00a601cedaa2$8e0bfaf0$aa23f0d0$%yoo@samsung.com> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="===============5899859385121255319==" Return-path: Content-language: ko List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Sender: xen-devel-bounces@lists.xen.org Errors-To: xen-devel-bounces@lists.xen.org To: xen-devel@lists.xen.org Cc: 'Eugene Fedotov' List-Id: xen-devel@lists.xenproject.org This is a multi-part message in MIME format. --===============5899859385121255319== Content-type: multipart/alternative; boundary="----=_NextPart_000_00A7_01CEDAED.FDF3A2F0" Content-language: ko This is a multi-part message in MIME format. ------=_NextPart_000_00A7_01CEDAED.FDF3A2F0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Implement save/restore of hvm context hypercall. In hvm context save/restore, we save gic, timer and vfp registers. Changes from v4: Save vcpu registers within hvm context, and purge the save-vcpu-register patch. Singed-off-by: Evgeny Fedotov --- xen/arch/arm/Makefile | 1 + xen/arch/arm/domctl.c | 89 ++++++- xen/arch/arm/hvm.c | 464 ++++++++++++++++++++++++++++++++- xen/arch/arm/save.c | 66 +++++ xen/common/Makefile | 2 + xen/include/asm-arm/hvm/support.h | 29 +++ xen/include/public/arch-arm/hvm/save.h | 130 +++++++++ 7 files changed, 779 insertions(+), 2 deletions(-) create mode 100644 xen/arch/arm/save.c create mode 100644 xen/include/asm-arm/hvm/support.h diff --git a/xen/arch/arm/Makefile b/xen/arch/arm/Makefile index 003ac84..8910a6c 100644 --- a/xen/arch/arm/Makefile +++ b/xen/arch/arm/Makefile @@ -31,6 +31,7 @@ obj-y += vuart.o obj-y += hvm.o obj-y += device.o obj-y += decode.o +obj-y += save.o #obj-bin-y += ....o diff --git a/xen/arch/arm/domctl.c b/xen/arch/arm/domctl.c index 851ee40..cb38e59 100644 --- a/xen/arch/arm/domctl.c +++ b/xen/arch/arm/domctl.c @@ -9,12 +9,99 @@ #include #include #include +#include +#include #include 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; + } + + /* Allocate our own marshalling buffer */ + ret = -ENOMEM; + if ( (c.data = xmalloc_bytes(c.size)) == NULL ) + { + printk("(gethvmcontext) xmalloc_bytes failed: %d\n", 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.c b/xen/arch/arm/hvm.c index 471c4cd..01ce2e7 100644 --- a/xen/arch/arm/hvm.c +++ b/xen/arch/arm/hvm.c @@ -7,14 +7,15 @@ #include +#include #include #include #include #include +#include long do_hvm_op(unsigned long op, XEN_GUEST_HANDLE_PARAM(void) arg) - { long rc = 0; @@ -65,3 +66,464 @@ long do_hvm_op(unsigned long op, XEN_GUEST_HANDLE_PARAM(void) arg) return rc; } + +static int vgic_irq_rank_save(struct vgic_rank *ext, + struct vgic_irq_rank *rank) +{ + spin_lock(&rank->lock); + /* Some of VGIC registers are not used yet, it is for a future usage */ + /* IENABLE, IACTIVE, IPEND, PENDSGI registers */ + ext->ienable = rank->ienable; + ext->iactive = rank->iactive; + ext->ipend = rank->ipend; + ext->pendsgi = rank->pendsgi; + /* ICFG */ + ext->icfg[0] = rank->icfg[0]; + ext->icfg[1] = rank->icfg[1]; + /* IPRIORITY */ + if ( sizeof(rank->ipriority) != sizeof (ext->ipriority) ) + { + dprintk(XENLOG_G_ERR, "hvm_hw_gic: check ipriority dumping space\n"); + return -EINVAL; + } + memcpy(ext->ipriority, rank->ipriority, sizeof(rank->ipriority)); + /* ITARGETS */ + if ( sizeof(rank->itargets) != sizeof (ext->itargets) ) + { + dprintk(XENLOG_G_ERR, "hvm_hw_gic: check itargets dumping space\n"); + return -EINVAL; + } + memcpy(ext->itargets, rank->itargets, sizeof(rank->itargets)); + spin_unlock(&rank->lock); + return 0; +} + +static int vgic_irq_rank_restore(struct vgic_irq_rank *rank, + struct vgic_rank *ext) +{ + spin_lock(&rank->lock); + /* IENABLE, IACTIVE, IPEND, PENDSGI registers */ + rank->ienable = ext->ienable; + rank->iactive = ext->iactive; + rank->ipend = ext->ipend; + rank->pendsgi = ext->pendsgi; + /* ICFG */ + rank->icfg[0] = ext->icfg[0]; + rank->icfg[1] = ext->icfg[1]; + /* IPRIORITY */ + if ( sizeof(rank->ipriority) != sizeof (ext->ipriority) ) + { + dprintk(XENLOG_G_ERR, "hvm_hw_gic: check ipriority dumping space\n"); + return -EINVAL; + } + memcpy(rank->ipriority, ext->ipriority, sizeof(rank->ipriority)); + /* ITARGETS */ + if ( sizeof(rank->itargets) != sizeof (ext->itargets) ) + { + dprintk(XENLOG_G_ERR, "hvm_hw_gic: check itargets dumping space\n"); + return -EINVAL; + } + memcpy(rank->itargets, ext->itargets, sizeof(rank->itargets)); + spin_unlock(&rank->lock); + return 0; +} + + +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; + + /* Save list registers and masks */ + /* (it is not necessary to save/restore them, but LR state can have + * influence on downtime after Live Migration (to be tested) + */ + if ( sizeof(v->arch.gic_lr) > sizeof (ctxt.gic_lr) ) + { + dprintk(XENLOG_G_ERR, "hvm_hw_gic: increase LR dumping space\n"); + return -EINVAL; + } + memcpy(ctxt.gic_lr, v->arch.gic_lr, sizeof(v->arch.gic_lr)); + ctxt.lr_mask = v->arch.lr_mask; + ctxt.event_mask = v->arch.event_mask; + + /* Save PPI states (per-CPU) */ + /* It is necessary if SMP enabled */ + if ( vgic_irq_rank_save(&ctxt.ppi_state, &v->arch.vgic.private_irqs) ) + return 1; + + 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; + + /* Restore list registers and masks */ + if ( sizeof(v->arch.gic_lr) > sizeof (ctxt.gic_lr) ) + { + dprintk(XENLOG_G_ERR, "hvm_hw_gic: increase LR dumping space\n"); + return -EINVAL; + } + memcpy(v->arch.gic_lr, ctxt.gic_lr, sizeof(v->arch.gic_lr)); + v->arch.lr_mask = ctxt.lr_mask; + v->arch.event_mask = ctxt.event_mask; + + /* Restore PPI states */ + if ( vgic_irq_rank_restore(&v->arch.vgic.private_irqs, &ctxt.ppi_state) ) + return 1; + + return 0; +} + +HVM_REGISTER_SAVE_RESTORE(GIC, gic_save, gic_load, 1, HVMSR_PER_VCPU); + +static int timer_save(struct domain *d, hvm_domain_context_t *h) +{ + struct hvm_hw_timer ctxt; + struct vcpu *v; + struct vtimer *t; + int i; + + /* Save the state of vtimer and ptimer */ + for_each_vcpu( d, v ) + { + t = &v->arch.virt_timer; + for ( i = 0; i < 2; i++ ) + { + ctxt.cval = t->cval; + ctxt.ctl = t->ctl; + ctxt.vtb_offset = i ? d->arch.phys_timer_base.offset : + d->arch.virt_timer_base.offset; + ctxt.type = i ? TIMER_TYPE_PHYS : TIMER_TYPE_VIRT; + if ( hvm_save_entry(A15_TIMER, v->vcpu_id, h, &ctxt) != 0 ) + return 1; + t = &v->arch.phys_timer; + } + } + + return 0; +} + +static int timer_load(struct domain *d, hvm_domain_context_t *h) +{ + int vcpuid; + struct hvm_hw_timer ctxt; + struct vcpu *v; + struct vtimer *t = NULL; + + /* 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(A15_TIMER, h, &ctxt) != 0 ) + return -EINVAL; + + + if ( ctxt.type == TIMER_TYPE_VIRT ) + { + t = &v->arch.virt_timer; + d->arch.virt_timer_base.offset = ctxt.vtb_offset; + + } + else + { + t = &v->arch.phys_timer; + d->arch.phys_timer_base.offset = ctxt.vtb_offset; + } + + t->cval = ctxt.cval; + t->ctl = ctxt.ctl; + t->v = v; + + return 0; +} + +HVM_REGISTER_SAVE_RESTORE(A15_TIMER, timer_save, timer_load, 2, HVMSR_PER_VCPU); + +static int cpu_save(struct domain *d, hvm_domain_context_t *h) +{ + struct hvm_hw_cpu ctxt; + struct vcpu_guest_core_regs c; + struct vcpu *v; + + /* Save the state of CPU */ + for_each_vcpu( d, v ) + { + memset(&ctxt, 0, sizeof(ctxt)); + + ctxt.sctlr = v->arch.sctlr; + ctxt.ttbr0 = v->arch.ttbr0; + ctxt.ttbr1 = v->arch.ttbr1; + ctxt.ttbcr = v->arch.ttbcr; + + ctxt.dacr = v->arch.dacr; + ctxt.ifar = v->arch.ifar; + ctxt.ifsr = v->arch.ifsr; + ctxt.dfar = v->arch.dfar; + ctxt.dfsr = v->arch.dfsr; + +#ifdef CONFIG_ARM_32 + ctxt.mair0 = v->arch.mair0; + ctxt.mair1 = v->arch.mair1; +#else + ctxt.mair0 = v->arch.mair; +#endif + /* Control Registers */ + ctxt.actlr = v->arch.actlr; + ctxt.sctlr = v->arch.sctlr; + ctxt.cpacr = v->arch.cpacr; + + ctxt.contextidr = v->arch.contextidr; + ctxt.tpidr_el0 = v->arch.tpidr_el0; + ctxt.tpidr_el1 = v->arch.tpidr_el1; + ctxt.tpidrro_el0 = v->arch.tpidrro_el0; + + /* CP 15 */ + ctxt.csselr = v->arch.csselr; + + ctxt.afsr0 = v->arch.afsr0; + ctxt.afsr1 = v->arch.afsr1; + ctxt.vbar = v->arch.vbar; + ctxt.par = v->arch.par; + ctxt.teecr = v->arch.teecr; + ctxt.teehbr = v->arch.teehbr; + ctxt.joscr = v->arch.joscr; + ctxt.jmcr = v->arch.jmcr; + + memset(&c, 0, sizeof(c)); + + /* get guest core registers */ + vcpu_regs_hyp_to_user(v, &c); + + ctxt.x0 = c.x0; + ctxt.x1 = c.x1; + ctxt.x2 = c.x2; + ctxt.x3 = c.x3; + ctxt.x4 = c.x4; + ctxt.x5 = c.x5; + ctxt.x6 = c.x6; + ctxt.x7 = c.x7; + ctxt.x8 = c.x8; + ctxt.x9 = c.x9; + ctxt.x10 = c.x10; + ctxt.x11 = c.x11; + ctxt.x12 = c.x12; + ctxt.x13 = c.x13; + ctxt.x14 = c.x14; + ctxt.x15 = c.x15; + ctxt.x16 = c.x16; + ctxt.x17 = c.x17; + ctxt.x18 = c.x18; + ctxt.x19 = c.x19; + ctxt.x20 = c.x20; + ctxt.x21 = c.x21; + ctxt.x22 = c.x22; + ctxt.x23 = c.x23; + ctxt.x24 = c.x24; + ctxt.x25 = c.x25; + ctxt.x26 = c.x26; + ctxt.x27 = c.x27; + ctxt.x28 = c.x28; + ctxt.x29 = c.x29; + ctxt.x30 = c.x30; + ctxt.pc64 = c.pc64; + ctxt.cpsr = c.cpsr; + ctxt.spsr_el1 = c.spsr_el1; /* spsr_svc */ + + #ifdef CONFIG_ARM_32 + ctxt.spsr_fiq = c.spsr_fiq; + ctxt.spsr_irq = c.spsr_irq; + ctxt.spsr_und = c.spsr_und; + ctxt.spsr_abt = c.spsr_abt; + #endif + #ifdef CONFIG_ARM_64 + ctxt.sp_el0 = c.sp_el0; + ctxt.sp_el1 = c.sp_el1; + ctxt.elr_el1 = c.elr_el1; + #endif + + /* check VFP state size before dumping */ + if ( sizeof(v->arch.vfp) > sizeof (ctxt.vfp) ) + { + dprintk(XENLOG_G_ERR, "hvm_hw_cpu: increase VFP dumping space\n"); + return -EINVAL; + } + memcpy((void*) &ctxt.vfp, (void*) &v->arch.vfp, sizeof(v->arch.vfp)); + + ctxt.pause_flags = v->pause_flags; + + if ( hvm_save_entry(VCPU, v->vcpu_id, h, &ctxt) != 0 ) + return 1; + } + return 0; +} + +static int cpu_load(struct domain *d, hvm_domain_context_t *h) +{ + int vcpuid; + struct hvm_hw_cpu ctxt; + struct vcpu *v; + struct vcpu_guest_core_regs c; + + /* 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(VCPU, h, &ctxt) != 0 ) + return -EINVAL; + + v->arch.sctlr = ctxt.sctlr; + v->arch.ttbr0 = ctxt.ttbr0; + v->arch.ttbr1 = ctxt.ttbr1; + v->arch.ttbcr = ctxt.ttbcr; + + v->arch.dacr = ctxt.dacr; + v->arch.ifar = ctxt.ifar; + v->arch.ifsr = ctxt.ifsr; + v->arch.dfar = ctxt.dfar; + v->arch.dfsr = ctxt.dfsr; + +#ifdef CONFIG_ARM_32 + v->arch.mair0 = ctxt.mair0; + v->arch.mair1 = ctxt.mair1; +#else + v->arch.mair = ctxt.mair0; +#endif + + /* Control Registers */ + v->arch.actlr = ctxt.actlr; + v->arch.cpacr = ctxt.cpacr; + v->arch.contextidr = ctxt.contextidr; + v->arch.tpidr_el0 = ctxt.tpidr_el0; + v->arch.tpidr_el1 = ctxt.tpidr_el1; + v->arch.tpidrro_el0 = ctxt.tpidrro_el0; + + /* CP 15 */ + v->arch.csselr = ctxt.csselr; + + v->arch.afsr0 = ctxt.afsr0; + v->arch.afsr1 = ctxt.afsr1; + v->arch.vbar = ctxt.vbar; + v->arch.par = ctxt.par; + v->arch.teecr = ctxt.teecr; + v->arch.teehbr = ctxt.teehbr; + v->arch.joscr = ctxt.joscr; + v->arch.jmcr = ctxt.jmcr; + + /* fill guest core registers */ + memset(&c, 0, sizeof(c)); + c.x0 = ctxt.x0; + c.x1 = ctxt.x1; + c.x2 = ctxt.x2; + c.x3 = ctxt.x3; + c.x4 = ctxt.x4; + c.x5 = ctxt.x5; + c.x6 = ctxt.x6; + c.x7 = ctxt.x7; + c.x8 = ctxt.x8; + c.x9 = ctxt.x9; + c.x10 = ctxt.x10; + c.x11 = ctxt.x11; + c.x12 = ctxt.x12; + c.x13 = ctxt.x13; + c.x14 = ctxt.x14; + c.x15 = ctxt.x15; + c.x16 = ctxt.x16; + c.x17 = ctxt.x17; + c.x18 = ctxt.x18; + c.x19 = ctxt.x19; + c.x20 = ctxt.x20; + c.x21 = ctxt.x21; + c.x22 = ctxt.x22; + c.x23 = ctxt.x23; + c.x24 = ctxt.x24; + c.x25 = ctxt.x25; + c.x26 = ctxt.x26; + c.x27 = ctxt.x27; + c.x28 = ctxt.x28; + c.x29 = ctxt.x29; + c.x30 = ctxt.x30; + c.pc64 = ctxt.pc64; + c.cpsr = ctxt.cpsr; + c.spsr_el1 = ctxt.spsr_el1; /* spsr_svc */ + + #ifdef CONFIG_ARM_32 + c.spsr_fiq = ctxt.spsr_fiq; + c.spsr_irq = ctxt.spsr_irq; + c.spsr_und = ctxt.spsr_und; + c.spsr_abt = ctxt.spsr_abt; + #endif + #ifdef CONFIG_ARM_64 + c.sp_el0 = ctxt.sp_el0; + c.sp_el1 = ctxt.sp_el1; + c.elr_el1 = ctxt.elr_el1; + #endif + + /* set guest core registers */ + vcpu_regs_user_to_hyp(v, &c); + + if ( sizeof(v->arch.vfp) > sizeof (ctxt.vfp) ) + { + dprintk(XENLOG_G_ERR, "hvm_hw_cpu: increase VFP dumping space\n"); + return -EINVAL; + } + + memcpy(&v->arch.vfp, &ctxt, sizeof(v->arch.vfp)); + + v->is_initialised = 1; + v->pause_flags = ctxt.pause_flags; + + return 0; +} + +HVM_REGISTER_SAVE_RESTORE(VCPU, cpu_save, cpu_load, 1, HVMSR_PER_VCPU); + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/arch/arm/save.c b/xen/arch/arm/save.c new file mode 100644 index 0000000..c923910 --- /dev/null +++ b/xen/arch/arm/save.c @@ -0,0 +1,66 @@ +/* + * hvm/save.c: Save and restore HVM guest's emulated hardware state for ARM. + * + * Copyright (c) 2013, Samsung Electronics. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307 USA. + */ + +#include +#include + +void arch_hvm_save(struct domain *d, struct hvm_save_header *hdr) +{ + hdr->cpuid = READ_SYSREG32(MIDR_EL1); +} + +int arch_hvm_load(struct domain *d, struct hvm_save_header *hdr) +{ + uint32_t cpuid; + + if ( hdr->magic != HVM_FILE_MAGIC ) + { + printk(XENLOG_G_ERR "HVM%d restore: bad magic number %#"PRIx32"\n", + d->domain_id, hdr->magic); + return -1; + } + + if ( hdr->version != HVM_FILE_VERSION ) + { + printk(XENLOG_G_ERR "HVM%d restore: unsupported version %u\n", + d->domain_id, hdr->version); + return -1; + } + + cpuid = READ_SYSREG32(MIDR_EL1); + if ( hdr->cpuid != cpuid ) + { + printk(XENLOG_G_INFO "HVM%d restore: VM saved on one CPU " + "(%#"PRIx32") and restored on another (%#"PRIx32").\n", + d->domain_id, hdr->cpuid, cpuid); + return -1; + } + + return 0; +} + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/common/Makefile b/xen/common/Makefile index 686f7a1..f943302 100644 --- a/xen/common/Makefile +++ b/xen/common/Makefile @@ -63,6 +63,8 @@ subdir-$(CONFIG_COMPAT) += compat subdir-$(x86_64) += hvm +subdir-$(CONFIG_ARM) += hvm + subdir-$(coverage) += gcov subdir-y += libelf diff --git a/xen/include/asm-arm/hvm/support.h b/xen/include/asm-arm/hvm/support.h new file mode 100644 index 0000000..8311f2f --- /dev/null +++ b/xen/include/asm-arm/hvm/support.h @@ -0,0 +1,29 @@ +/* + * support.h: HVM support routines used by ARMv7 VE. + * + * Copyright (c) 2012, Citrix Systems + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef __ASM_ARM_HVM_SUPPORT_H__ +#define __ASM_ARM_HVM_SUPPORT_H__ + +#include +#include +#include +#include +#include + +#endif /* __ASM_ARM_HVM_SUPPORT_H__ */ diff --git a/xen/include/public/arch-arm/hvm/save.h b/xen/include/public/arch-arm/hvm/save.h index 75b8e65..1f71c41 100644 --- a/xen/include/public/arch-arm/hvm/save.h +++ b/xen/include/public/arch-arm/hvm/save.h @@ -26,6 +26,136 @@ #ifndef __XEN_PUBLIC_HVM_SAVE_ARM_H__ #define __XEN_PUBLIC_HVM_SAVE_ARM_H__ +#define HVM_FILE_MAGIC 0x92385520 +#define HVM_FILE_VERSION 0x00000001 + + +struct hvm_save_header +{ + uint32_t magic; /* Must be HVM_FILE_MAGIC */ + uint32_t version; /* File format version */ + uint64_t changeset; /* Version of Xen that saved this file */ + uint32_t cpuid; /* MIDR_EL1 on the saving machine */ +}; + +DECLARE_HVM_SAVE_TYPE(HEADER, 1, struct hvm_save_header); + +struct vgic_rank +{ + uint32_t ienable, iactive, ipend, pendsgi; + uint32_t icfg[2]; + uint32_t ipriority[8]; + uint32_t itargets[8]; +}; + +struct hvm_hw_gic +{ + uint32_t gic_hcr; + uint32_t gic_vmcr; + uint32_t gic_apr; + uint32_t gic_lr[64]; + uint64_t event_mask; + uint64_t lr_mask; + struct vgic_rank ppi_state; +}; + +DECLARE_HVM_SAVE_TYPE(GIC, 2, struct hvm_hw_gic); + +#define TIMER_TYPE_VIRT 0 +#define TIMER_TYPE_PHYS 1 + +struct hvm_hw_timer +{ + uint64_t vtb_offset; + uint32_t ctl; + uint64_t cval; + uint32_t type; +}; + +DECLARE_HVM_SAVE_TYPE(A15_TIMER, 3, struct hvm_hw_timer); + + +struct hvm_hw_cpu +{ + uint64_t vfp[34]; /* Vector floating pointer */ + /* VFP v3 state is 34x64 bit, VFP v4 is not yet supported */ + + /* Guest core registers */ + uint64_t x0; /* r0_usr */ + uint64_t x1; /* r1_usr */ + uint64_t x2; /* r2_usr */ + uint64_t x3; /* r3_usr */ + uint64_t x4; /* r4_usr */ + uint64_t x5; /* r5_usr */ + uint64_t x6; /* r6_usr */ + uint64_t x7; /* r7_usr */ + uint64_t x8; /* r8_usr */ + uint64_t x9; /* r9_usr */ + uint64_t x10; /* r10_usr */ + uint64_t x11; /* r11_usr */ + uint64_t x12; /* r12_usr */ + uint64_t x13; /* sp_usr */ + uint64_t x14; /* lr_usr; */ + uint64_t x15; /* __unused_sp_hyp */ + uint64_t x16; /* lr_irq */ + uint64_t x17; /* sp_irq */ + uint64_t x18; /* lr_svc */ + uint64_t x19; /* sp_svc */ + uint64_t x20; /* lr_abt */ + uint64_t x21; /* sp_abt */ + uint64_t x22; /* lr_und */ + uint64_t x23; /* sp_und */ + uint64_t x24; /* r8_fiq */ + uint64_t x25; /* r9_fiq */ + uint64_t x26; /* r10_fiq */ + uint64_t x27; /* r11_fiq */ + uint64_t x28; /* r12_fiq */ + uint64_t x29; /* fp,sp_fiq */ + uint64_t x30; /* lr_fiq */ + uint64_t pc64; /* ELR_EL2 */ + uint32_t cpsr; /* SPSR_EL2 */ + uint32_t spsr_el1; /*spsr_svc */ + /* AArch32 guests only */ + uint32_t spsr_fiq, spsr_irq, spsr_und, spsr_abt; + /* AArch64 guests only */ + uint64_t sp_el0; + uint64_t sp_el1, elr_el1; + + uint32_t sctlr, ttbcr; + uint64_t ttbr0, ttbr1; + + uint32_t ifar, dfar; + uint32_t ifsr, dfsr; + uint32_t dacr; + uint64_t par; + + uint64_t mair0, mair1; + uint64_t tpidr_el0; + uint64_t tpidr_el1; + uint64_t tpidrro_el0; + uint64_t vbar; + + /* Control Registers */ + uint32_t actlr; + uint32_t cpacr; + uint32_t afsr0, afsr1; + uint32_t contextidr; + uint32_t teecr, teehbr; /* ThumbEE, 32-bit guests only */ + uint32_t joscr, jmcr; + /* CP 15 */ + uint32_t csselr; + + unsigned long pause_flags; + +}; + +DECLARE_HVM_SAVE_TYPE(VCPU, 4, struct hvm_hw_cpu); + +/* + * Largest type-code in use + */ +#define HVM_SAVE_CODE_MAX 4 + #endif /* -- 1.8.1.2 ------=_NextPart_000_00A7_01CEDAED.FDF3A2F0 Content-Type: text/html; charset="us-ascii" Content-Transfer-Encoding: quoted-printable

Implement save/restore of hvm context = hypercall.

In hvm context save/restore, we save gic, timer and vfp = registers.

 

Changes from v4: Save vcpu registers within hvm context, = and purge

the save-vcpu-register patch.

 

Singed-off-by: Evgeny Fedotov = <e.fedotov@samsung.com>

---

= xen/arch/arm/Makefile        &nbs= p;         |   1 = +

= xen/arch/arm/domctl.c        &nbs= p;         |  89 = ++++++-

= xen/arch/arm/hvm.c         &= nbsp;           | 464 = ++++++++++++++++++++++++++++++++-

= xen/arch/arm/save.c         =            |  66 = +++++

= xen/common/Makefile         =            = |   2 +

= xen/include/asm-arm/hvm/support.h      |  = 29 +++

= xen/include/public/arch-arm/hvm/save.h | 130 = +++++++++

= 7 files changed, 779 insertions(+), 2 = deletions(-)

create mode 100644 = xen/arch/arm/save.c

create mode 100644 = xen/include/asm-arm/hvm/support.h

 

diff --git a/xen/arch/arm/Makefile = b/xen/arch/arm/Makefile

index 003ac84..8910a6c 100644

--- = a/xen/arch/arm/Makefile

+++ b/xen/arch/arm/Makefile

@@ -31,6 +31,7 @@ obj-y +=3D = vuart.o

= obj-y +=3D hvm.o

obj-y +=3D device.o

obj-y +=3D = decode.o

+obj-y +=3D save.o

 

#obj-bin-y +=3D = ....o

 

diff --git a/xen/arch/arm/domctl.c = b/xen/arch/arm/domctl.c

index 851ee40..cb38e59 100644

--- = a/xen/arch/arm/domctl.c

+++ b/xen/arch/arm/domctl.c

@@ -9,12 +9,99 = @@

= #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 =3D 0;

+    bool_t copyback = =3D 0;

+

+    switch ( domctl->cmd = )

+    {

+    case = XEN_DOMCTL_sethvmcontext:

+    = {

+        struct = hvm_domain_context c =3D { .size =3D domctl->u.hvmcontext.size = };

+

+        ret =3D = -ENOMEM;

+        if ( (c.data = =3D xmalloc_bytes(c.size)) =3D=3D NULL )

+          = ;  goto sethvmcontext_out;

+

+        ret =3D = -EFAULT;

+        if ( = copy_from_guest(c.data, domctl->u.hvmcontext.buffer, c.size) !=3D 0 = )

+          = ;  goto sethvmcontext_out;

+

+        = domain_pause(d);

+        ret =3D = hvm_load(d, &c);

+        = domain_unpause(d);

+

+    = sethvmcontext_out:

+        if ( c.data = !=3D NULL )

+          = ;  xfree(c.data);

+    }

+    = break;

+    case = XEN_DOMCTL_gethvmcontext:

+    = {

+        struct = hvm_domain_context c =3D { 0 };

+

+        ret =3D = -EINVAL;

+

+        c.size =3D = 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 =3D c.size;

+          = ;  ret =3D 0;

+          = ;  goto gethvmcontext_out;

+    =     }

+

+        /* Check that = the client has a big enough buffer */

+        ret =3D = -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;

+        = }

+

+        /* Allocate our = own marshalling buffer */

+        ret =3D = -ENOMEM;

+        if ( (c.data = =3D xmalloc_bytes(c.size)) =3D=3D NULL )

+        = {

+          = ;  printk("(gethvmcontext) xmalloc_bytes failed: %d\n", = c.size );

+          = ;  goto gethvmcontext_out;

+        = }

+

+        = domain_pause(d);

+        ret =3D = hvm_save(d, &c);

+        = domain_unpause(d);

+

+        = domctl->u.hvmcontext.size =3D c.cur;

+        if ( = copy_to_guest(domctl->u.hvmcontext.buffer, c.data, c.size) !=3D 0 = )

+        = {

+          = ;  printk("(gethvmcontext) copy to guest = failed\n");

+          = ;  ret =3D -EFAULT;

+        = }

+

+    = gethvmcontext_out:

+        copyback =3D = 1;

+

+        if ( c.data = !=3D NULL )

+          = ;  xfree(c.data);

+    }

+    = break;

+

+    default:

+        return = -EINVAL;

+    }

+

+    if ( copyback = && __copy_to_guest(u_domctl, domctl, 1) = )

+        ret =3D = -EFAULT;

+

+    return ret;

}

 

void arch_get_info_guest(struct = vcpu *v, vcpu_guest_context_u c)

diff --git a/xen/arch/arm/hvm.c = b/xen/arch/arm/hvm.c

index 471c4cd..01ce2e7 100644

--- = a/xen/arch/arm/hvm.c

+++ b/xen/arch/arm/hvm.c

@@ -7,14 +7,15 = @@

 

#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 = <asm/hypercall.h>

+#include <asm/gic.h>

 

long do_hvm_op(unsigned long op, = XEN_GUEST_HANDLE_PARAM(void) arg)

-

{

     long rc = =3D 0;

 

@@ -65,3 +66,464 @@ long do_hvm_op(unsigned long op, = XEN_GUEST_HANDLE_PARAM(void) arg)

 

     return = rc;

= }

+

+static int vgic_irq_rank_save(struct vgic_rank = *ext,

+          = ;            =          struct vgic_irq_rank = *rank)

+{

+    = spin_lock(&rank->lock);

+    /* Some of VGIC = registers are not used yet, it is for a future usage = */

+    /* IENABLE, IACTIVE, IPEND,  = PENDSGI registers */

+    ext->ienable =3D = rank->ienable;

+    ext->iactive =3D = rank->iactive;

+    ext->ipend =3D = rank->ipend;

+    ext->pendsgi =3D = rank->pendsgi;

+    /* ICFG */

+    ext->icfg[0] = =3D rank->icfg[0];

+    ext->icfg[1] =3D = rank->icfg[1];

+    /* IPRIORITY */

+    if ( = sizeof(rank->ipriority) !=3D sizeof (ext->ipriority) = )

+    {

+        = dprintk(XENLOG_G_ERR, "hvm_hw_gic: check ipriority dumping = space\n");

+        return = -EINVAL;

+    }

+    = memcpy(ext->ipriority, rank->ipriority, = sizeof(rank->ipriority));

+    /* ITARGETS = */

+    if ( sizeof(rank->itargets) !=3D = sizeof (ext->itargets) )

+    = {

+        = dprintk(XENLOG_G_ERR, "hvm_hw_gic: check itargets dumping = space\n");

+        return = -EINVAL;

+    }

+    = memcpy(ext->itargets, rank->itargets, = sizeof(rank->itargets));

+    = spin_unlock(&rank->lock);

+    return = 0;

+}

+

+static int vgic_irq_rank_restore(struct vgic_irq_rank = *rank,

+          = ;            =             = struct vgic_rank *ext)

+{

+    = spin_lock(&rank->lock);

+    /* IENABLE, = IACTIVE, IPEND,  PENDSGI registers */

+    = rank->ienable =3D ext->ienable;

+    = rank->iactive =3D ext->iactive;

+    rank->ipend = =3D ext->ipend;

+    rank->pendsgi =3D = ext->pendsgi;

+    /* ICFG */

+    = rank->icfg[0] =3D ext->icfg[0];

+    = rank->icfg[1] =3D ext->icfg[1];

+    /* IPRIORITY = */

+    if ( sizeof(rank->ipriority) !=3D = sizeof (ext->ipriority) )

+    = {

+        = dprintk(XENLOG_G_ERR, "hvm_hw_gic: check ipriority dumping = space\n");

+        return = -EINVAL;

+    }

+    = memcpy(rank->ipriority, ext->ipriority, = sizeof(rank->ipriority));

+    /* ITARGETS = */

+    if ( sizeof(rank->itargets) !=3D = sizeof (ext->itargets) )

+    = {

+        = dprintk(XENLOG_G_ERR, "hvm_hw_gic: check itargets dumping = space\n");

+        return = -EINVAL;

+    }

+    = memcpy(rank->itargets, ext->itargets, = sizeof(rank->itargets));

+    = spin_unlock(&rank->lock);

+    return = 0;

+}

+

+

+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 = =3D v->arch.gic_hcr;

+        ctxt.gic_vmcr = =3D v->arch.gic_vmcr;

+        ctxt.gic_apr = =3D v->arch.gic_apr;

+

+        /* Save list = registers and masks */

+        /* (it is not = necessary to save/restore them, but LR state can = have

+         * = influence on downtime after Live Migration (to be = tested)

+         = */

+        if ( = sizeof(v->arch.gic_lr) > sizeof (ctxt.gic_lr) = )

+        = {

+          = ;   dprintk(XENLOG_G_ERR, "hvm_hw_gic: increase LR = dumping space\n");

+          = ;   return -EINVAL;

+        = }

+        = memcpy(ctxt.gic_lr, v->arch.gic_lr, = sizeof(v->arch.gic_lr));

+        ctxt.lr_mask = =3D v->arch.lr_mask;

+        ctxt.event_mask = =3D v->arch.event_mask;

+

+        /* Save PPI = states (per-CPU) */

+        /* It is = necessary if SMP enabled */

+        if ( = vgic_irq_rank_save(&ctxt.ppi_state,  = &v->arch.vgic.private_irqs) )

+          = ;  return 1;

+

+        if ( = hvm_save_entry(GIC, v->vcpu_id, h, &ctxt) !=3D 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 =3D = hvm_load_instance(h);

+    if ( vcpuid >=3D d->max_vcpus || = (v =3D d->vcpu[vcpuid]) =3D=3D 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) !=3D 0 )

+        return = -EINVAL;

+

+    v->arch.gic_hcr =3D = ctxt.gic_hcr;

+    v->arch.gic_vmcr =3D = ctxt.gic_vmcr;

+    v->arch.gic_apr =3D = ctxt.gic_apr;

+

+    /* Restore list registers and masks = */

+    if ( sizeof(v->arch.gic_lr) > = sizeof (ctxt.gic_lr) )

+    {

+         = dprintk(XENLOG_G_ERR, "hvm_hw_gic: increase LR dumping = space\n");

+         return = -EINVAL;

+    }

+    = memcpy(v->arch.gic_lr, ctxt.gic_lr, = sizeof(v->arch.gic_lr));

+    = v->arch.lr_mask =3D ctxt.lr_mask;

+    = v->arch.event_mask =3D ctxt.event_mask;

+

+    /* Restore PPI = states */

+    if ( = vgic_irq_rank_restore(&v->arch.vgic.private_irqs, = &ctxt.ppi_state) )

+        return = 1;

+

+    return 0;

+}

+

+HVM_REGISTER_SAVE_RESTORE(GIC, = gic_save, gic_load, 1, HVMSR_PER_VCPU);

+

+static int timer_save(struct = domain *d, hvm_domain_context_t *h)

+{

+    struct = hvm_hw_timer ctxt;

+    struct vcpu *v;

+    struct vtimer = *t;

+    int i;

+

+    /* Save the = state of vtimer and ptimer */

+    for_each_vcpu( = d, v )

+    {

+        t =3D = &v->arch.virt_timer;

+        for ( i =3D 0; = i < 2; i++ )

+        = {

+          = ;  ctxt.cval =3D t->cval;

+          = ;  ctxt.ctl =3D t->ctl;

+          = ;  ctxt.vtb_offset =3D i ? d->arch.phys_timer_base.offset = :

+       =          d->arch.virt_tim= er_base.offset;

+          = ;  ctxt.type =3D i ? TIMER_TYPE_PHYS : = TIMER_TYPE_VIRT;

+          = ;  if ( hvm_save_entry(A15_TIMER, v->vcpu_id, h, &ctxt) !=3D = 0 )

+          = ;      return 1;

+          = ;  t =3D &v->arch.phys_timer;

+        = }

+ =    }

+

+    return 0;

+}

+

+static int timer_load(struct = domain *d, hvm_domain_context_t *h)

+{

+    int = vcpuid;

+    struct hvm_hw_timer = ctxt;

+    struct vcpu *v;

+    struct vtimer = *t =3D NULL;

+

+    /* Which vcpu is this? = */

+    vcpuid =3D = hvm_load_instance(h);

+

+    if ( vcpuid >=3D d->max_vcpus || = (v =3D d->vcpu[vcpuid]) =3D=3D NULL )

+    = {

+        = dprintk(XENLOG_G_ERR, "HVM restore: dom%u has no = vcpu%u\n",

+          = ;      d->domain_id, = vcpuid);

+        return = -EINVAL;

+    }

+

+    if ( = hvm_load_entry(A15_TIMER, h, &ctxt) !=3D 0 )

+        return = -EINVAL;

+

+

+    if ( ctxt.type =3D=3D TIMER_TYPE_VIRT = )

+    {

+        t =3D = &v->arch.virt_timer;

+        = d->arch.virt_timer_base.offset =3D = ctxt.vtb_offset;

+

+    }

+    = else

+    {

+      =   t =3D &v->arch.phys_timer;

+        = d->arch.phys_timer_base.offset =3D = ctxt.vtb_offset;

+    }

+

+    t->cval =3D = ctxt.cval;

+    t->ctl =3D = ctxt.ctl;

+    t->v =3D v;

+

+    return = 0;

+}

+

+HVM_REGISTER_SAVE_RESTORE(A15_TIMER, timer_save, = timer_load, 2, HVMSR_PER_VCPU);

+

+static int cpu_save(struct domain = *d, hvm_domain_context_t *h)

+{

+    struct = hvm_hw_cpu ctxt;

+    struct vcpu_guest_core_regs = c;

+    struct vcpu *v;

+

+    /* Save the = state of CPU */

+    for_each_vcpu( d, v = )

+    {

+        = memset(&ctxt, 0, sizeof(ctxt));

+

+        ctxt.sctlr =3D = v->arch.sctlr;

+        ctxt.ttbr0 =3D = v->arch.ttbr0;

+        ctxt.ttbr1 =3D = v->arch.ttbr1;

+        ctxt.ttbcr =3D = v->arch.ttbcr;

+

+        ctxt.dacr =3D = v->arch.dacr;

+        ctxt.ifar =3D = v->arch.ifar;

+        ctxt.ifsr =3D = v->arch.ifsr;

+        ctxt.dfar =3D = v->arch.dfar;

+        ctxt.dfsr =3D = v->arch.dfsr;

+

+#ifdef CONFIG_ARM_32

+        ctxt.mair0 =3D = v->arch.mair0;

+        ctxt.mair1 =3D = v->arch.mair1;

+#else

+        ctxt.mair0 =3D = v->arch.mair;

+#endif

+        /* Control = Registers */

+        ctxt.actlr =3D = v->arch.actlr;

+        ctxt.sctlr =3D = v->arch.sctlr;

+        ctxt.cpacr =3D = v->arch.cpacr;

+

+        ctxt.contextidr = =3D v->arch.contextidr;

+        ctxt.tpidr_el0 = =3D v->arch.tpidr_el0;

+        ctxt.tpidr_el1 = =3D v->arch.tpidr_el1;

+        = ctxt.tpidrro_el0 =3D v->arch.tpidrro_el0;

+

+        /* CP 15 = */

+        ctxt.csselr =3D = v->arch.csselr;

+

+        ctxt.afsr0 =3D = v->arch.afsr0;

+        ctxt.afsr1 =3D = v->arch.afsr1;

+        ctxt.vbar =3D = v->arch.vbar;

+        ctxt.par =3D = v->arch.par;

+        ctxt.teecr =3D = v->arch.teecr;

+        ctxt.teehbr =3D = v->arch.teehbr;

+        ctxt.joscr =3D = v->arch.joscr;

+        ctxt.jmcr =3D = v->arch.jmcr;

+

+        memset(&c, = 0, sizeof(c));

+

+        /* get guest = core registers */

+        = vcpu_regs_hyp_to_user(v, &c);

+

+        ctxt.x0 =3D = c.x0;

+        ctxt.x1 =3D = c.x1;

+        ctxt.x2 =3D = c.x2;

+        ctxt.x3 =3D = c.x3;

+        ctxt.x4 =3D = c.x4;

+        ctxt.x5 =3D = c.x5;

+        ctxt.x6 =3D = c.x6;

+        ctxt.x7 =3D = c.x7;

+        ctxt.x8 =3D = c.x8;

+        ctxt.x9 =3D = c.x9;

+        ctxt.x10 =3D = c.x10;

+        ctxt.x11 =3D = c.x11;

+        ctxt.x12 =3D = c.x12;

+        ctxt.x13 =3D = c.x13;

+        ctxt.x14 =3D = c.x14;

+        ctxt.x15 =3D = c.x15;

+        ctxt.x16 =3D = c.x16;

+        ctxt.x17 =3D = c.x17;

+        ctxt.x18 =3D = c.x18;

+        ctxt.x19 =3D = c.x19;

+        ctxt.x20 =3D = c.x20;

+        ctxt.x21 =3D = c.x21;

+        ctxt.x22 =3D = c.x22;

+        ctxt.x23 =3D = c.x23;

+        ctxt.x24 =3D = c.x24;

+        ctxt.x25 =3D = c.x25;

+        ctxt.x26 =3D = c.x26;

+        ctxt.x27 =3D = c.x27;

+        ctxt.x28 =3D = c.x28;

+        ctxt.x29 =3D = c.x29;

+        ctxt.x30 =3D = c.x30;

+        ctxt.pc64 =3D = c.pc64;

+        ctxt.cpsr =3D = c.cpsr;

+        ctxt.spsr_el1 = =3D c.spsr_el1; /* spsr_svc */

+

+        #ifdef = CONFIG_ARM_32

+          = ;      ctxt.spsr_fiq =3D = c.spsr_fiq;

+          = ;      ctxt.spsr_irq =3D = c.spsr_irq;

+          = ;      ctxt.spsr_und =3D = c.spsr_und;

+          = ;      ctxt.spsr_abt =3D = c.spsr_abt;

+        = #endif

+        #ifdef = CONFIG_ARM_64

+          = ;      ctxt.sp_el0 =3D = c.sp_el0;

+          = ;      ctxt.sp_el1 =3D = c.sp_el1;

+          = ;      ctxt.elr_el1 =3D = c.elr_el1;

+        = #endif

+

+        /* check VFP = state size before dumping */

+        if ( = sizeof(v->arch.vfp) > sizeof (ctxt.vfp) )

+        = {

+          = ;  dprintk(XENLOG_G_ERR, "hvm_hw_cpu: increase VFP dumping = space\n");

+          = ;  return -EINVAL;

+        = }

+        memcpy((void*) = &ctxt.vfp, (void*) &v->arch.vfp, = sizeof(v->arch.vfp));

+

+        = ctxt.pause_flags =3D v->pause_flags;

+

+        if ( = hvm_save_entry(VCPU, v->vcpu_id, h, &ctxt) !=3D 0 = )

+          = ;  return 1;

+    }

+    return = 0;

+}

+

+static int cpu_load(struct domain *d, hvm_domain_context_t = *h)

+{

+    int vcpuid;

+    struct = hvm_hw_cpu ctxt;

+    struct vcpu *v;

+    struct = vcpu_guest_core_regs c;

+

+    /* Which vcpu is this? = */

+    vcpuid =3D = hvm_load_instance(h);

+    if ( vcpuid >=3D d->max_vcpus || = (v =3D d->vcpu[vcpuid]) =3D=3D NULL )

+    = {

+        = dprintk(XENLOG_G_ERR, "HVM restore: dom%u has no = vcpu%u\n",

+          = ;      d->domain_id, = vcpuid);

+        return = -EINVAL;

+    }

+

+    if ( = hvm_load_entry(VCPU, h, &ctxt) !=3D 0 )

+        return = -EINVAL;

+

+    v->arch.sctlr =3D = ctxt.sctlr;

+    v->arch.ttbr0 =3D = ctxt.ttbr0;

+    v->arch.ttbr1 =3D = ctxt.ttbr1;

+    v->arch.ttbcr =3D = ctxt.ttbcr;

+

+    v->arch.dacr =3D = ctxt.dacr;

+    v->arch.ifar =3D = ctxt.ifar;

+    v->arch.ifsr =3D = ctxt.ifsr;

+    v->arch.dfar =3D = ctxt.dfar;

+    v->arch.dfsr =3D = ctxt.dfsr;

+

+#ifdef CONFIG_ARM_32

+    = v->arch.mair0 =3D ctxt.mair0;

+    = v->arch.mair1 =3D ctxt.mair1;

+#else

+    v->arch.mair = =3D ctxt.mair0;

+#endif

+

+    /* Control Registers = */

+    v->arch.actlr =3D = ctxt.actlr;

+    v->arch.cpacr =3D = ctxt.cpacr;

+    v->arch.contextidr =3D = ctxt.contextidr;

+    v->arch.tpidr_el0 =3D = ctxt.tpidr_el0;

+    v->arch.tpidr_el1 =3D = ctxt.tpidr_el1;

+    v->arch.tpidrro_el0 =3D = ctxt.tpidrro_el0;

+

+    /* CP 15 */

+    = v->arch.csselr =3D ctxt.csselr;

+

+    = v->arch.afsr0 =3D ctxt.afsr0;

+    = v->arch.afsr1 =3D ctxt.afsr1;

+    v->arch.vbar = =3D ctxt.vbar;

+    v->arch.par =3D = ctxt.par;

+    v->arch.teecr =3D = ctxt.teecr;

+    v->arch.teehbr =3D = ctxt.teehbr;

+    v->arch.joscr =3D = ctxt.joscr;

+    v->arch.jmcr =3D = ctxt.jmcr;

+

+    /* fill guest core registers = */

+    memset(&c, 0, = sizeof(c));

+    c.x0 =3D = ctxt.x0;

+    c.x1 =3D = ctxt.x1;

+    c.x2 =3D = ctxt.x2;

+    c.x3 =3D = ctxt.x3;

+    c.x4 =3D = ctxt.x4;

+    c.x5 =3D = ctxt.x5;

+    c.x6 =3D = ctxt.x6;

+    c.x7 =3D = ctxt.x7;

+    c.x8 =3D = ctxt.x8;

+    c.x9 =3D = ctxt.x9;

+    c.x10 =3D = ctxt.x10;

+    c.x11 =3D = ctxt.x11;

+    c.x12 =3D = ctxt.x12;

+    c.x13 =3D = ctxt.x13;

+    c.x14 =3D = ctxt.x14;

+    c.x15 =3D = ctxt.x15;

+    c.x16 =3D = ctxt.x16;

+    c.x17 =3D = ctxt.x17;

+    c.x18 =3D = ctxt.x18;

+    c.x19 =3D = ctxt.x19;

+    c.x20 =3D = ctxt.x20;

+    c.x21 =3D = ctxt.x21;

+    c.x22 =3D = ctxt.x22;

+    c.x23 =3D = ctxt.x23;

+    c.x24 =3D = ctxt.x24;

+    c.x25 =3D = ctxt.x25;

+    c.x26 =3D = ctxt.x26;

+    c.x27 =3D = ctxt.x27;

+    c.x28 =3D = ctxt.x28;

+    c.x29 =3D = ctxt.x29;

+    c.x30 =3D = ctxt.x30;

+    c.pc64 =3D = ctxt.pc64;

+    c.cpsr =3D = ctxt.cpsr;

+    c.spsr_el1 =3D ctxt.spsr_el1; /* = spsr_svc */

+

+   #ifdef CONFIG_ARM_32

+    c.spsr_fiq =3D = ctxt.spsr_fiq;

+    c.spsr_irq =3D = ctxt.spsr_irq;

+    c.spsr_und =3D = ctxt.spsr_und;

+    c.spsr_abt =3D = ctxt.spsr_abt;

+   #endif

+   #ifdef = CONFIG_ARM_64

+    c.sp_el0 =3D = ctxt.sp_el0;

+    c.sp_el1 =3D = ctxt.sp_el1;

+    c.elr_el1 =3D = ctxt.elr_el1;

+   #endif

+

+    /* set guest = core registers */

+    vcpu_regs_user_to_hyp(v, = &c);

+

+    if ( sizeof(v->arch.vfp) > sizeof = (ctxt.vfp) )

+    {

+        = dprintk(XENLOG_G_ERR, "hvm_hw_cpu: increase VFP dumping = space\n");

+        return = -EINVAL;

+    }

+

+    = memcpy(&v->arch.vfp, &ctxt,  = sizeof(v->arch.vfp));

+

+    v->is_initialised =3D = 1;

+    v->pause_flags =3D = ctxt.pause_flags;

+

+    return 0;

+}

+

+HVM_REGISTER_SAVE_RESTORE(VCPU, = cpu_save, cpu_load, 1, HVMSR_PER_VCPU);

+

+/*

+ * Local = variables:

+ * mode: C

+ * c-file-style: "BSD"

+ * c-basic-offset: = 4

+ * = tab-width: 4

+ * indent-tabs-mode: nil

+ * End:

+ */

diff --git a/xen/arch/arm/save.c = b/xen/arch/arm/save.c

new file mode 100644

index = 0000000..c923910

--- /dev/null

+++ = b/xen/arch/arm/save.c

@@ -0,0 +1,66 @@

+/*

+ * hvm/save.c: Save and restore = HVM guest's emulated hardware state for ARM.

+ *

+ * Copyright (c) 2013, Samsung = Electronics.

+ *

+ * This program is free software; you can redistribute it = and/or modify it

+ * under the terms and conditions of the GNU General = Public License,

+ * version 2, as published by the Free Software = Foundation.

+ *

+ * This program is distributed in the hope it will be = useful, but WITHOUT

+ * ANY WARRANTY; without even the implied warranty of = MERCHANTABILITY or

+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU = General Public License for

+ * more = details.

+ = *

+ * You = should have received a copy of the GNU General Public License along = with

+ * = this program; if not, write to the Free Software Foundation, Inc., 59 = Temple

+ * = Place - Suite 330, Boston, MA 02111-1307 USA.

+ */

+

+#include = <asm/hvm/support.h>

+#include = <public/hvm/save.h>

+

+void arch_hvm_save(struct domain = *d, struct hvm_save_header *hdr)

+{

+    hdr->cpuid = =3D READ_SYSREG32(MIDR_EL1);

+}

+

+int arch_hvm_load(struct domain = *d, struct hvm_save_header *hdr)

+{

+    uint32_t = cpuid;

+

+    if ( hdr->magic !=3D HVM_FILE_MAGIC = )

+    {

+        = printk(XENLOG_G_ERR "HVM%d restore: bad magic number = %#"PRIx32"\n",

+          = ;     d->domain_id, = hdr->magic);

+        return = -1;

+    }

+

+    if ( = hdr->version !=3D HVM_FILE_VERSION )

+    = {

+        = printk(XENLOG_G_ERR "HVM%d restore: unsupported version = %u\n",

+          = ;     d->domain_id, = hdr->version);

+        return = -1;

+    }

+

+    cpuid =3D = READ_SYSREG32(MIDR_EL1);

+    if ( hdr->cpuid !=3D cpuid = )

+    {

+        = printk(XENLOG_G_INFO "HVM%d restore: VM saved on one CPU = "

+          = ;     "(%#"PRIx32") and restored on = another (%#"PRIx32").\n",

+          = ;     d->domain_id, hdr->cpuid, = cpuid);

+        return = -1;

+    }

+

+    return = 0;

+}

+

+/*

+ * Local variables:

+ * mode: C

+ * c-file-style: = "BSD"

+ * c-basic-offset: 4

+ * tab-width: = 4

+ * = indent-tabs-mode: nil

+ * End:

+ */

diff --git a/xen/common/Makefile = b/xen/common/Makefile

index 686f7a1..f943302 100644

--- = a/xen/common/Makefile

+++ b/xen/common/Makefile

@@ -63,6 +63,8 @@ = subdir-$(CONFIG_COMPAT) +=3D compat

 

subdir-$(x86_64) +=3D = hvm

 

+subdir-$(CONFIG_ARM) +=3D hvm

+

subdir-$(coverage) +=3D = gcov

 

subdir-y +=3D libelf

diff --git = a/xen/include/asm-arm/hvm/support.h = b/xen/include/asm-arm/hvm/support.h

new file mode = 100644

index 0000000..8311f2f

--- = /dev/null

+++ = b/xen/include/asm-arm/hvm/support.h

@@ -0,0 +1,29 = @@

+/*

+ * support.h: HVM support routines used by ARMv7 = VE.

+ = *

+ * = Copyright (c) 2012, Citrix Systems

+ *

+ * This program is free software; = you can redistribute it and/or modify it

+ * under the terms and conditions = of the GNU General Public License,

+ * version 2, as published by the = Free Software Foundation.

+ *

+ * This program is distributed in = the hope it will be useful, but WITHOUT

+ * ANY WARRANTY; without even the = implied warranty of MERCHANTABILITY or

+ * FITNESS FOR A PARTICULAR = PURPOSE.  See the GNU General Public License = for

+ * = more details.

+ *

+ * You should have received a copy of the GNU General = Public License along with

+ * this program; if not, write to = the Free Software Foundation, Inc., 59 Temple

+ * Place - Suite 330, Boston, MA = 02111-1307 USA.

+ */

+

+#ifndef __ASM_ARM_HVM_SUPPORT_H__

+#define = __ASM_ARM_HVM_SUPPORT_H__

+

+#include = <xen/types.h>

+#include = <public/hvm/ioreq.h>

+#include = <xen/sched.h>

+#include <xen/hvm/save.h>

+#include = <asm/processor.h>

+

+#endif /* __ASM_ARM_HVM_SUPPORT_H__ = */

diff = --git a/xen/include/public/arch-arm/hvm/save.h = b/xen/include/public/arch-arm/hvm/save.h

index 75b8e65..1f71c41 = 100644

--- = a/xen/include/public/arch-arm/hvm/save.h

+++ = b/xen/include/public/arch-arm/hvm/save.h

@@ -26,6 +26,136 = @@

#ifndef = __XEN_PUBLIC_HVM_SAVE_ARM_H__

#define = __XEN_PUBLIC_HVM_SAVE_ARM_H__

 

+#define HVM_FILE_MAGIC   = 0x92385520

+#define HVM_FILE_VERSION = 0x00000001

+

+

+struct hvm_save_header

+{

+    uint32_t = magic;     =         /* Must be = HVM_FILE_MAGIC */

+    uint32_t = version;           /* = File format version */

+    uint64_t = changeset;         /* Version of = Xen that saved this file */

+    uint32_t = cpuid;           &= nbsp; /* MIDR_EL1 on the saving machine */

+};

+

+DECLARE_HVM_SAVE_TYPE(HEADER, 1, = struct hvm_save_header);

+

+struct vgic_rank

+{

+    uint32_t = ienable, iactive, ipend, pendsgi;

+    uint32_t = icfg[2];

+    uint32_t = ipriority[8];

+    uint32_t = itargets[8];

+};

+

+struct hvm_hw_gic

+{

+    uint32_t = gic_hcr;

+    uint32_t = gic_vmcr;

+    uint32_t = gic_apr;

+    uint32_t = gic_lr[64];

+    uint64_t = event_mask;

+    uint64_t = lr_mask;

+    struct vgic_rank = ppi_state;

+};

+

+DECLARE_HVM_SAVE_TYPE(GIC, 2, struct = hvm_hw_gic);

+

+#define TIMER_TYPE_VIRT 0

+#define TIMER_TYPE_PHYS = 1

+

+struct hvm_hw_timer

+{

+    uint64_t = vtb_offset;

+    uint32_t ctl;

+    uint64_t = cval;

+    uint32_t type;

+};

+

+DECLARE_HVM_SAVE_TYPE(A15_TIMER, = 3, struct hvm_hw_timer);

+

+

+struct hvm_hw_cpu

+{

+    uint64_t = vfp[34]; /* Vector floating pointer */

+    /* VFP v3 state = is 34x64 bit, VFP v4 is not yet supported */

+

+    /* Guest core = registers */

+    uint64_t x0;     /* = r0_usr */

+    uint64_t x1;     /* = r1_usr */

+    uint64_t x2;     /* = r2_usr */

+    uint64_t x3;     /* = r3_usr */

+    uint64_t x4;     /* = r4_usr */

+    uint64_t x5;     /* = r5_usr */

+    uint64_t x6;     /* = r6_usr */

+    uint64_t x7;     /* = r7_usr */

+    uint64_t x8;     /* = r8_usr */

+    uint64_t x9;     /* = r9_usr */

+    uint64_t x10;    /* = r10_usr */

+    uint64_t x11;    /* = r11_usr */

+    uint64_t x12;    /* = r12_usr */

+    uint64_t x13;    /* = sp_usr */

+    uint64_t x14;    /* = lr_usr; */

+    uint64_t x15;    /* = __unused_sp_hyp */

+    uint64_t x16;    /* = lr_irq */

+    uint64_t x17;    /* = sp_irq */

+    uint64_t x18;    /* = lr_svc */

+    uint64_t x19;    /* = sp_svc */

+    uint64_t x20;    /* = lr_abt */

+    uint64_t x21;    /* = sp_abt */

+    uint64_t x22;    /* = lr_und */

+    uint64_t x23;    /* = sp_und */

+    uint64_t x24;    /* = r8_fiq */

+    uint64_t x25;    /* = r9_fiq */

+    uint64_t x26;    /* = r10_fiq */

+    uint64_t x27;    /* = r11_fiq */

+    uint64_t x28;    /* = r12_fiq */

+    uint64_t x29;    /* = fp,sp_fiq */

+    uint64_t x30;    /* = lr_fiq */

+    uint64_t pc64;   /* ELR_EL2 = */

+    uint32_t cpsr;   /* SPSR_EL2 = */

+    uint32_t spsr_el1;  /*spsr_svc = */

+    /* AArch32 guests only = */

+    uint32_t spsr_fiq, spsr_irq, spsr_und, = spsr_abt;

+    /* AArch64 guests only = */

+    uint64_t = sp_el0;

+    uint64_t sp_el1, = elr_el1;

+

+    uint32_t sctlr, = ttbcr;

+    uint64_t ttbr0, = ttbr1;

+

+    uint32_t ifar, = dfar;

+    uint32_t ifsr, = dfsr;

+    uint32_t dacr;

+    uint64_t = par;

+

+    uint64_t mair0, = mair1;

+    uint64_t = tpidr_el0;

+    uint64_t = tpidr_el1;

+    uint64_t = tpidrro_el0;

+    uint64_t vbar;

+

+    /* Control = Registers */

+    uint32_t actlr;

+    uint32_t = cpacr;

+    uint32_t afsr0, = afsr1;

+    uint32_t = contextidr;

+    uint32_t teecr, teehbr; /* ThumbEE, = 32-bit guests only */

+    uint32_t joscr, = jmcr;

+    /* CP 15 */

+    uint32_t = csselr;

+

+    unsigned long = pause_flags;

+

+};

+

+DECLARE_HVM_SAVE_TYPE(VCPU, 4, struct = hvm_hw_cpu);

+

+/*

+ * Largest type-code in use

+ */

+#define HVM_SAVE_CODE_MAX = 4

+

#endif

 

/*

--

1.8.1.2

------=_NextPart_000_00A7_01CEDAED.FDF3A2F0-- --===============5899859385121255319== Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Disposition: inline _______________________________________________ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel --===============5899859385121255319==--