diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c
index c7b93c7d91..e5a50d9fca 100644
--- a/xen/arch/x86/hvm/hvm.c
+++ b/xen/arch/x86/hvm/hvm.c
@@ -1238,6 +1238,36 @@ static int cf_check hvm_save_cpu_xsave_states(
     return 0;
 }
 
+#define HVM_CPU_XSAVES_SIZE(xcr0) (offsetof(struct hvm_hw_cpu_xsave, \
+                                            save_area) + \
+                                   xstate_compressed_size(xcr0))
+
+static int cf_check hvm_save_cpu_xsaves_states(
+    struct vcpu *v, hvm_domain_context_t *h)
+{
+    struct hvm_hw_cpu_xsave *ctxt;
+    unsigned int size;
+    int err;
+
+    if ( !xsave_enabled(v) )
+        return 0;   /* do nothing */
+
+    size = HVM_CPU_XSAVES_SIZE(v->arch.xcr0_accum);
+    err = _hvm_init_entry(h, CPU_XSAVES_CODE, v->vcpu_id, size);
+    if ( err )
+        return err;
+
+    ctxt = (struct hvm_hw_cpu_xsave *)&h->data[h->cur];
+    h->cur += size;
+    ctxt->xfeature_mask = xfeature_mask;
+    ctxt->xcr0 = v->arch.xcr0;
+    ctxt->xcr0_accum = v->arch.xcr0_accum;
+
+    memcpy(&ctxt->save_area, v->arch.xsave_area, size);
+
+    return 0;
+}
+
 /*
  * Structure layout conformity checks, documenting correctness of the cast in
  * the invocation of validate_xstate() below.
@@ -1311,6 +1341,10 @@ static int cf_check hvm_load_cpu_xsave_states(
     ctxt = (struct hvm_hw_cpu_xsave *)&h->data[h->cur];
     h->cur += desc->length;
 
+    if ( !cpu_has_xsaves &&
+         xsave_area_compressed((const void *)&ctxt->save_area) )
+        return -EOPNOTSUPP;
+
     err = validate_xstate(d, ctxt->xcr0, ctxt->xcr0_accum,
                           (const void *)&ctxt->save_area.xsave_hdr);
     if ( err )
@@ -1322,7 +1356,10 @@ static int cf_check hvm_load_cpu_xsave_states(
                ctxt->xcr0, ctxt->save_area.xsave_hdr.xstate_bv, err);
         return err;
     }
-    size = HVM_CPU_XSAVE_SIZE(ctxt->xcr0_accum);
+    if ( xsave_area_compressed((const void *)&ctxt->save_area) )
+        size = HVM_CPU_XSAVES_SIZE(ctxt->xcr0_accum);
+    else
+        size = HVM_CPU_XSAVE_SIZE(ctxt->xcr0_accum);
     desc_length = desc->length;
     if ( desc_length > size )
     {
@@ -1348,14 +1385,7 @@ static int cf_check hvm_load_cpu_xsave_states(
         desc_length = size;
     }
 
-    if ( xsave_area_compressed((const void *)&ctxt->save_area) )
-    {
-        printk(XENLOG_G_WARNING
-               "HVM%d.%u restore: compressed xsave state not supported\n",
-               d->domain_id, vcpuid);
-        return -EOPNOTSUPP;
-    }
-    else if ( desc_length != size )
+    if ( desc_length != size )
     {
         printk(XENLOG_G_WARNING
                "HVM%d.%u restore mismatch: xsave length %#x != %#x\n",
@@ -1367,8 +1397,13 @@ static int cf_check hvm_load_cpu_xsave_states(
     v->arch.xcr0 = ctxt->xcr0;
     v->arch.xcr0_accum = ctxt->xcr0_accum;
     v->arch.nonlazy_xstate_used = ctxt->xcr0_accum & XSTATE_NONLAZY;
-    compress_xsave_states(v, &ctxt->save_area,
-                          size - offsetof(struct hvm_hw_cpu_xsave, save_area));
+    if ( xsave_area_compressed((const void *)&ctxt->save_area) )
+        memcpy(v->arch.xsave_area, &ctxt->save_area,
+               size - offsetof(struct hvm_hw_cpu_xsave, save_area));
+    else
+        compress_xsave_states(v, &ctxt->save_area,
+                              size - offsetof(struct hvm_hw_cpu_xsave,
+                                              save_area));
 
     return 0;
 }
@@ -1385,6 +1420,7 @@ static const uint32_t msrs_to_send[] = {
     MSR_AMD64_DR1_ADDRESS_MASK,
     MSR_AMD64_DR2_ADDRESS_MASK,
     MSR_AMD64_DR3_ADDRESS_MASK,
+    MSR_LBR_DEPTH,
 };
 
 static int cf_check hvm_save_cpu_msrs(struct vcpu *v, hvm_domain_context_t *h)
@@ -1572,6 +1608,15 @@ static int __init cf_check hvm_register_CPU_save_and_restore(void)
                             sizeof(struct hvm_save_descriptor),
                         HVMSR_PER_VCPU);
 
+    hvm_register_savevm(CPU_XSAVES_CODE,
+                        "CPU_XSAVES",
+                        hvm_save_cpu_xsaves_states,
+                        NULL,
+                        hvm_load_cpu_xsave_states,
+                        HVM_CPU_XSAVES_SIZE(xfeature_mask) +
+                            sizeof(struct hvm_save_descriptor),
+                        HVMSR_PER_VCPU);
+
     hvm_register_savevm(CPU_MSR_CODE,
                         "CPU_MSR",
                         hvm_save_cpu_msrs,
diff --git a/xen/arch/x86/xstate.c b/xen/arch/x86/xstate.c
index 607bf9c8a5..1c7a39e778 100644
--- a/xen/arch/x86/xstate.c
+++ b/xen/arch/x86/xstate.c
@@ -946,8 +946,7 @@ int validate_xstate(const struct domain *d, uint64_t xcr0, uint64_t xcr0_accum,
          !valid_xcr0(xcr0_accum) )
         return -EINVAL;
 
-    if ( (xcr0_accum & ~xfeature_mask) ||
-         hdr->xcomp_bv )
+    if ( xcr0_accum & ~xfeature_mask )
         return -EOPNOTSUPP;
 
     for ( i = 0; i < ARRAY_SIZE(hdr->reserved); ++i )
diff --git a/xen/include/public/arch-x86/hvm/save.h b/xen/include/public/arch-x86/hvm/save.h
index 7ecacadde1..89651f3dd3 100644
--- a/xen/include/public/arch-x86/hvm/save.h
+++ b/xen/include/public/arch-x86/hvm/save.h
@@ -624,12 +624,14 @@ struct hvm_msr {
 
 #define CPU_MSR_CODE  20
 
+#define CPU_XSAVES_CODE 21
+
 /* Range 22 - 34 (inclusive) reserved for Amazon */
 
 /*
  * Largest type-code in use
  */
-#define HVM_SAVE_CODE_MAX 20
+#define HVM_SAVE_CODE_MAX 21
 
 #endif /* __XEN_PUBLIC_HVM_SAVE_X86_H__ */
 
