WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-changelog

[Xen-changelog] [xen-unstable] x86: xsave save/restore support for both

To: xen-changelog@xxxxxxxxxxxxxxxxxxx
Subject: [Xen-changelog] [xen-unstable] x86: xsave save/restore support for both PV and HVM guests (version 2)
From: Xen patchbot-unstable <patchbot-unstable@xxxxxxxxxxxxxxxxxxx>
Date: Mon, 08 Nov 2010 21:25:14 -0800
Delivery-date: Mon, 08 Nov 2010 21:26:45 -0800
Envelope-to: www-data@xxxxxxxxxxxxxxxxxxx
List-help: <mailto:xen-changelog-request@lists.xensource.com?subject=help>
List-id: BK change log <xen-changelog.lists.xensource.com>
List-post: <mailto:xen-changelog@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=unsubscribe>
Reply-to: xen-devel@xxxxxxxxxxxxxxxxxxx
Sender: xen-changelog-bounces@xxxxxxxxxxxxxxxxxxx
# HG changeset patch
# User Keir Fraser <keir@xxxxxxx>
# Date 1289231042 0
# Node ID d8b8490d73ded5787c4e1cd10b2f29c9e4be3632
# Parent  eceb22a210e7f1e460092c1cfa2e544088c30314
x86: xsave save/restore support for both PV and HVM guests (version 2)

I have tested the patch in the following senarios:
1> Non-xsave platform
2> Xsave-capable platform, guest does not support xsave, xen support xsave
3> Xsave-capable platform, guest does support xsave, xen supports xsave
4> Guest (non-xsave) saved on platform without xsave, restored on a
   Xsave-capable system.

All passed.

Signed-off-by: Shan Haitao <haitao.shan@xxxxxxxxx>
Signed-off-by: Han Weidong <weidong.han@xxxxxxxxx>
---
 tools/libxc/xc_domain_restore.c        |   78 +++++++++++++++++--
 tools/libxc/xc_domain_save.c           |   76 ++++++++++++++++++-
 xen/arch/x86/domctl.c                  |  132 +++++++++++++++++++++++++++++++++
 xen/arch/x86/hvm/hvm.c                 |  118 +++++++++++++++++++++++++++++
 xen/include/public/arch-x86/hvm/save.h |   25 ++++++
 xen/include/public/domctl.h            |   28 +++++++
 xen/include/xsm/xsm.h                  |    5 +
 xen/xsm/flask/hooks.c                  |   20 +++++
 xen/xsm/flask/include/av_permissions.h |    2 
 9 files changed, 471 insertions(+), 13 deletions(-)

diff -r eceb22a210e7 -r d8b8490d73de tools/libxc/xc_domain_restore.c
--- a/tools/libxc/xc_domain_restore.c   Mon Nov 08 15:41:01 2010 +0000
+++ b/tools/libxc/xc_domain_restore.c   Mon Nov 08 15:44:02 2010 +0000
@@ -189,7 +189,8 @@ static int uncanonicalize_pagetable(
 /* Load the p2m frame list, plus potential extended info chunk */
 static xen_pfn_t *load_p2m_frame_list(
     xc_interface *xch, struct restore_ctx *ctx,
-    int io_fd, int *pae_extended_cr3, int *ext_vcpucontext)
+    int io_fd, int *pae_extended_cr3, int *ext_vcpucontext,
+    int *vcpuextstate, uint32_t *vcpuextstate_size)
 {
     xen_pfn_t *p2m_frame_list;
     vcpu_guest_context_any_t ctxt;
@@ -265,6 +266,13 @@ static xen_pfn_t *load_p2m_frame_list(
             else if ( !strncmp(chunk_sig, "extv", 4) )
             {
                 *ext_vcpucontext = 1;
+            }
+            else if ( !strncmp(chunk_sig, "xcnt", 4) )
+            {
+                *vcpuextstate = 1;
+                RDEXACT(io_fd, vcpuextstate_size, sizeof(*vcpuextstate_size));
+                tot_bytes -= chunk_bytes;
+                chunk_bytes = 0;
             }
             
             /* Any remaining bytes of this chunk: read and discard. */
@@ -449,7 +457,8 @@ static int buffer_tail_hvm(xc_interface 
 static int buffer_tail_hvm(xc_interface *xch, struct restore_ctx *ctx,
                            struct tailbuf_hvm *buf, int fd,
                            unsigned int max_vcpu_id, uint64_t vcpumap,
-                           int ext_vcpucontext)
+                           int ext_vcpucontext,
+                           int vcpuextstate, uint32_t vcpuextstate_size)
 {
     uint8_t *tmp;
     unsigned char qemusig[21];
@@ -516,7 +525,9 @@ static int buffer_tail_pv(xc_interface *
 static int buffer_tail_pv(xc_interface *xch, struct restore_ctx *ctx,
                           struct tailbuf_pv *buf, int fd,
                           unsigned int max_vcpu_id, uint64_t vcpumap,
-                          int ext_vcpucontext)
+                          int ext_vcpucontext,
+                          int vcpuextstate,
+                          uint32_t vcpuextstate_size)
 {
     unsigned int i;
     size_t pfnlen, vcpulen;
@@ -556,6 +567,9 @@ static int buffer_tail_pv(xc_interface *
                : sizeof(vcpu_guest_context_x86_32_t)) * buf->vcpucount;
     if ( ext_vcpucontext )
         vcpulen += 128 * buf->vcpucount;
+    if ( vcpuextstate ) {
+        vcpulen += vcpuextstate_size * buf->vcpucount;
+    }
 
     if ( !(buf->vcpubuf) ) {
         if ( !(buf->vcpubuf = malloc(vcpulen)) ) {
@@ -594,14 +608,17 @@ static int buffer_tail_pv(xc_interface *
 
 static int buffer_tail(xc_interface *xch, struct restore_ctx *ctx,
                        tailbuf_t *buf, int fd, unsigned int max_vcpu_id,
-                       uint64_t vcpumap, int ext_vcpucontext)
+                       uint64_t vcpumap, int ext_vcpucontext,
+                       int vcpuextstate, uint32_t vcpuextstate_size)
 {
     if ( buf->ishvm )
         return buffer_tail_hvm(xch, ctx, &buf->u.hvm, fd, max_vcpu_id, vcpumap,
-                               ext_vcpucontext);
+                               ext_vcpucontext, vcpuextstate,
+                               vcpuextstate_size);
     else
         return buffer_tail_pv(xch, ctx, &buf->u.pv, fd, max_vcpu_id, vcpumap,
-                              ext_vcpucontext);
+                              ext_vcpucontext, vcpuextstate,
+                              vcpuextstate_size);
 }
 
 static void tailbuf_free_hvm(struct tailbuf_hvm *buf)
@@ -1056,6 +1073,8 @@ int xc_domain_restore(xc_interface *xch,
 {
     DECLARE_DOMCTL;
     int rc = 1, frc, i, j, n, m, pae_extended_cr3 = 0, ext_vcpucontext = 0;
+    int vcpuextstate = 0;
+    uint32_t vcpuextstate_size = 0;
     unsigned long mfn, pfn;
     unsigned int prev_pc;
     int nraces = 0;
@@ -1069,6 +1088,9 @@ int xc_domain_restore(xc_interface *xch,
 
     /* A copy of the CPU context of the guest. */
     DECLARE_HYPERCALL_BUFFER(vcpu_guest_context_any_t, ctxt);
+
+    /* A copy of the CPU eXtended States of the guest. */
+    DECLARE_HYPERCALL_BUFFER(void, buffer);
 
     /* A table containing the type of each PFN (/not/ MFN!). */
     unsigned long *pfn_type = NULL;
@@ -1156,7 +1178,9 @@ int xc_domain_restore(xc_interface *xch,
     {
         /* Load the p2m frame list, plus potential extended info chunk */
         p2m_frame_list = load_p2m_frame_list(xch, ctx,
-            io_fd, &pae_extended_cr3, &ext_vcpucontext);
+            io_fd, &pae_extended_cr3, &ext_vcpucontext,
+            &vcpuextstate, &vcpuextstate_size);
+
         if ( !p2m_frame_list )
             goto out;
 
@@ -1303,10 +1327,11 @@ int xc_domain_restore(xc_interface *xch,
     if ( !ctx->completed ) {
 
         if ( buffer_tail(xch, ctx, &tailbuf, io_fd, max_vcpu_id, vcpumap,
-                         ext_vcpucontext) < 0 ) {
+                         ext_vcpucontext, vcpuextstate, vcpuextstate_size) < 0 
) {
             ERROR ("error buffering image tail");
             goto out;
         }
+
         ctx->completed = 1;
 
         /*
@@ -1332,7 +1357,7 @@ int xc_domain_restore(xc_interface *xch,
     memset(&tmptail, 0, sizeof(tmptail));
     tmptail.ishvm = hvm;
     if ( buffer_tail(xch, ctx, &tmptail, io_fd, max_vcpu_id, vcpumap,
-                     ext_vcpucontext) < 0 ) {
+                     ext_vcpucontext, vcpuextstate, vcpuextstate_size) < 0 ) {
         ERROR ("error buffering image tail, finishing");
         goto finish;
     }
@@ -1653,7 +1678,7 @@ int xc_domain_restore(xc_interface *xch,
         }
 
         if ( !ext_vcpucontext )
-            continue;
+            goto vcpu_ext_state_restore;
         memcpy(&domctl.u.ext_vcpucontext, vcpup, 128);
         vcpup += 128;
         domctl.cmd = XEN_DOMCTL_set_ext_vcpucontext;
@@ -1664,6 +1689,39 @@ int xc_domain_restore(xc_interface *xch,
             PERROR("Couldn't set extended vcpu%d info", i);
             goto out;
         }
+
+ vcpu_ext_state_restore:
+        if ( !vcpuextstate )
+            continue;
+
+        memcpy(&domctl.u.vcpuextstate.xfeature_mask, vcpup,
+               sizeof(domctl.u.vcpuextstate.xfeature_mask));
+        vcpup += sizeof(domctl.u.vcpuextstate.xfeature_mask);
+        memcpy(&domctl.u.vcpuextstate.size, vcpup,
+               sizeof(domctl.u.vcpuextstate.size));
+        vcpup += sizeof(domctl.u.vcpuextstate.size);
+
+        buffer = xc_hypercall_buffer_alloc(xch, buffer,
+                                           domctl.u.vcpuextstate.size);
+        if ( !buffer )
+        {
+            PERROR("Could not allocate buffer to restore eXtended States");
+            goto out;
+        }
+        memcpy(buffer, vcpup, domctl.u.vcpuextstate.size);
+        vcpup += domctl.u.vcpuextstate.size;
+
+        domctl.cmd = XEN_DOMCTL_setvcpuextstate;
+        domctl.domain = dom;
+        domctl.u.vcpuextstate.vcpu = i;
+        set_xen_guest_handle(domctl.u.vcpuextstate.buffer, buffer);
+        frc = xc_domctl(xch, &domctl);
+        if ( frc != 0 )
+        {
+            PERROR("Couldn't set eXtended States for vcpu%d", i);
+            goto out;
+        }
+        xc_hypercall_buffer_free(xch, buffer);
     }
 
     memcpy(shared_info_page, tailbuf.u.pv.shared_info_page, PAGE_SIZE);
diff -r eceb22a210e7 -r d8b8490d73de tools/libxc/xc_domain_save.c
--- a/tools/libxc/xc_domain_save.c      Mon Nov 08 15:41:01 2010 +0000
+++ b/tools/libxc/xc_domain_save.c      Mon Nov 08 15:44:02 2010 +0000
@@ -810,14 +810,39 @@ static xen_pfn_t *map_and_save_p2m_table
                               ? sizeof(ctxt.x64) 
                               : sizeof(ctxt.x32));
         uint32_t chunk2_sz = 0;
-        uint32_t tot_sz    = (chunk1_sz + 8) + (chunk2_sz + 8);
+        uint32_t chunk3_sz = 4;
+        uint32_t xcnt_size = 0;
+        uint32_t tot_sz;
+        DECLARE_DOMCTL;
+
+        domctl.cmd = XEN_DOMCTL_getvcpuextstate;
+        domctl.domain = dom;
+        domctl.u.vcpuextstate.vcpu = 0;
+        domctl.u.vcpuextstate.size = 0;
+        domctl.u.vcpuextstate.xfeature_mask = 0;
+        if ( xc_domctl(xch, &domctl) < 0 )
+        {
+            PERROR("No extended context for VCPU%d", i);
+            goto out;
+        }
+        xcnt_size = domctl.u.vcpuextstate.size + 2 * sizeof(uint64_t);
+
+        tot_sz = (chunk1_sz + 8) + (chunk2_sz + 8);
+        if ( domctl.u.vcpuextstate.xfeature_mask )
+            tot_sz += chunk3_sz + 8;
+
         if ( write_exact(io_fd, &signature, sizeof(signature)) ||
              write_exact(io_fd, &tot_sz, sizeof(tot_sz)) ||
              write_exact(io_fd, "vcpu", 4) ||
              write_exact(io_fd, &chunk1_sz, sizeof(chunk1_sz)) ||
              write_exact(io_fd, &ctxt, chunk1_sz) ||
              write_exact(io_fd, "extv", 4) ||
-             write_exact(io_fd, &chunk2_sz, sizeof(chunk2_sz)) )
+             write_exact(io_fd, &chunk2_sz, sizeof(chunk2_sz)) ||
+             (domctl.u.vcpuextstate.xfeature_mask) ?
+                (write_exact(io_fd, "xcnt", 4) ||
+                write_exact(io_fd, &chunk3_sz, sizeof(chunk3_sz)) ||
+                write_exact(io_fd, &xcnt_size, 4)) :
+                0 )
         {
             PERROR("write: extended info");
             goto out;
@@ -904,6 +929,9 @@ int xc_domain_save(xc_interface *xch, in
 
     /* base of the region in which domain memory is mapped */
     unsigned char *region_base = NULL;
+
+    /* A copy of the CPU eXtended States of the guest. */
+    DECLARE_HYPERCALL_BUFFER(void, buffer);
 
     /* bitmap of pages:
        - that should be sent this iteration (unless later marked as skip);
@@ -1786,6 +1814,50 @@ int xc_domain_save(xc_interface *xch, in
             PERROR("Error when writing to state file (2)");
             goto out;
         }
+
+        /* Start to fetch CPU eXtended States */
+        /* Get buffer size first */
+        domctl.cmd = XEN_DOMCTL_getvcpuextstate;
+        domctl.domain = dom;
+        domctl.u.vcpuextstate.vcpu = i;
+        domctl.u.vcpuextstate.xfeature_mask = 0;
+        domctl.u.vcpuextstate.size = 0;
+        if ( xc_domctl(xch, &domctl) < 0 )
+        {
+            PERROR("No eXtended states (XSAVE) for VCPU%d", i);
+            goto out;
+        }
+
+        if ( !domctl.u.vcpuextstate.xfeature_mask )
+            continue;
+
+        /* Getting eXtended states data */
+        buffer = xc_hypercall_buffer_alloc(xch, buffer, 
domctl.u.vcpuextstate.size);
+        if ( !buffer )
+        {
+            PERROR("Insufficient memory for getting eXtended states for"
+                   "VCPU%d", i);
+            goto out;
+        }
+        set_xen_guest_handle(domctl.u.vcpuextstate.buffer, buffer);
+        if ( xc_domctl(xch, &domctl) < 0 )
+        {
+            PERROR("No eXtended states (XSAVE) for VCPU%d", i);
+            xc_hypercall_buffer_free(xch, buffer);
+            goto out;
+        }
+
+        if ( wrexact(io_fd, &domctl.u.vcpuextstate.xfeature_mask,
+                     sizeof(domctl.u.vcpuextstate.xfeature_mask)) ||
+             wrexact(io_fd, &domctl.u.vcpuextstate.size,
+                     sizeof(domctl.u.vcpuextstate.size)) ||
+             wrexact(io_fd, buffer, domctl.u.vcpuextstate.size) )
+        {
+            PERROR("Error when writing to state file VCPU extended state");
+            xc_hypercall_buffer_free(xch, buffer);
+            goto out;
+        }
+        xc_hypercall_buffer_free(xch, buffer);
     }
 
     /*
diff -r eceb22a210e7 -r d8b8490d73de xen/arch/x86/domctl.c
--- a/xen/arch/x86/domctl.c     Mon Nov 08 15:41:01 2010 +0000
+++ b/xen/arch/x86/domctl.c     Mon Nov 08 15:44:02 2010 +0000
@@ -33,6 +33,7 @@
 #include <asm/mem_event.h>
 #include <public/mem_event.h>
 #include <asm/mem_sharing.h>
+#include <asm/i387.h>
 
 #ifdef XEN_KDB_CONFIG
 #include "../kdb/include/kdbdefs.h"
@@ -1406,6 +1407,132 @@ long arch_do_domctl(
     }
     break;
 
+    case XEN_DOMCTL_setvcpuextstate:
+    case XEN_DOMCTL_getvcpuextstate:
+    {
+        struct xen_domctl_vcpuextstate *evc;
+        struct domain *d;
+        struct vcpu *v;
+        uint32_t offset = 0;
+        uint64_t _xfeature_mask = 0;
+        uint64_t _xcr0, _xcr0_accum;
+        void *receive_buf = NULL, *_xsave_area;
+
+#define PV_XSAVE_SIZE (2 * sizeof(uint64_t) + xsave_cntxt_size)
+
+        evc = &domctl->u.vcpuextstate;
+
+        ret = -ESRCH;
+
+        d = rcu_lock_domain_by_id(domctl->domain);
+        if ( d == NULL )
+            break;
+
+        ret = xsm_vcpuextstate(d, domctl->cmd);
+        if ( ret )
+            goto vcpuextstate_out;
+
+        ret = -ESRCH;
+        if ( (evc->vcpu >= d->max_vcpus) ||
+             ((v = d->vcpu[evc->vcpu]) == NULL) )
+            goto vcpuextstate_out;
+
+        if ( domctl->cmd == XEN_DOMCTL_getvcpuextstate )
+        {
+            if ( !evc->size && !evc->xfeature_mask )
+            {
+                evc->xfeature_mask = xfeature_mask;
+                evc->size = PV_XSAVE_SIZE;
+                ret = 0;
+                goto vcpuextstate_out;
+            }
+            if ( evc->size != PV_XSAVE_SIZE ||
+                 evc->xfeature_mask != xfeature_mask )
+            {
+                ret = -EINVAL;
+                goto vcpuextstate_out;
+            }
+            if ( copy_to_guest_offset(domctl->u.vcpuextstate.buffer,
+                                      offset, (void *)&v->arch.xcr0,
+                                      sizeof(v->arch.xcr0)) )
+            {
+                ret = -EFAULT;
+                goto vcpuextstate_out;
+            }
+            offset += sizeof(v->arch.xcr0);
+            if ( copy_to_guest_offset(domctl->u.vcpuextstate.buffer,
+                                      offset, (void *)&v->arch.xcr0_accum,
+                                      sizeof(v->arch.xcr0_accum)) )
+            {
+                ret = -EFAULT;
+                goto vcpuextstate_out;
+            }
+            offset += sizeof(v->arch.xcr0_accum);
+            if ( copy_to_guest_offset(domctl->u.vcpuextstate.buffer,
+                                      offset, v->arch.xsave_area,
+                                      xsave_cntxt_size) )
+            {
+                ret = -EFAULT;
+                goto vcpuextstate_out;
+            }
+        }
+        else
+        {
+            ret = -EINVAL;
+
+            _xfeature_mask = evc->xfeature_mask;
+            /* xsave context must be restored on compatible target CPUs */
+            if ( (_xfeature_mask & xfeature_mask) != _xfeature_mask )
+                goto vcpuextstate_out;
+            if ( evc->size > PV_XSAVE_SIZE || evc->size < 2 * sizeof(uint64_t) 
)
+                goto vcpuextstate_out;
+
+            receive_buf = xmalloc_bytes(evc->size);
+            if ( !receive_buf )
+            {
+                ret = -ENOMEM;
+                goto vcpuextstate_out;
+            }
+            if ( copy_from_guest_offset(receive_buf, 
domctl->u.vcpuextstate.buffer,
+                                        offset, evc->size) )
+            {
+                ret = -EFAULT;
+                xfree(receive_buf);
+                goto vcpuextstate_out;
+            }
+
+            _xcr0 = *(uint64_t *)receive_buf;
+            _xcr0_accum = *(uint64_t *)(receive_buf + sizeof(uint64_t));
+            _xsave_area = receive_buf + 2 * sizeof(uint64_t);
+
+            if ( !(_xcr0 & XSTATE_FP) || _xcr0 & ~xfeature_mask )
+            {
+                xfree(receive_buf);
+                goto vcpuextstate_out;
+            }
+            if ( (_xcr0 & _xcr0_accum) != _xcr0 )
+            {
+                xfree(receive_buf);
+                goto vcpuextstate_out;
+            }
+
+            v->arch.xcr0 = _xcr0;
+            v->arch.xcr0_accum = _xcr0_accum;
+            memcpy(v->arch.xsave_area, _xsave_area, evc->size - 2 * 
sizeof(uint64_t) );
+
+            xfree(receive_buf);
+        }
+
+        ret = 0;
+
+    vcpuextstate_out:
+        rcu_unlock_domain(d);
+        if ( (domctl->cmd == XEN_DOMCTL_getvcpuextstate) &&
+             copy_to_guest(u_domctl, domctl, 1) )
+            ret = -EFAULT;
+    }
+    break;
+
 #ifdef __x86_64__
     case XEN_DOMCTL_mem_event_op:
     {
@@ -1454,6 +1581,11 @@ void arch_get_info_guest(struct vcpu *v,
 #else
 #define c(fld) (c.nat->fld)
 #endif
+
+    /* Fill legacy context from xsave area first */
+    if ( cpu_has_xsave )
+        memcpy(v->arch.xsave_area, &v->arch.guest_context.fpu_ctxt,
+               sizeof(v->arch.guest_context.fpu_ctxt));
 
     if ( !is_pv_32on64_domain(v->domain) )
         memcpy(c.nat, &v->arch.guest_context, sizeof(*c.nat));
diff -r eceb22a210e7 -r d8b8490d73de xen/arch/x86/hvm/hvm.c
--- a/xen/arch/x86/hvm/hvm.c    Mon Nov 08 15:41:01 2010 +0000
+++ b/xen/arch/x86/hvm/hvm.c    Mon Nov 08 15:44:02 2010 +0000
@@ -758,6 +758,17 @@ static int hvm_load_cpu_ctxt(struct doma
 
     memcpy(&vc->fpu_ctxt, ctxt.fpu_regs, sizeof(ctxt.fpu_regs));
 
+    /* In case xsave-absent save file is restored on a xsave-capable host */
+    if ( cpu_has_xsave )
+    {
+        struct xsave_struct *xsave_area = v->arch.xsave_area;
+
+        memcpy(v->arch.xsave_area, ctxt.fpu_regs, sizeof(ctxt.fpu_regs));
+        xsave_area->xsave_hdr.xstate_bv = XSTATE_FP_SSE;
+        v->arch.xcr0_accum = XSTATE_FP_SSE;
+        v->arch.xcr0 = XSTATE_FP_SSE;
+    }
+
     vc->user_regs.eax = ctxt.rax;
     vc->user_regs.ebx = ctxt.rbx;
     vc->user_regs.ecx = ctxt.rcx;
@@ -798,6 +809,113 @@ static int hvm_load_cpu_ctxt(struct doma
 
 HVM_REGISTER_SAVE_RESTORE(CPU, hvm_save_cpu_ctxt, hvm_load_cpu_ctxt,
                           1, HVMSR_PER_VCPU);
+
+#define HVM_CPU_XSAVE_SIZE  (3 * sizeof(uint64_t) + xsave_cntxt_size)
+
+static int hvm_save_cpu_xsave_states(struct domain *d, hvm_domain_context_t *h)
+{
+    struct vcpu *v;
+    struct hvm_hw_cpu_xsave *ctxt;
+
+    if ( !cpu_has_xsave )
+        return 0;   /* do nothing */
+
+    for_each_vcpu ( d, v )
+    {
+        if ( _hvm_init_entry(h, CPU_XSAVE_CODE, v->vcpu_id, 
HVM_CPU_XSAVE_SIZE) )
+            return 1;
+        ctxt = (struct hvm_hw_cpu_xsave *)&h->data[h->cur];
+        h->cur += HVM_CPU_XSAVE_SIZE;
+        memset(ctxt, 0, HVM_CPU_XSAVE_SIZE);
+
+        ctxt->xfeature_mask = xfeature_mask;
+        ctxt->xcr0 = v->arch.xcr0;
+        ctxt->xcr0_accum = v->arch.xcr0_accum;
+        if ( v->fpu_initialised )
+            memcpy(&ctxt->save_area,
+                v->arch.xsave_area, xsave_cntxt_size);
+    }
+
+    return 0;
+}
+
+static int hvm_load_cpu_xsave_states(struct domain *d, hvm_domain_context_t *h)
+{
+    int vcpuid;
+    struct vcpu *v;
+    struct hvm_hw_cpu_xsave *ctxt;
+    struct hvm_save_descriptor *desc;
+    uint64_t _xfeature_mask;
+
+    /* fails since we can't restore an img saved on xsave-capable host */
+//XXX: 
+    if ( !cpu_has_xsave )
+        return -EINVAL;
+
+    /* Which vcpu is this? */
+    vcpuid = hvm_load_instance(h);
+    if ( vcpuid >= d->max_vcpus || (v = d->vcpu[vcpuid]) == NULL )
+    {
+        gdprintk(XENLOG_ERR, "HVM restore: domain has no vcpu %u\n", vcpuid);
+        return -EINVAL;
+    }
+
+    /* Customized checking for entry since our entry is of variable length */
+    desc = (struct hvm_save_descriptor *)&h->data[h->cur];
+    if ( sizeof (*desc) > h->size - h->cur)
+    {
+        gdprintk(XENLOG_WARNING,
+                 "HVM restore: not enough data left to read descriptpr"
+                 "for type %u\n", CPU_XSAVE_CODE);
+        return -1;
+    }
+    if ( desc->length + sizeof (*desc) > h->size - h->cur)
+    {
+        gdprintk(XENLOG_WARNING,
+                 "HVM restore: not enough data left to read %u bytes "
+                 "for type %u\n", desc->length, CPU_XSAVE_CODE);
+        return -1;
+    }
+    if ( CPU_XSAVE_CODE != desc->typecode || (desc->length > 
HVM_CPU_XSAVE_SIZE) )
+    {
+        gdprintk(XENLOG_WARNING,
+                 "HVM restore mismatch: expected type %u with max length %u, "
+                 "saw type %u length %u\n", CPU_XSAVE_CODE,
+                 (uint32_t)HVM_CPU_XSAVE_SIZE,
+                 desc->typecode, desc->length);
+        return -1;
+    }
+    h->cur += sizeof (*desc);
+    /* Checking finished */
+
+    ctxt = (struct hvm_hw_cpu_xsave *)&h->data[h->cur];
+    h->cur += desc->length;
+
+    _xfeature_mask = ctxt->xfeature_mask;
+    if ( (_xfeature_mask & xfeature_mask) != _xfeature_mask )
+        return -EINVAL;
+
+    v->arch.xcr0 = ctxt->xcr0;
+    v->arch.xcr0_accum = ctxt->xcr0_accum;
+    memcpy(v->arch.xsave_area, &ctxt->save_area, xsave_cntxt_size);
+
+    return 0;
+}
+
+/* We need variable length data chunk for xsave area, hence customized
+ * declaration other than HVM_REGISTER_SAVE_RESTORE.
+ */
+static int __hvm_register_CPU_XSAVE_save_and_restore(void)
+{
+    hvm_register_savevm(CPU_XSAVE_CODE,
+                        "CPU_XSAVE",
+                        hvm_save_cpu_xsave_states,
+                        hvm_load_cpu_xsave_states,
+                        HVM_CPU_XSAVE_SIZE + sizeof (struct 
hvm_save_descriptor),
+                        HVMSR_PER_VCPU);
+    return 0;
+}
+__initcall(__hvm_register_CPU_XSAVE_save_and_restore);
 
 int hvm_vcpu_initialise(struct vcpu *v)
 {
diff -r eceb22a210e7 -r d8b8490d73de xen/include/public/arch-x86/hvm/save.h
--- a/xen/include/public/arch-x86/hvm/save.h    Mon Nov 08 15:41:01 2010 +0000
+++ b/xen/include/public/arch-x86/hvm/save.h    Mon Nov 08 15:44:02 2010 +0000
@@ -431,9 +431,32 @@ struct hvm_viridian_context {
 
 DECLARE_HVM_SAVE_TYPE(VIRIDIAN, 15, struct hvm_viridian_context);
 
+
+/*
+ * The save area of XSAVE/XRSTOR.
+ */
+
+struct hvm_hw_cpu_xsave {
+    uint64_t xfeature_mask;
+    uint64_t xcr0;                 /* Updated by XSETBV */
+    uint64_t xcr0_accum;           /* Updated by XSETBV */
+    struct {
+        struct { char x[512]; } fpu_sse;
+
+        struct {
+            uint64_t xstate_bv;         /* Updated by XRSTOR */
+            uint64_t reserved[7];
+        } xsave_hdr;                    /* The 64-byte header */
+
+        struct { char x[0]; } ymm;    /* YMM */
+    } save_area;
+} __attribute__((packed));
+
+#define CPU_XSAVE_CODE  16
+
 /* 
  * Largest type-code in use
  */
-#define HVM_SAVE_CODE_MAX 15
+#define HVM_SAVE_CODE_MAX 16
 
 #endif /* __XEN_PUBLIC_HVM_SAVE_X86_H__ */
diff -r eceb22a210e7 -r d8b8490d73de xen/include/public/domctl.h
--- a/xen/include/public/domctl.h       Mon Nov 08 15:41:01 2010 +0000
+++ b/xen/include/public/domctl.h       Mon Nov 08 15:44:02 2010 +0000
@@ -780,6 +780,31 @@ struct xen_domctl_mem_sharing_op {
 };
 typedef struct xen_domctl_mem_sharing_op xen_domctl_mem_sharing_op_t;
 DEFINE_XEN_GUEST_HANDLE(xen_domctl_mem_sharing_op_t);
+
+#if defined(__i386__) || defined(__x86_64__)
+/* XEN_DOMCTL_setvcpuextstate */
+/* XEN_DOMCTL_getvcpuextstate */
+struct xen_domctl_vcpuextstate {
+    /* IN: VCPU that this call applies to. */
+    uint32_t         vcpu;
+    /*
+     * SET: xfeature support mask of struct (IN)
+     * GET: xfeature support mask of struct (IN/OUT)
+     * xfeature mask is served as identifications of the saving format
+     * so that compatible CPUs can have a check on format to decide
+     * whether it can restore.
+     */
+    uint64_aligned_t         xfeature_mask;
+    /*
+     * SET: Size of struct (IN)
+     * GET: Size of struct (IN/OUT)
+     */
+    uint64_aligned_t         size;
+    XEN_GUEST_HANDLE_64(uint64) buffer;
+};
+typedef struct xen_domctl_vcpuextstate xen_domctl_vcpuextstate_t;
+DEFINE_XEN_GUEST_HANDLE(xen_domctl_vcpuextstate_t);
+#endif
 
 struct xen_domctl {
     uint32_t cmd;
@@ -841,6 +866,8 @@ struct xen_domctl {
 #define XEN_DOMCTL_gettscinfo                    59
 #define XEN_DOMCTL_settscinfo                    60
 #define XEN_DOMCTL_getpageframeinfo3             61
+#define XEN_DOMCTL_setvcpuextstate               62
+#define XEN_DOMCTL_getvcpuextstate               63
 #define XEN_DOMCTL_gdbsx_guestmemio            1000
 #define XEN_DOMCTL_gdbsx_pausevcpu             1001
 #define XEN_DOMCTL_gdbsx_unpausevcpu           1002
@@ -891,6 +918,7 @@ struct xen_domctl {
         struct xen_domctl_mem_sharing_op    mem_sharing_op;
 #if defined(__i386__) || defined(__x86_64__)
         struct xen_domctl_cpuid             cpuid;
+        struct xen_domctl_vcpuextstate      vcpuextstate;
 #endif
         struct xen_domctl_gdbsx_memio       gdbsx_guest_memio;
         struct xen_domctl_gdbsx_pauseunp_vcpu gdbsx_pauseunp_vcpu;
diff -r eceb22a210e7 -r d8b8490d73de xen/include/xsm/xsm.h
--- a/xen/include/xsm/xsm.h     Mon Nov 08 15:41:01 2010 +0000
+++ b/xen/include/xsm/xsm.h     Mon Nov 08 15:44:02 2010 +0000
@@ -149,6 +149,7 @@ struct xsm_operations {
     int (*bind_pt_irq) (struct domain *d, struct xen_domctl_bind_pt_irq *bind);
     int (*pin_mem_cacheattr) (struct domain *d);
     int (*ext_vcpucontext) (struct domain *d, uint32_t cmd);
+    int (*vcpuextstate) (struct domain *d, uint32_t cmd);
 #endif
 };
 
@@ -622,6 +623,10 @@ static inline int xsm_ext_vcpucontext(st
 {
     return xsm_call(ext_vcpucontext(d, cmd));
 }
+static inline int xsm_vcpuextstate(struct domain *d, uint32_t cmd)
+{
+    return xsm_call(vcpuextstate(d, cmd));
+}
 #endif /* CONFIG_X86 */
 
 #endif /* __XSM_H */
diff -r eceb22a210e7 -r d8b8490d73de xen/xsm/flask/hooks.c
--- a/xen/xsm/flask/hooks.c     Mon Nov 08 15:41:01 2010 +0000
+++ b/xen/xsm/flask/hooks.c     Mon Nov 08 15:44:02 2010 +0000
@@ -1173,6 +1173,25 @@ static int flask_ext_vcpucontext (struct
         break;
     default:
         return -EPERM;
+    }
+
+    return domain_has_perm(current->domain, d, SECCLASS_DOMAIN, perm);
+}
+
+static int flask_vcpuextstate (struct domain *d, uint32_t cmd)
+{
+    u32 perm;
+
+    switch ( cmd )
+    {
+        case XEN_DOMCTL_setvcpuextstate:
+            perm = DOMAIN__SETVCPUEXTSTATE;
+        break;
+        case XEN_DOMCTL_getvcpuextstate:
+            perm = DOMAIN__GETVCPUEXTSTATE;
+        break;
+        default:
+            return -EPERM;
     }
 
     return domain_has_perm(current->domain, d, SECCLASS_DOMAIN, perm);
@@ -1328,6 +1347,7 @@ static struct xsm_operations flask_ops =
     .bind_pt_irq = flask_bind_pt_irq,
     .pin_mem_cacheattr = flask_pin_mem_cacheattr,
     .ext_vcpucontext = flask_ext_vcpucontext,
+    .vcpuextstate = flask_vcpuextstate,
 #endif
 };
 
diff -r eceb22a210e7 -r d8b8490d73de xen/xsm/flask/include/av_permissions.h
--- a/xen/xsm/flask/include/av_permissions.h    Mon Nov 08 15:41:01 2010 +0000
+++ b/xen/xsm/flask/include/av_permissions.h    Mon Nov 08 15:44:02 2010 +0000
@@ -51,6 +51,8 @@
 #define DOMAIN__TRIGGER                           0x00800000UL
 #define DOMAIN__GETEXTVCPUCONTEXT                 0x01000000UL
 #define DOMAIN__SETEXTVCPUCONTEXT                 0x02000000UL
+#define DOMAIN__GETVCPUEXTSTATE                   0x04000000UL
+#define DOMAIN__SETVCPUEXTSTATE                   0x08000000UL
 
 #define HVM__SETHVMC                              0x00000001UL
 #define HVM__GETHVMC                              0x00000002UL

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

<Prev in Thread] Current Thread [Next in Thread>
  • [Xen-changelog] [xen-unstable] x86: xsave save/restore support for both PV and HVM guests (version 2), Xen patchbot-unstable <=