[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-ia64-devel] [PATCH 16/23] [RFC] vti domain save/restore: implement arch_get/set_info_guest() more



# HG changeset patch
# User yamahata@xxxxxxxxxxxxx
# Date 1192100096 -32400
# Node ID a04cedb034ea936890485d6989d01b5712151748
# Parent  905a46fbe0d8f1c51e4eec565434b6e0069454ad
implement arch_get_info_guest(), arch_set_info_guest() more.
PATCHNAME: implement_arch_get_set_info_guest

Signed-off-by: Isaku Yamahata <yamahata@xxxxxxxxxxxxx>

diff -r 905a46fbe0d8 -r a04cedb034ea xen/arch/ia64/vmx/Makefile
--- a/xen/arch/ia64/vmx/Makefile        Wed Oct 10 19:45:29 2007 +0900
+++ b/xen/arch/ia64/vmx/Makefile        Thu Oct 11 19:54:56 2007 +0900
@@ -19,3 +19,4 @@ obj-y += vtlb.o
 obj-y += vtlb.o
 obj-y += optvfault.o
 obj-y += vacpi.o
+obj-y += vmx_vcpu_save.o
diff -r 905a46fbe0d8 -r a04cedb034ea xen/arch/ia64/vmx/vmx_vcpu_save.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/arch/ia64/vmx/vmx_vcpu_save.c Thu Oct 11 19:54:56 2007 +0900
@@ -0,0 +1,203 @@
+/******************************************************************************
+ * vmx_vcpu_save.c
+ *
+ * Copyright (c) 2007 Isaku Yamahata <yamahata at valinux co jp>
+ *                    VA Linux Systems Japan K.K.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that 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/vmx_vcpu.h>
+#include <asm/vmx_vcpu_save.h>
+
+void
+vmx_arch_get_info_guest(struct vcpu *v, vcpu_guest_context_u c)
+{
+    vpd_t *vpd = (void *)v->arch.privregs;
+    struct mapped_regs *vpd_low = &vpd->vpd_low;
+    unsigned long nats;
+    unsigned long bnats;
+
+       union vcpu_ar_regs *ar = &c.nat->regs.ar;
+       union vcpu_cr_regs *cr = &c.nat->regs.cr;
+    int i;
+
+    // banked registers
+    if (vpd_low->vpsr & IA64_PSR_BN) {
+        for (i = 0; i < 16; i++) {
+            //c.nat->regs.r[i + 16] = vpd_low->vgr[i];
+            c.nat->regs.bank[i] = vpd_low->vbgr[i];
+        }
+        nats = vpd_low->vnat;
+        bnats = vpd_low->vbnat;
+    } else {
+        for (i = 0; i < 16; i++) {
+            c.nat->regs.bank[i] = vpd_low->vgr[i];
+            //c.nat->regs.r[i + 16] = vpd_low->vbgr[i];
+        }
+        bnats = vpd_low->vnat;
+        nats = vpd_low->vbnat;
+    }
+    // c.nat->regs.nats[0:15] is already set. we shouldn't overwrite.
+    c.nat->regs.nats =
+        (c.nat->regs.nats & MASK(0, 16)) | (nats & MASK(16, 16));
+    c.nat->regs.bnats = bnats & MASK(16, 16);
+
+    //c.nat->regs.psr = vpd_low->vpsr;
+    //c.nat->regs.pr = vpd_low->vpr;
+
+    // ar
+    ar->kr[0] = v->arch.arch_vmx.vkr[0];
+    ar->kr[1] = v->arch.arch_vmx.vkr[1];
+    ar->kr[2] = v->arch.arch_vmx.vkr[2];
+    ar->kr[3] = v->arch.arch_vmx.vkr[3];
+    ar->kr[4] = v->arch.arch_vmx.vkr[4];
+    ar->kr[5] = v->arch.arch_vmx.vkr[5];
+    ar->kr[6] = v->arch.arch_vmx.vkr[6];
+    ar->kr[7] = v->arch.arch_vmx.vkr[7];
+#ifdef CONFIG_IA32_SUPPORT
+    // csd and ssd are done by arch_get_info_guest()
+    ar->fcr = v->arch._thread.fcr;
+    ar->eflag = v->arch._thread.eflag;
+    ar->cflg = v->arch._thread.cflg;
+    ar->fsr = v->arch._thread.fsr;
+    ar->fir = v->arch._thread.fir;
+    ar->fdr = v->arch._thread.fdr;
+#endif
+    //ar->itc = vpd_low->itc;//see vtime
+
+    // cr
+    //cr->dcr = vpd_low->dcr;
+    //cr->itm = vpd_low->itm;
+    //cr->iva = vpd_low->iva;
+    //cr->pta = vpd_low->pta;
+    //cr->ipsr = vpd_low->ipsr;
+    //cr->isr = vpd_low->isr;
+    //cr->iip = vpd_low->iip;
+    //cr->ifa = vpd_low->ifa;
+    //cr->itir = vpd_low->itir;
+    cr->iipa = vpd_low->iipa;
+    cr->ifs = vpd_low->ifs;
+    //cr->iim = vpd_low->iim;
+    //cr->iha = vpd_low->iha;
+    cr->lid = vpd_low->lid;
+    cr->ivr = vpd_low->ivr;
+    //cr->tpr = vpd_low->tpr;
+    cr->eoi = vpd_low->eoi;
+    //cr->irr[0] = vpd_low->irr[0];
+    //cr->irr[1] = vpd_low->irr[1];
+    //cr->irr[2] = vpd_low->irr[2];
+    //cr->irr[3] = vpd_low->irr[3];
+    //cr->itv = vpd_low->itv;
+    //cr->pmv = vpd_low->pmv;
+    //cr->cmcv = vpd_low->cmcv;
+    cr->lrr0 = vpd_low->lrr0;
+    cr->lrr1 = vpd_low->lrr1;
+}
+
+int
+vmx_arch_set_info_guest(struct vcpu *v, vcpu_guest_context_u c)
+{
+    vpd_t *vpd = (void *)v->arch.privregs;
+    struct mapped_regs *vpd_low = &vpd->vpd_low;
+    unsigned long vnat;
+    unsigned long vbnat;
+
+       union vcpu_ar_regs *ar = &c.nat->regs.ar;
+       union vcpu_cr_regs *cr = &c.nat->regs.cr;
+    int i;
+
+    // banked registers
+    if (c.nat->regs.psr & IA64_PSR_BN) {
+        for (i = 0; i < 16; i++) {
+            //vpd_low->vgr[i] = c.nat->regs.r[i + 16];
+            vpd_low->vbgr[i] = c.nat->regs.bank[i];
+        }
+        vnat = c.nat->regs.nats;
+        vbnat = c.nat->regs.bnats;
+    } else {
+        for (i = 0; i < 16; i++) {
+            vpd_low->vgr[i] = c.nat->regs.bank[i];
+            //vpd_low->vbgr[i] = c.nat->regs.r[i + 16];
+        }
+        vbnat = c.nat->regs.nats;
+        vnat = c.nat->regs.bnats;
+    }
+    vpd_low->vnat = vnat & MASK(16, 16);
+    vpd_low->vbnat = vbnat & MASK(16, 16);
+    //vpd_low->vpsr = c.nat->regs.psr;
+    //vpd_low->vpr = c.nat->regs.pr;
+
+    // ar
+    v->arch.arch_vmx.vkr[0] = ar->kr[0];
+    v->arch.arch_vmx.vkr[1] = ar->kr[1];
+    v->arch.arch_vmx.vkr[2] = ar->kr[2];
+    v->arch.arch_vmx.vkr[3] = ar->kr[3];
+    v->arch.arch_vmx.vkr[4] = ar->kr[4];
+    v->arch.arch_vmx.vkr[5] = ar->kr[5];
+    v->arch.arch_vmx.vkr[6] = ar->kr[6];
+    v->arch.arch_vmx.vkr[7] = ar->kr[7];
+#ifdef CONFIG_IA32_SUPPORT
+    v->arch._thread.fcr = ar->fcr;
+    v->arch._thread.eflag = ar->eflag;
+    v->arch._thread.cflg = ar->cflg;
+    v->arch._thread.fsr = ar->fsr;
+    v->arch._thread.fir = ar->fir;
+    v->arch._thread.fdr = ar->fdr;
+#endif
+    //vpd_low->itc = ar->itc;// see vtime.
+
+    // cr
+    vpd_low->dcr = cr->dcr;
+    vpd_low->itm = cr->itm;
+    //vpd_low->iva = cr->iva;
+    vpd_low->pta = cr->pta;
+    vpd_low->ipsr = cr->ipsr;
+    vpd_low->isr = cr->isr;
+    vpd_low->iip = cr->iip;
+    vpd_low->ifa = cr->ifa;
+    vpd_low->itir = cr->itir;
+    vpd_low->iipa = cr->iipa;
+    vpd_low->ifs = cr->ifs;
+    vpd_low->iim = cr->iim;
+    vpd_low->iha = cr->iha;
+    vpd_low->lid = cr->lid;
+    vpd_low->ivr = cr->ivr; //XXX vlsapic
+    vpd_low->tpr = cr->tpr;
+    vpd_low->eoi = cr->eoi;
+    vpd_low->irr[0] = cr->irr[0];
+    vpd_low->irr[1] = cr->irr[1];
+    vpd_low->irr[2] = cr->irr[2];
+    vpd_low->irr[3] = cr->irr[3];
+    vpd_low->itv = cr->itv;
+    vpd_low->pmv = cr->pmv;
+    vpd_low->cmcv = cr->cmcv;
+    vpd_low->lrr0 = cr->lrr0;
+    vpd_low->lrr1 = cr->lrr1;
+
+    v->arch.irq_new_condition = 1;
+    return 0;
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff -r 905a46fbe0d8 -r a04cedb034ea xen/arch/ia64/xen/domain.c
--- a/xen/arch/ia64/xen/domain.c        Wed Oct 10 19:45:29 2007 +0900
+++ b/xen/arch/ia64/xen/domain.c        Thu Oct 11 19:54:56 2007 +0900
@@ -41,6 +41,7 @@
 #include <asm/vmx_vcpu.h>
 #include <asm/vmx_vpd.h>
 #include <asm/vmx_phy_mode.h>
+#include <asm/vmx_vcpu_save.h>
 #include <asm/vhpt.h>
 #include <asm/vcpu.h>
 #include <asm/tlbflush.h>
@@ -54,6 +55,7 @@
 #include <public/vcpu.h>
 #include <linux/cpu.h>
 #include <linux/notifier.h>
+#include <asm/debugger.h>
 
 /* dom0_size: default memory allocation for dom0 (~4GB) */
 static unsigned long __initdata dom0_size = 4096UL*1024UL*1024UL;
@@ -516,6 +518,12 @@ void vcpu_destroy(struct vcpu *v)
                relinquish_vcpu_resources(v);
 }
 
+static unsigned long*
+vcpu_to_rbs_bottom(struct vcpu *v)
+{
+       return (unsigned long*)((char *)v + IA64_RBS_OFFSET);
+}
+
 static void init_switch_stack(struct vcpu *v)
 {
        struct pt_regs *regs = vcpu_regs (v);
@@ -523,7 +531,7 @@ static void init_switch_stack(struct vcp
        extern void ia64_ret_from_clone;
 
        memset(sw, 0, sizeof(struct switch_stack) + sizeof(struct pt_regs));
-       sw->ar_bspstore = (unsigned long)v + IA64_RBS_OFFSET;
+       sw->ar_bspstore = (unsigned long)vcpu_to_rbs_bottom(v);
        sw->b0 = (unsigned long) &ia64_ret_from_clone;
        sw->ar_fpsr = FPSR_DEFAULT;
        v->arch._thread.ksp = (unsigned long) sw - 16;
@@ -628,19 +636,100 @@ int arch_vcpu_reset(struct vcpu *v)
        return 0;
 }
 
+static unsigned long num_phys_stacked;
+static int __init
+init_num_phys_stacked(void)
+{
+       switch (ia64_pal_rse_info(&num_phys_stacked, NULL)) {
+       case 0L:
+               printk("the number of physical stacked general registers"
+                      "(RSE.N_STACKED_PHYS) = %ld\n", num_phys_stacked);
+               return 0;
+       case -2L:
+       case -3L:
+       default:
+               break;
+       }
+       printk("WARNING: PAL_RSE_INFO call failed. "
+              "domain save/restore may NOT work!\n");
+       return -EINVAL;
+}
+__initcall(init_num_phys_stacked);
+
 #define COPY_FPREG(dst, src) memcpy(dst, src, sizeof(struct ia64_fpreg))
+
+#define AR_PFS_PEC_SHIFT       51
+#define AR_PFS_REC_SIZE                6
+#define AR_PFS_PEC_MASK                (((1UL << 6) - 1) << 51)
+
+/*
+ * See init_swtich_stack() and ptrace.h
+ */
+static struct switch_stack*
+vcpu_to_switch_stack(struct vcpu* v)
+{
+       return (struct switch_stack *)(v->arch._thread.ksp + 16);
+}
+
+static int
+vcpu_has_not_run(struct vcpu* v)
+{
+       extern void ia64_ret_from_clone;
+       struct switch_stack *sw = vcpu_to_switch_stack(v);
+
+       return (sw == (struct switch_stack *)(vcpu_regs(v)) - 1) &&
+               (sw->b0 == (unsigned long)&ia64_ret_from_clone);
+}
+
+static void
+nats_update(unsigned int* nats, unsigned int reg, char nat)
+{
+       BUG_ON(reg > 31);
+
+       if (nat)
+               *nats |= (1UL << reg);
+       else
+               *nats &= ~(1UL << reg);
+}
 
 void arch_get_info_guest(struct vcpu *v, vcpu_guest_context_u c)
 {
        int i;
        struct vcpu_tr_regs *tr = &c.nat->regs.tr;
        struct cpu_user_regs *uregs = vcpu_regs(v);
+       struct switch_stack *sw = vcpu_to_switch_stack(v);
+       struct unw_frame_info info;
        int is_hvm = VMX_DOMAIN(v);
        unsigned int rbs_size;
-
+       unsigned long * const rbs_bottom = vcpu_to_rbs_bottom(v);
+       unsigned long *rbs_top;
+       unsigned long *rbs_rnat_addr;
+       unsigned int top_slot;
+       unsigned int num_regs;
+
+       memset(c.nat, 0, sizeof(*c.nat));
        c.nat->regs.b[6] = uregs->b6;
        c.nat->regs.b[7] = uregs->b7;
 
+       memset(&info, 0, sizeof(info));
+       unw_init_from_blocked_task(&info, v);
+       if (vcpu_has_not_run(v)) {
+               c.nat->regs.ar.lc = sw->ar_lc;
+               c.nat->regs.ar.ec =
+                       (sw->ar_pfs & AR_PFS_PEC_MASK) >> AR_PFS_PEC_SHIFT;
+       } else if (unw_unwind_to_user(&info) < 0) {
+               /* warn: should panic? */
+               gdprintk(XENLOG_ERR, "vcpu=%d unw_unwind_to_user() failed.\n",
+                        v->vcpu_id);
+               show_stack(v, NULL);
+
+               /* can't return error */
+               c.nat->regs.ar.lc = 0;
+               c.nat->regs.ar.ec = 0;
+       } else {
+               unw_get_ar(&info, UNW_AR_LC, &c.nat->regs.ar.lc);
+               unw_get_ar(&info, UNW_AR_EC, &c.nat->regs.ar.ec);
+       }
        c.nat->regs.ar.csd = uregs->ar_csd;
        c.nat->regs.ar.ssd = uregs->ar_ssd;
 
@@ -666,7 +755,11 @@ void arch_get_info_guest(struct vcpu *v,
        c.nat->regs.pr = uregs->pr;
        c.nat->regs.b[0] = uregs->b0;
        rbs_size = uregs->loadrs >> 16;
-       c.nat->regs.ar.bsp = uregs->ar_bspstore + rbs_size;
+       num_regs = ia64_rse_num_regs(rbs_bottom,
+                       (unsigned long*)((char*)rbs_bottom + rbs_size));
+       c.nat->regs.ar.bsp = (unsigned long)ia64_rse_skip_regs(
+               (unsigned long*)c.nat->regs.ar.bspstore, num_regs);
+       BUG_ON(num_regs > num_phys_stacked);
 
        c.nat->regs.r[1] = uregs->r1;
        c.nat->regs.r[12] = uregs->r12;
@@ -696,6 +789,11 @@ void arch_get_info_guest(struct vcpu *v,
 
        c.nat->regs.ar.ccv = uregs->ar_ccv;
 
+       COPY_FPREG(&c.nat->regs.f[2], &sw->f2);
+       COPY_FPREG(&c.nat->regs.f[3], &sw->f3);
+       COPY_FPREG(&c.nat->regs.f[4], &sw->f4);
+       COPY_FPREG(&c.nat->regs.f[5], &sw->f5);
+
        COPY_FPREG(&c.nat->regs.f[6], &uregs->f6);
        COPY_FPREG(&c.nat->regs.f[7], &uregs->f7);
        COPY_FPREG(&c.nat->regs.f[8], &uregs->f8);
@@ -703,24 +801,155 @@ void arch_get_info_guest(struct vcpu *v,
        COPY_FPREG(&c.nat->regs.f[10], &uregs->f10);
        COPY_FPREG(&c.nat->regs.f[11], &uregs->f11);
 
-       c.nat->regs.r[4] = uregs->r4;
-       c.nat->regs.r[5] = uregs->r5;
-       c.nat->regs.r[6] = uregs->r6;
-       c.nat->regs.r[7] = uregs->r7;
-
-       /* FIXME: to be reordered.  */
-       c.nat->regs.nats = uregs->eml_unat;
+       COPY_FPREG(&c.nat->regs.f[12], &sw->f12);
+       COPY_FPREG(&c.nat->regs.f[13], &sw->f13);
+       COPY_FPREG(&c.nat->regs.f[14], &sw->f14);
+       COPY_FPREG(&c.nat->regs.f[15], &sw->f15);
+       COPY_FPREG(&c.nat->regs.f[16], &sw->f16);
+       COPY_FPREG(&c.nat->regs.f[17], &sw->f17);
+       COPY_FPREG(&c.nat->regs.f[18], &sw->f18);
+       COPY_FPREG(&c.nat->regs.f[19], &sw->f19);
+       COPY_FPREG(&c.nat->regs.f[20], &sw->f20);
+       COPY_FPREG(&c.nat->regs.f[21], &sw->f21);
+       COPY_FPREG(&c.nat->regs.f[22], &sw->f22);
+       COPY_FPREG(&c.nat->regs.f[23], &sw->f23);
+       COPY_FPREG(&c.nat->regs.f[24], &sw->f24);
+       COPY_FPREG(&c.nat->regs.f[25], &sw->f25);
+       COPY_FPREG(&c.nat->regs.f[26], &sw->f26);
+       COPY_FPREG(&c.nat->regs.f[27], &sw->f27);
+       COPY_FPREG(&c.nat->regs.f[28], &sw->f28);
+       COPY_FPREG(&c.nat->regs.f[29], &sw->f29);
+       COPY_FPREG(&c.nat->regs.f[30], &sw->f30);
+       COPY_FPREG(&c.nat->regs.f[31], &sw->f31);
+
+       for (i = 0; i < 96; i++)
+               COPY_FPREG(&c.nat->regs.f[i + 32], &v->arch._thread.fph[i]);
+
+#define NATS_UPDATE(reg)                                               \
+       nats_update(&c.nat->regs.nats, (reg),                           \
+                   !!(uregs->eml_unat &                                \
+                      (1UL << ia64_unat_pos(&uregs->r ## reg))))
+
+       // corresponding bit in ar.unat is determined by
+       // (&uregs->rN){8:3}.
+       // r8: the lowest gr member of struct cpu_user_regs.
+       // r7: the highest gr member of struct cpu_user_regs.
+       BUILD_BUG_ON(offsetof(struct cpu_user_regs, r7) -
+                    offsetof(struct cpu_user_regs, r8) >
+                    64 * sizeof(unsigned long));
+
+       NATS_UPDATE(1);
+       NATS_UPDATE(2);
+       NATS_UPDATE(3);
+
+       NATS_UPDATE(8);
+       NATS_UPDATE(9);
+       NATS_UPDATE(10);
+       NATS_UPDATE(11);
+       NATS_UPDATE(12);
+       NATS_UPDATE(13);
+       NATS_UPDATE(14);
+       NATS_UPDATE(15);
+       NATS_UPDATE(16);
+       NATS_UPDATE(17);
+       NATS_UPDATE(18);
+       NATS_UPDATE(19);
+       NATS_UPDATE(20);
+       NATS_UPDATE(21);
+       NATS_UPDATE(22);
+       NATS_UPDATE(23);
+       NATS_UPDATE(24);
+       NATS_UPDATE(25);
+       NATS_UPDATE(26);
+       NATS_UPDATE(27);
+       NATS_UPDATE(28);
+       NATS_UPDATE(29);
+       NATS_UPDATE(30);
+       NATS_UPDATE(31);
+       
+       if (!is_hvm) {
+               c.nat->regs.r[4] = uregs->r4;
+               c.nat->regs.r[5] = uregs->r5;
+               c.nat->regs.r[6] = uregs->r6;
+               c.nat->regs.r[7] = uregs->r7;
+
+               NATS_UPDATE(4);
+               NATS_UPDATE(5);
+               NATS_UPDATE(6);
+               NATS_UPDATE(7);
+#undef NATS_UPDATE
+       } else {
+               /*
+                * for VTi domain, r[4-7] are saved sometimes both in
+                * uregs->r[4-7] and memory stack or only in memory stack.
+                * So it is ok to get them from memory stack.
+                */
+               c.nat->regs.nats = uregs->eml_unat;
+
+               if (vcpu_has_not_run(v)) {
+                       c.nat->regs.r[4] = sw->r4;
+                       c.nat->regs.r[5] = sw->r5;
+                       c.nat->regs.r[6] = sw->r6;
+                       c.nat->regs.r[7] = sw->r7;
+
+                       nats_update(&c.nat->regs.nats, 4,
+                                   !!(sw->ar_unat &
+                                      (1UL << ia64_unat_pos(&sw->r4))));
+                       nats_update(&c.nat->regs.nats, 5,
+                                   !!(sw->ar_unat &
+                                      (1UL << ia64_unat_pos(&sw->r5))));
+                       nats_update(&c.nat->regs.nats, 6,
+                                   !!(sw->ar_unat &
+                                      (1UL << ia64_unat_pos(&sw->r6))));
+                       nats_update(&c.nat->regs.nats, 7,
+                                   !!(sw->ar_unat &
+                                      (1UL << ia64_unat_pos(&sw->r7))));
+               } else {
+                       char nat;
+
+                       unw_get_gr(&info, 4, &c.nat->regs.r[4], &nat);
+                       nats_update(&c.nat->regs.nats, 4, nat);
+                       unw_get_gr(&info, 5, &c.nat->regs.r[5], &nat);
+                       nats_update(&c.nat->regs.nats, 5, nat);
+                       unw_get_gr(&info, 6, &c.nat->regs.r[6], &nat);
+                       nats_update(&c.nat->regs.nats, 6, nat);
+                       unw_get_gr(&info, 7, &c.nat->regs.r[7], &nat);
+                       nats_update(&c.nat->regs.nats, 7, nat);
+               }
+       }
 
        c.nat->regs.rbs_voff = (IA64_RBS_OFFSET / 8) % 64;
-       if (rbs_size < sizeof (c.nat->regs.rbs))
-               memcpy(c.nat->regs.rbs, (char *)v + IA64_RBS_OFFSET, rbs_size);
+       if (unlikely(rbs_size > sizeof(c.nat->regs.rbs)))
+               gdprintk(XENLOG_INFO,
+                        "rbs_size is too large 0x%x > 0x%lx\n",
+                        rbs_size, sizeof(c.nat->regs.rbs));
+       else
+               memcpy(c.nat->regs.rbs, rbs_bottom, rbs_size);
+
+       rbs_top = (unsigned long*)((char *)rbs_bottom + rbs_size) - 1;
+       rbs_rnat_addr = ia64_rse_rnat_addr(rbs_top);
+       if ((unsigned long)rbs_rnat_addr >= sw->ar_bspstore)
+               rbs_rnat_addr = &sw->ar_rnat;
+
+       top_slot = ia64_rse_slot_num(rbs_top);
+
+       c.nat->regs.rbs_rnat = (*rbs_rnat_addr) & ((1UL << top_slot) - 1);
+       if (ia64_rse_rnat_addr(rbs_bottom) == ia64_rse_rnat_addr(rbs_top)) {
+               unsigned int bottom_slot = ia64_rse_slot_num(rbs_bottom);
+               c.nat->regs.rbs_rnat &= ~((1UL << bottom_slot) - 1);
+       }
 
        c.nat->privregs_pfn = get_gpfn_from_mfn
                (virt_to_maddr(v->arch.privregs) >> PAGE_SHIFT);
 
        for (i = 0; i < IA64_NUM_DBG_REGS; i++) {
-               vcpu_get_dbr(v, i, &c.nat->regs.dbr[i]);
-               vcpu_get_ibr(v, i, &c.nat->regs.ibr[i]);
+               if (VMX_DOMAIN(v)) {
+                       vmx_vcpu_get_dbr(v, i, &c.nat->regs.dbr[i]);
+                       vmx_vcpu_get_ibr(v, i, &c.nat->regs.ibr[i]);
+               } else {
+                       vcpu_get_dbr(v, i, &c.nat->regs.dbr[i]);
+                       vcpu_get_ibr(v, i, &c.nat->regs.ibr[i]);
+               }
        }
 
        for (i = 0; i < 8; i++)
@@ -762,7 +991,12 @@ void arch_get_info_guest(struct vcpu *v,
        vcpu_get_ifa(v, &c.nat->regs.cr.ifa);
        vcpu_get_itir(v, &c.nat->regs.cr.itir);
        vcpu_get_iha(v, &c.nat->regs.cr.iha);
-       vcpu_get_ivr(v, &c.nat->regs.cr.ivr);
+
+       //XXX change irr[] and arch.insvc[]
+       if (v->domain->arch.is_vti)
+               /* c.nat->regs.cr.ivr = vmx_vcpu_get_ivr(v)*/;//XXXnot SMP-safe
+       else
+               vcpu_get_ivr (v, &c.nat->regs.cr.ivr);
        vcpu_get_iim(v, &c.nat->regs.cr.iim);
 
        vcpu_get_tpr(v, &c.nat->regs.cr.tpr);
@@ -770,18 +1004,172 @@ void arch_get_info_guest(struct vcpu *v,
        vcpu_get_irr1(v, &c.nat->regs.cr.irr[1]);
        vcpu_get_irr2(v, &c.nat->regs.cr.irr[2]);
        vcpu_get_irr3(v, &c.nat->regs.cr.irr[3]);
-       vcpu_get_itv(v, &c.nat->regs.cr.itv);
+       vcpu_get_itv(v, &c.nat->regs.cr.itv);//XXX vlsapic
        vcpu_get_pmv(v, &c.nat->regs.cr.pmv);
        vcpu_get_cmcv(v, &c.nat->regs.cr.cmcv);
+
+       if (is_hvm)
+               vmx_arch_get_info_guest(v, c);
+}
+
+#if 0
+// for debug
+static void
+__rbs_print(const char* func, int line, const char* name,
+           const unsigned long* rbs, unsigned int rbs_size)
+{
+       unsigned int i;
+       printk("%s:%d %s rbs %p\n", func, line, name, rbs);
+       printk("   rbs_size 0x%016x no 0x%lx\n",
+              rbs_size, rbs_size / sizeof(unsigned long));
+
+       for (i = 0; i < rbs_size / sizeof(unsigned long); i++) {
+               const char* zero_or_n = "0x";
+               if (ia64_rse_is_rnat_slot((unsigned long*)&rbs[i]))
+                       zero_or_n = "Nx";
+
+               if ((i % 3) == 0)
+                       printk("0x%02x:", i);
+               printk(" %s%016lx", zero_or_n, rbs[i]);
+               if ((i % 3) == 2)
+                       printk("\n");
+       }
+       printk("\n");           
+}
+
+#define rbs_print(rbs, rbs_size)                               \
+       __rbs_print(__func__, __LINE__, (#rbs), (rbs), (rbs_size))
+#endif
+
+static int
+copy_rbs(struct vcpu* v, unsigned long* dst_rbs_size,
+        const unsigned long* rbs, unsigned long rbs_size,
+        unsigned long src_rnat, unsigned long rbs_voff)
+{
+       int rc = -EINVAL;
+       struct page_info* page;
+       unsigned char* vaddr;
+       unsigned long* src_bsp;
+       unsigned long* src_bspstore;
+
+       struct switch_stack* sw = vcpu_to_switch_stack(v);
+       unsigned long num_regs;
+       unsigned long* dst_bsp;
+       unsigned long* dst_bspstore;
+       unsigned long* dst_rnat;
+       unsigned long dst_rnat_tmp;
+       unsigned long dst_rnat_mask;
+       unsigned long flags;
+       extern void ia64_copy_rbs(unsigned long* dst_bspstore,
+                                 unsigned long* dst_rbs_size,
+                                 unsigned long* dst_rnat_p,
+                                 unsigned long* src_bsp,
+                                 unsigned long src_rbs_size,
+                                 unsigned long src_rnat);
+
+       dst_bspstore = vcpu_to_rbs_bottom(v);
+       *dst_rbs_size = rbs_size;
+       if (rbs_size == 0)
+               return 0;
+       
+       // rbs offset depends on sizeof(struct vcpu) so that
+       // it's too unstable for hypercall ABI.
+       // we need to take rbs offset into acount.
+       //memcpy(dst_bspstore, c.nat->regs.rbs, rbs_size);
+
+       // It is assumed that rbs_size is small enough compared
+       // to KERNEL_STACK_SIZE.
+       page = alloc_domheap_pages(NULL, KERNEL_STACK_SIZE_ORDER, 0);
+       if (page == NULL)
+               return -ENOMEM;
+       vaddr = page_to_virt(page);
+
+       src_bspstore = (unsigned long*)(vaddr + rbs_voff * 8);
+       src_bsp = (unsigned long*)((unsigned char*)src_bspstore + rbs_size);
+       if ((unsigned long)src_bsp >= (unsigned long)vaddr + PAGE_SIZE)
+               goto out;
+       memcpy(src_bspstore, rbs, rbs_size);
+       
+       num_regs = ia64_rse_num_regs(src_bspstore, src_bsp);
+       dst_bsp = ia64_rse_skip_regs(dst_bspstore, num_regs);
+       *dst_rbs_size = (unsigned long)dst_bsp - (unsigned long)dst_bspstore;
+
+       // rough check.
+       if (((unsigned long)dst_bsp & ~PAGE_MASK) > KERNEL_STACK_SIZE / 2)
+               goto out;
+
+       //XXX TODO
+       // ia64_copy_rbs() uses real cpu's stack register.
+       // So it may fault with an Illigal Operation fault resulting
+       // in panic if rbs_size is too large to load compared to
+       // the number of physical stacked registers, RSE.N_STACKED_PHYS,
+       // which is cpu implementatin specific.
+       // See SDM vol. 2  Register Stack Engine 6, especially 6.5.5.
+       //
+       // For safe operation and cpu model independency, 
+       // we need to copy them by hand without loadrs and flushrs
+       // However even if we implement that, similar issue still occurs
+       // when running guest. CPU context restore routine issues loadrs
+       // resulting in Illegal Operation fault. For such a case,
+       // we need to emulate RSE store.
+       // So it would be better to implement only RSE store emulation
+       // and copy stacked registers directly into guest RBS.
+       if (num_regs > num_phys_stacked) {
+               rc = -ENOSYS;
+               gdprintk(XENLOG_WARNING,
+                        "%s:%d domain %d: can't load stacked registres\n"
+                        "requested size 0x%lx => 0x%lx, num regs %ld"
+                        "RSE.N_STACKED_PHYS %ld\n",
+                        __func__, __LINE__, v->domain->domain_id, 
+                        rbs_size, *dst_rbs_size, num_regs,
+                        num_phys_stacked);
+               goto out;
+       }
+
+       // we mask interrupts to avoid using register backing store.
+       local_irq_save(flags);
+       ia64_copy_rbs(dst_bspstore, dst_rbs_size, &dst_rnat_tmp,
+                     src_bsp, rbs_size, src_rnat);
+       local_irq_restore(flags);
+
+       dst_rnat_mask = (1UL << ia64_rse_slot_num(dst_bsp)) - 1;
+       dst_rnat = ia64_rse_rnat_addr(dst_bsp);
+       if ((unsigned long)dst_rnat > sw->ar_bspstore)
+               dst_rnat = &sw->ar_rnat;
+       // if ia64_rse_rnat_addr(dst_bsp) ==
+       // ia64_rse_rnat_addr(vcpu_to_rbs_bottom(v)), the lsb bit of rnat
+       // is just ignored. so we don't have to mask it out.
+       *dst_rnat =
+               (*dst_rnat & ~dst_rnat_mask) | (dst_rnat_tmp & dst_rnat_mask);
+       
+       rc = 0;
+out:
+       free_domheap_pages(page, KERNEL_STACK_SIZE_ORDER);
+       return rc;
+}
+
+static void
+unat_update(unsigned long *unat_eml, unsigned long *spill_addr, char nat)
+{
+       unsigned int pos = ia64_unat_pos(spill_addr);
+       if (nat)
+               *unat_eml |= (1UL << pos);
+       else
+               *unat_eml &= ~(1UL << pos);
 }
 
 int arch_set_info_guest(struct vcpu *v, vcpu_guest_context_u c)
 {
        struct cpu_user_regs *uregs = vcpu_regs(v);
        struct domain *d = v->domain;
+       struct switch_stack *sw = vcpu_to_switch_stack(v);
        int was_initialised = v->is_initialised;
+       struct unw_frame_info info;
        unsigned int rbs_size;
-       int rc, i;
+       unsigned int num_regs;
+       unsigned long * const rbs_bottom = vcpu_to_rbs_bottom(v);
+       int rc = 0;
+       int i;
 
        /* Finish vcpu initialization.  */
        if (!was_initialised) {
@@ -806,6 +1194,26 @@ int arch_set_info_guest(struct vcpu *v, 
        uregs->b6 = c.nat->regs.b[6];
        uregs->b7 = c.nat->regs.b[7];
        
+       memset(&info, 0, sizeof(info));
+       unw_init_from_blocked_task(&info, v);
+       if (vcpu_has_not_run(v)) {
+               sw->ar_lc = c.nat->regs.ar.lc;
+               sw->ar_pfs =
+                       (sw->ar_pfs & ~AR_PFS_PEC_MASK) |
+                       ((c.nat->regs.ar.ec << AR_PFS_PEC_SHIFT) &
+                        AR_PFS_PEC_MASK);
+       } else if (unw_unwind_to_user(&info) < 0) {
+               /* warn: should panic? */
+               gdprintk(XENLOG_ERR,
+                        "vcpu=%d unw_unwind_to_user() failed.\n",
+                        v->vcpu_id);
+               show_stack(v, NULL);
+
+               //return -ENOSYS;
+       } else {
+               unw_set_ar(&info, UNW_AR_LC, c.nat->regs.ar.lc);
+               unw_set_ar(&info, UNW_AR_EC, c.nat->regs.ar.ec);
+       }
        uregs->ar_csd = c.nat->regs.ar.csd;
        uregs->ar_ssd = c.nat->regs.ar.ssd;
        
@@ -820,7 +1228,7 @@ int arch_set_info_guest(struct vcpu *v, 
                vmx_vcpu_set_psr(v, c.nat->regs.psr);
        uregs->cr_iip = c.nat->regs.ip;
        uregs->cr_ifs = c.nat->regs.cfm;
-       
+
        uregs->ar_unat = c.nat->regs.ar.unat;
        uregs->ar_pfs = c.nat->regs.ar.pfs;
        uregs->ar_rsc = c.nat->regs.ar.rsc;
@@ -829,12 +1237,46 @@ int arch_set_info_guest(struct vcpu *v, 
        
        uregs->pr = c.nat->regs.pr;
        uregs->b0 = c.nat->regs.b[0];
-       rbs_size = c.nat->regs.ar.bsp - c.nat->regs.ar.bspstore;
+       if (((IA64_RBS_OFFSET / 8) % 64) != c.nat->regs.rbs_voff)
+               gdprintk(XENLOG_INFO,
+                        "rbs stack offset is different! xen 0x%x given 0x%x",
+                        (IA64_RBS_OFFSET / 8) % 64, c.nat->regs.rbs_voff);
+       num_regs = ia64_rse_num_regs((unsigned long*)c.nat->regs.ar.bspstore,
+                                    (unsigned long*)c.nat->regs.ar.bsp);
+       rbs_size = (unsigned long)ia64_rse_skip_regs(rbs_bottom, num_regs) -
+               (unsigned long)rbs_bottom;
+       if (rbs_size > sizeof (c.nat->regs.rbs)) {
+               gdprintk(XENLOG_INFO,
+                        "rbs size is too large %x > %lx\n",
+                        rbs_size, sizeof (c.nat->regs.rbs));
+               return -EINVAL;
+       }
+       
        /* Protection against crazy user code.  */
        if (!was_initialised)
-               uregs->loadrs = (rbs_size) << 16;
-       if (rbs_size == (uregs->loadrs >> 16))
-               memcpy((char *)v + IA64_RBS_OFFSET, c.nat->regs.rbs, rbs_size);
+               uregs->loadrs = (rbs_size << 16);
+       if (rbs_size == (uregs->loadrs >> 16)) {
+               unsigned long dst_rbs_size = 0;
+               if (vcpu_has_not_run(v))
+                       sw->ar_bspstore = (unsigned long)rbs_bottom;
+               
+               rc = copy_rbs(v, &dst_rbs_size,
+                             c.nat->regs.rbs, rbs_size,
+                             c.nat->regs.rbs_rnat,
+                             c.nat->regs.rbs_voff);
+               if (rc < 0)
+                       return rc;
+
+               /* In case of newly created vcpu, ar_bspstore points to
+                * the bottom of register stack. Move it up.
+                * See also init_switch_stack().
+                */
+               if (vcpu_has_not_run(v)) {
+                       uregs->loadrs = (dst_rbs_size << 16);
+                       sw->ar_bspstore = (unsigned long)((char*)rbs_bottom +
+                                                         dst_rbs_size);
+               }
+       }
 
        uregs->r1 = c.nat->regs.r[1];
        uregs->r12 = c.nat->regs.r[12];
@@ -863,22 +1305,117 @@ int arch_set_info_guest(struct vcpu *v, 
        uregs->r31 = c.nat->regs.r[31];
        
        uregs->ar_ccv = c.nat->regs.ar.ccv;
-       
+
+       COPY_FPREG(&sw->f2, &c.nat->regs.f[2]);
+       COPY_FPREG(&sw->f3, &c.nat->regs.f[3]);
+       COPY_FPREG(&sw->f4, &c.nat->regs.f[4]);
+       COPY_FPREG(&sw->f5, &c.nat->regs.f[5]);
+
        COPY_FPREG(&uregs->f6, &c.nat->regs.f[6]);
        COPY_FPREG(&uregs->f7, &c.nat->regs.f[7]);
        COPY_FPREG(&uregs->f8, &c.nat->regs.f[8]);
        COPY_FPREG(&uregs->f9, &c.nat->regs.f[9]);
        COPY_FPREG(&uregs->f10, &c.nat->regs.f[10]);
        COPY_FPREG(&uregs->f11, &c.nat->regs.f[11]);
+
+       COPY_FPREG(&sw->f12, &c.nat->regs.f[12]);
+       COPY_FPREG(&sw->f13, &c.nat->regs.f[13]);
+       COPY_FPREG(&sw->f14, &c.nat->regs.f[14]);
+       COPY_FPREG(&sw->f15, &c.nat->regs.f[15]);
+       COPY_FPREG(&sw->f16, &c.nat->regs.f[16]);
+       COPY_FPREG(&sw->f17, &c.nat->regs.f[17]);
+       COPY_FPREG(&sw->f18, &c.nat->regs.f[18]);
+       COPY_FPREG(&sw->f19, &c.nat->regs.f[19]);
+       COPY_FPREG(&sw->f20, &c.nat->regs.f[20]);
+       COPY_FPREG(&sw->f21, &c.nat->regs.f[21]);
+       COPY_FPREG(&sw->f22, &c.nat->regs.f[22]);
+       COPY_FPREG(&sw->f23, &c.nat->regs.f[23]);
+       COPY_FPREG(&sw->f24, &c.nat->regs.f[24]);
+       COPY_FPREG(&sw->f25, &c.nat->regs.f[25]);
+       COPY_FPREG(&sw->f26, &c.nat->regs.f[26]);
+       COPY_FPREG(&sw->f27, &c.nat->regs.f[27]);
+       COPY_FPREG(&sw->f28, &c.nat->regs.f[28]);
+       COPY_FPREG(&sw->f29, &c.nat->regs.f[29]);
+       COPY_FPREG(&sw->f30, &c.nat->regs.f[30]);
+       COPY_FPREG(&sw->f31, &c.nat->regs.f[31]);
+
+       for (i = 0; i < 96; i++)
+               COPY_FPREG(&v->arch._thread.fph[i], &c.nat->regs.f[i + 32]);
+
+
+#define UNAT_UPDATE(reg)                                       \
+       unat_update(&uregs->eml_unat, &uregs->r ## reg,         \
+                   !!(c.nat->regs.nats & (1UL << (reg))));
+
+       uregs->eml_unat = 0;
+       UNAT_UPDATE(1);
+       UNAT_UPDATE(2);
+       UNAT_UPDATE(3);
+
+       UNAT_UPDATE(8);
+       UNAT_UPDATE(9);
+       UNAT_UPDATE(10);
+       UNAT_UPDATE(11);
+       UNAT_UPDATE(12);
+       UNAT_UPDATE(13);
+       UNAT_UPDATE(14);
+       UNAT_UPDATE(15);
+       UNAT_UPDATE(16);
+       UNAT_UPDATE(17);
+       UNAT_UPDATE(18);
+       UNAT_UPDATE(19);
+       UNAT_UPDATE(20);
+       UNAT_UPDATE(21);
+       UNAT_UPDATE(22);
+       UNAT_UPDATE(23);
+       UNAT_UPDATE(24);
+       UNAT_UPDATE(25);
+       UNAT_UPDATE(26);
+       UNAT_UPDATE(27);
+       UNAT_UPDATE(28);
+       UNAT_UPDATE(29);
+       UNAT_UPDATE(30);
+       UNAT_UPDATE(31);
        
+       /*
+        * r4-r7 is saved sometimes both in pt_regs->r[4-7] and memory stack or
+        * only in memory stack.
+        * for both cases, both memory stack and pt_regs->r[4-7] are updated.
+        */
        uregs->r4 = c.nat->regs.r[4];
        uregs->r5 = c.nat->regs.r[5];
        uregs->r6 = c.nat->regs.r[6];
        uregs->r7 = c.nat->regs.r[7];
-       
-       /* FIXME: to be reordered and restored.  */
-       /* uregs->eml_unat = c.nat->regs.nat; */
-       uregs->eml_unat = 0;
+
+       UNAT_UPDATE(4);
+       UNAT_UPDATE(5);
+       UNAT_UPDATE(6);
+       UNAT_UPDATE(7);
+#undef UNAT_UPDATE
+       if (vcpu_has_not_run(v)) {
+               sw->r4 = c.nat->regs.r[4];
+               sw->r5 = c.nat->regs.r[5];
+               sw->r6 = c.nat->regs.r[6];
+               sw->r7 = c.nat->regs.r[7];
+
+               unat_update(&sw->ar_unat, &sw->r4,
+                           !!(c.nat->regs.nats & (1UL << 4)));
+               unat_update(&sw->ar_unat, &sw->r5,
+                           !!(c.nat->regs.nats & (1UL << 5)));
+               unat_update(&sw->ar_unat, &sw->r6,
+                           !!(c.nat->regs.nats & (1UL << 6)));
+               unat_update(&sw->ar_unat, &sw->r7,
+                           !!(c.nat->regs.nats & (1UL << 7)));
+       } else {
+               unw_set_gr(&info, 4, c.nat->regs.r[4],
+                          !!(c.nat->regs.nats & (1UL << 4)));
+               unw_set_gr(&info, 5, c.nat->regs.r[5],
+                          !!(c.nat->regs.nats & (1UL << 5)));
+               unw_set_gr(&info, 6, c.nat->regs.r[6],
+                          !!(c.nat->regs.nats & (1UL << 6)));
+               unw_set_gr(&info, 7, c.nat->regs.r[7],
+                          !!(c.nat->regs.nats & (1UL << 7)));
+       }
        
        if (!d->arch.is_vti) {
                /* domain runs at PL2/3 */
@@ -888,8 +1425,31 @@ int arch_set_info_guest(struct vcpu *v, 
        }
 
        for (i = 0; i < IA64_NUM_DBG_REGS; i++) {
-               vcpu_set_dbr(v, i, c.nat->regs.dbr[i]);
-               vcpu_set_ibr(v, i, c.nat->regs.ibr[i]);
+               if (d->arch.is_vti) {
+                       vmx_vcpu_set_dbr(v, i, c.nat->regs.dbr[i]);
+                       vmx_vcpu_set_ibr(v, i, c.nat->regs.ibr[i]);
+               } else {
+                       vcpu_set_dbr(v, i, c.nat->regs.dbr[i]);
+                       vcpu_set_ibr(v, i, c.nat->regs.ibr[i]);
+               }
+       }
+
+       /* rr[] must be set before setting itrs[] dtrs[] */
+       for (i = 0; i < 8; i++) {
+               //XXX TODO integrity check.
+               //    if invalid value is given, 
+               //    vmx_load_all_rr() and load_region_regs()
+               //    result in General exception, reserved register/field
+               //    failt causing panicing xen.
+               if (d->arch.is_vti) {
+                       //without VGCF_EXTRA_REGS check,
+                       //VTi domain doesn't boot.
+                       if (c.nat->flags & VGCF_EXTRA_REGS)
+                               vmx_vcpu_set_rr(v, (unsigned long)i << 61,
+                                               c.nat->regs.rr[i]);
+               } else
+                       vcpu_set_rr(v, (unsigned long)i << 61,
+                                   c.nat->regs.rr[i]);
        }
 
        if (c.nat->flags & VGCF_EXTRA_REGS) {
@@ -898,25 +1458,38 @@ int arch_set_info_guest(struct vcpu *v, 
                for (i = 0;
                     (i < sizeof(tr->itrs) / sizeof(tr->itrs[0])) && i < NITRS;
                     i++) {
-                       vcpu_set_itr(v, i, tr->itrs[i].pte,
-                                    tr->itrs[i].itir,
-                                    tr->itrs[i].vadr,
-                                    tr->itrs[i].rid);
+                       if (d->arch.is_vti)
+                               vmx_vcpu_itr_i(v, i, tr->itrs[i].pte,
+                                              tr->itrs[i].itir,
+                                              tr->itrs[i].vadr);
+                       else
+                               vcpu_set_itr(v, i, tr->itrs[i].pte,
+                                            tr->itrs[i].itir,
+                                            tr->itrs[i].vadr,
+                                            tr->itrs[i].rid);
                }
                for (i = 0;
                     (i < sizeof(tr->dtrs) / sizeof(tr->dtrs[0])) && i < NDTRS;
                     i++) {
-                       vcpu_set_dtr(v, i,
-                                    tr->dtrs[i].pte,
-                                    tr->dtrs[i].itir,
-                                    tr->dtrs[i].vadr,
-                                    tr->dtrs[i].rid);
+                       if (d->arch.is_vti)
+                               vmx_vcpu_itr_d(v, i, tr->dtrs[i].pte,
+                                              tr->dtrs[i].itir,
+                                              tr->dtrs[i].vadr);
+                       else
+                               vcpu_set_dtr(v, i,
+                                            tr->dtrs[i].pte,
+                                            tr->dtrs[i].itir,
+                                            tr->dtrs[i].vadr,
+                                            tr->dtrs[i].rid);
                }
                v->arch.event_callback_ip = c.nat->event_callback_ip;
                vcpu_set_iva(v, c.nat->regs.cr.iva);
        }
 
-       return 0;
+       if (d->arch.is_vti)
+               rc = vmx_arch_set_info_guest(v, c);
+
+       return rc;
 }
 
 static void relinquish_memory(struct domain *d, struct list_head *list)
diff -r 905a46fbe0d8 -r a04cedb034ea xen/arch/ia64/xen/xenasm.S
--- a/xen/arch/ia64/xen/xenasm.S        Wed Oct 10 19:45:29 2007 +0900
+++ b/xen/arch/ia64/xen/xenasm.S        Thu Oct 11 19:54:56 2007 +0900
@@ -3,6 +3,10 @@
  *
  * Copyright (C) 2004 Hewlett-Packard Co
  *     Dan Magenheimer <dan.magenheimer@xxxxxx>
+ *
+ * Copyright (C) 2007 VA Linux Systems Japan K.K.
+ *      Isaku Yamahata <yamahata at valinux co jp>
+ *      ia64_copy_rbs()
  */
 
 #include <linux/config.h>
@@ -357,3 +361,145 @@ stacked:
        br.ret.sptk.few rp
 END(pal_emulator_static)
 
+// void ia64_copy_rbs(unsigned long* dst_bspstore, unsigned long* dst_rbs_size,
+//                    unsigned long* dst_rnat_p,
+//                    unsigned long* src_bsp, unsigned long src_rbs_size,
+//                    unsigned long src_rnat);
+// Caller must mask interrupions.
+// Caller must ensure that src_rbs_size isn't larger than the number
+// of physical stacked registers. otherwise loadrs fault with Illegal
+// Operation fault resulting in panic.
+//
+// r14 = r32 = dst_bspstore
+// r15 = r33 = dst_rbs_size_p  
+// r16 = r34 = dst_rnat_p
+// r17 = r35 = src_bsp
+// r18 = r36 = src_rbs_size
+// r19 = r37 = src_rnat        
+//
+// r20 = saved ar.rsc
+// r21 = saved ar.bspstore
+//     
+// r22 = saved_ar_rnat
+// r23 = saved_ar_rp
+// r24 = saved_ar_pfs  
+//
+// we save the value in this register and store it into [dst_rbs_size_p] and
+// [dst_rnat_p] after rse opeation is done.
+// r30 = return value of __ia64_copy_rbs to ia64_copy_to_rbs = dst_rbs_size
+// r31 = return value of __ia64_copy_rbs to ia64_copy_to_rbs = dst_rnat
+//
+#define dst_bspstore           r14
+#define dst_rbs_size_p         r15
+#define dst_rnat_p             r16
+#define src_bsp                        r17
+#define src_rbs_size           r18
+#define src_rnat               r19
+
+#define saved_ar_rsc           r20
+#define saved_ar_bspstore      r21
+#define saved_ar_rnat          r22
+#define saved_rp               r23
+#define saved_ar_pfs           r24
+
+#define dst_rbs_size           r30
+#define dst_rnat               r31
+ENTRY(__ia64_copy_rbs)
+       .prologue
+       .fframe 0
+
+       // Here cfm.{sof, sol, sor, rrb}=0 
+       //
+       // flush current register stack to backing store
+{
+       flushrs // must be first isns in group
+       srlz.i
+}
+
+       // switch to enforced lazy mode 
+       mov saved_ar_rsc = ar.rsc
+       ;; 
+       mov ar.rsc = 0
+       ;; 
+
+       .save ar.bspstore, saved_ar_bspstore
+       mov saved_ar_bspstore = ar.bspstore
+       .save ar.rnat, saved_ar_rnat
+       mov saved_ar_rnat = ar.rnat
+       ;;
+
+       .body
+       // load from src
+       mov ar.bspstore = src_bsp
+       ;; 
+       mov ar.rnat = src_rnat
+       shl src_rbs_size = src_rbs_size,16
+       ;; 
+       mov ar.rsc = src_rbs_size
+       ;;
+{
+       loadrs // must be first isns in group
+       ;;
+}
+
+       // flush to dst
+       mov ar.bspstore = dst_bspstore
+       ;;
+{
+       flushrs // must be first isns in group
+       srlz.i
+}
+       ;;
+       mov dst_rbs_size = ar.bsp
+       mov dst_rnat = ar.rnat
+       ;;
+       sub dst_rbs_size = dst_rbs_size, dst_bspstore
+
+       // switch back to the original backing store
+       .restorereg ar.bspstore
+       mov ar.bspstore = saved_ar_bspstore
+       ;;
+       .restorereg ar.rnat
+       mov ar.rnat = saved_ar_rnat
+       ;; 
+       // restore rsc          
+       mov ar.rsc = saved_ar_rsc
+
+       ;; 
+       br.ret.sptk.many rp
+END(__ia64_copy_rbs)
+
+GLOBAL_ENTRY(ia64_copy_rbs)
+       .prologue
+       .fframe 0
+       .save ar.pfs, saved_ar_pfs
+       alloc saved_ar_pfs = ar.pfs, 6, 0, 0, 0
+       .save.b 0x1, saved_rp
+       mov saved_rp = rp
+
+       .body
+       // we play with register backing store so that we can't use
+       // stacked registers.
+       // save in0-in5 to static scratch registres
+       mov dst_bspstore   = r32
+       mov dst_rbs_size_p = r33
+       mov dst_rnat_p     = r34
+       mov src_bsp        = r35
+       mov src_rbs_size   = r36
+       mov src_rnat       = r37
+       ;;
+       // set cfm.{sof, sol, sor, rrb}=0 to avoid nasty stacked register
+       // issues related to cover by calling void __ia64_copy_rbs(void).
+       // cfm.{sof, sol, sor, rrb}=0 makes things easy.
+       br.call.sptk.many rp = __ia64_copy_rbs
+
+       st8 [dst_rbs_size_p] = dst_rbs_size
+       st8 [dst_rnat_p]     = dst_rnat
+
+       .restorereg ar.pfs
+       mov ar.pfs = saved_ar_pfs
+       .restorereg rp
+       mov rp = saved_rp
+       ;; 
+       br.ret.sptk.many rp
+END(ia64_copy_rbs)
diff -r 905a46fbe0d8 -r a04cedb034ea xen/include/asm-ia64/vmx_vcpu_save.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/include/asm-ia64/vmx_vcpu_save.h      Thu Oct 11 19:54:56 2007 +0900
@@ -0,0 +1,40 @@
+/******************************************************************************
+ * vmx_vcpu_save.h
+ *
+ * Copyright (c) 2007 Isaku Yamahata <yamahata at valinux co jp>
+ *                    VA Linux Systems Japan K.K.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that 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_IA64_VMX_VCPU_SAVE_H__
+#define __ASM_IA64_VMX_VCPU_SAVE_H__
+
+#include <xen/sched.h>
+#include <xen/domain.h>
+
+void vmx_arch_get_info_guest(struct vcpu *v, vcpu_guest_context_u c);
+int vmx_arch_set_info_guest(struct vcpu *v, vcpu_guest_context_u c);
+
+#endif /* __ASM_IA64_VMX_VCPU_SAVE_H__ */
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff -r 905a46fbe0d8 -r a04cedb034ea xen/include/public/arch-ia64.h
--- a/xen/include/public/arch-ia64.h    Wed Oct 10 19:45:29 2007 +0900
+++ b/xen/include/public/arch-ia64.h    Thu Oct 11 19:54:56 2007 +0900
@@ -421,7 +421,7 @@ struct vcpu_guest_context_regs {
 };
 
 struct vcpu_guest_context {
-#define VGCF_EXTRA_REGS (1<<1) /* Get/Set extra regs.  */
+#define VGCF_EXTRA_REGS (1UL << 1)     /* Get/Set extra regs.  */
     unsigned long flags;       /* VGCF_* flags */
 
     struct vcpu_guest_context_regs regs;

Attachment: 16064_a04cedb034ea_implement_arch_get_set_info_guest.patch
Description: Text Data

_______________________________________________
Xen-ia64-devel mailing list
Xen-ia64-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-ia64-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.