x86: Reorganise and rename debug register fields in struct vcpu
authorAndrew Cooper <andrew.cooper3@citrix.com>
Mon, 28 May 2018 14:22:49 +0000 (15:22 +0100)
committerAndrew Cooper <andrew.cooper3@citrix.com>
Tue, 30 Oct 2018 13:26:21 +0000 (13:26 +0000)
Reusing debugreg[5] for the PV emulated IO breakpoint information is confusing
to read.  Instead, introduce a dr7_emul field in pv_vcpu for the purpose.

With the PV emulation out of the way, debugreg[4,5] are entirely unused and
don't need to be stored.

Rename debugreg[0..3] to dr[0..3] to reduce code volume, but keep them as an
array because their behaviour is identical and this helps simplfy some of the
PV handling.  Introduce dr6 and dr7 fields to replace debugreg[6,7] which
removes the storage for debugreg[4,5].

In arch_get_info_guest(), handle the merging of emulated dr7 state alongside
all other dr handling, rather than much later.

Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
Reviewed-by: Roger Pau Monné <roger.pau@citrix.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
Reviewed-by: Kevin Tian <kevin.tian@intel.com>
Reviewed-by: Boris Ostrovsky <boris.ostrovsky@oracle.com>
xen/arch/x86/domain.c
xen/arch/x86/domctl.c
xen/arch/x86/hvm/hvm.c
xen/arch/x86/hvm/svm/svm.c
xen/arch/x86/hvm/vmx/vmx.c
xen/arch/x86/pv/emul-priv-op.c
xen/arch/x86/pv/emulate.c
xen/arch/x86/traps.c
xen/arch/x86/vm_event.c
xen/arch/x86/x86_emulate.c
xen/include/asm-x86/domain.h

index 19692e2193ff6903bd521134e670f07faefbc9f9..943f95b676b274fa3613c3fbd652004521dca493 100644 (file)
@@ -329,9 +329,9 @@ void arch_vcpu_regs_init(struct vcpu *v)
     memset(&v->arch.user_regs, 0, sizeof(v->arch.user_regs));
     v->arch.user_regs.eflags = X86_EFLAGS_MBS;
 
-    memset(v->arch.debugreg, 0, sizeof(v->arch.debugreg));
-    v->arch.debugreg[6] = X86_DR6_DEFAULT;
-    v->arch.debugreg[7] = X86_DR7_DEFAULT;
+    memset(v->arch.dr, 0, sizeof(v->arch.dr));
+    v->arch.dr6 = X86_DR6_DEFAULT;
+    v->arch.dr7 = X86_DR7_DEFAULT;
 }
 
 int arch_vcpu_create(struct vcpu *v)
@@ -885,8 +885,10 @@ int arch_set_info_guest(
 
     if ( is_hvm_domain(d) )
     {
-        for ( i = 0; i < ARRAY_SIZE(v->arch.debugreg); ++i )
-            v->arch.debugreg[i] = c(debugreg[i]);
+        for ( i = 0; i < ARRAY_SIZE(v->arch.dr); ++i )
+            v->arch.dr[i] = c(debugreg[i]);
+        v->arch.dr6 = c(debugreg[6]);
+        v->arch.dr7 = c(debugreg[7]);
 
         hvm_set_info_guest(v);
         goto out;
@@ -974,9 +976,15 @@ int arch_set_info_guest(
     v->arch.pv.ctrlreg[4] = cr4 ? pv_guest_cr4_fixup(v, cr4) :
         real_cr4_to_pv_guest_cr4(mmu_cr4_features);
 
-    memset(v->arch.debugreg, 0, sizeof(v->arch.debugreg));
-    for ( i = 0; i < 8; i++ )
-        (void)set_debugreg(v, i, c(debugreg[i]));
+    memset(v->arch.dr, 0, sizeof(v->arch.dr));
+    v->arch.dr6 = X86_DR6_DEFAULT;
+    v->arch.dr7 = X86_DR7_DEFAULT;
+    v->arch.pv.dr7_emul = 0;
+
+    for ( i = 0; i < ARRAY_SIZE(v->arch.dr); i++ )
+        set_debugreg(v, i, c(debugreg[i]));
+    set_debugreg(v, 6, c(debugreg[6]));
+    set_debugreg(v, 7, c(debugreg[7]));
 
     if ( v->is_initialised )
         goto out;
@@ -1542,7 +1550,7 @@ void paravirt_ctxt_switch_from(struct vcpu *v)
      * inside Xen, before we get a chance to reload DR7, and this cannot always
      * safely be handled.
      */
-    if ( unlikely(v->arch.debugreg[7] & DR7_ACTIVE_MASK) )
+    if ( unlikely(v->arch.dr7 & DR7_ACTIVE_MASK) )
         write_debugreg(7, 0);
 }
 
@@ -1555,7 +1563,7 @@ void paravirt_ctxt_switch_to(struct vcpu *v)
             l4e_from_page(v->domain->arch.perdomain_l3_pg,
                           __PAGE_HYPERVISOR_RW);
 
-    if ( unlikely(v->arch.debugreg[7] & DR7_ACTIVE_MASK) )
+    if ( unlikely(v->arch.dr7 & DR7_ACTIVE_MASK) )
         activate_debugregs(v);
 
     if ( cpu_has_rdtscp )
index 115ddf6d1adebfd9762d91790626e1e28aaba209..cc85395e96f97e80d291d5789f2284c7e86b4ec3 100644 (file)
@@ -1576,8 +1576,11 @@ void arch_get_info_guest(struct vcpu *v, vcpu_guest_context_u c)
         }
     }
 
-    for ( i = 0; i < ARRAY_SIZE(v->arch.debugreg); ++i )
-        c(debugreg[i] = v->arch.debugreg[i]);
+    for ( i = 0; i < ARRAY_SIZE(v->arch.dr); ++i )
+        c(debugreg[i] = v->arch.dr[i]);
+    c(debugreg[6] = v->arch.dr6);
+    c(debugreg[7] = v->arch.dr7 |
+      (is_pv_domain(d) ? v->arch.pv.dr7_emul : 0));
 
     if ( is_hvm_domain(d) )
     {
@@ -1652,10 +1655,6 @@ void arch_get_info_guest(struct vcpu *v, vcpu_guest_context_u c)
             c.nat->ctrlreg[1] =
                 pagetable_is_null(v->arch.guest_table_user) ? 0
                 : xen_pfn_to_cr3(pagetable_get_pfn(v->arch.guest_table_user));
-
-            /* Merge shadow DR7 bits into real DR7. */
-            c.nat->debugreg[7] |= c.nat->debugreg[5];
-            c.nat->debugreg[5] = 0;
         }
         else
         {
@@ -1664,10 +1663,6 @@ void arch_get_info_guest(struct vcpu *v, vcpu_guest_context_u c)
 
             c.cmp->ctrlreg[3] = compat_pfn_to_cr3(l4e_get_pfn(*l4e));
             unmap_domain_page(l4e);
-
-            /* Merge shadow DR7 bits into real DR7. */
-            c.cmp->debugreg[7] |= c.cmp->debugreg[5];
-            c.cmp->debugreg[5] = 0;
         }
 
         if ( guest_kernel_mode(v, &v->arch.user_regs) )
index 225c62f8bae387d334a7eb4b2f3fdd0547f53113..42d7a9bd1b10f68d1bacd18509796d676eaa8184 100644 (file)
@@ -791,12 +791,12 @@ static int hvm_save_cpu_ctxt(struct vcpu *v, hvm_domain_context_t *h)
         .cr2 = v->arch.hvm.guest_cr[2],
         .cr3 = v->arch.hvm.guest_cr[3],
         .cr4 = v->arch.hvm.guest_cr[4],
-        .dr0 = v->arch.debugreg[0],
-        .dr1 = v->arch.debugreg[1],
-        .dr2 = v->arch.debugreg[2],
-        .dr3 = v->arch.debugreg[3],
-        .dr6 = v->arch.debugreg[6],
-        .dr7 = v->arch.debugreg[7],
+        .dr0 = v->arch.dr[0],
+        .dr1 = v->arch.dr[1],
+        .dr2 = v->arch.dr[2],
+        .dr3 = v->arch.dr[3],
+        .dr6 = v->arch.dr6,
+        .dr7 = v->arch.dr7,
         .msr_efer = v->arch.hvm.guest_efer,
     };
 
@@ -1117,12 +1117,12 @@ static int hvm_load_cpu_ctxt(struct domain *d, hvm_domain_context_t *h)
     v->arch.user_regs.r13 = ctxt.r13;
     v->arch.user_regs.r14 = ctxt.r14;
     v->arch.user_regs.r15 = ctxt.r15;
-    v->arch.debugreg[0] = ctxt.dr0;
-    v->arch.debugreg[1] = ctxt.dr1;
-    v->arch.debugreg[2] = ctxt.dr2;
-    v->arch.debugreg[3] = ctxt.dr3;
-    v->arch.debugreg[6] = ctxt.dr6;
-    v->arch.debugreg[7] = ctxt.dr7;
+    v->arch.dr[0] = ctxt.dr0;
+    v->arch.dr[1] = ctxt.dr1;
+    v->arch.dr[2] = ctxt.dr2;
+    v->arch.dr[3] = ctxt.dr3;
+    v->arch.dr6   = ctxt.dr6;
+    v->arch.dr7   = ctxt.dr7;
 
     v->arch.vgc_flags = VGCF_online;
 
index dd0aca4f53abe78954b1b112c4ed8f5ed769cf76..41427e7b9b2f90adac7c23486b302b7257f07984 100644 (file)
@@ -216,12 +216,12 @@ static void svm_save_dr(struct vcpu *v)
         rdmsrl(MSR_AMD64_DR3_ADDRESS_MASK, v->arch.hvm.svm.dr_mask[3]);
     }
 
-    v->arch.debugreg[0] = read_debugreg(0);
-    v->arch.debugreg[1] = read_debugreg(1);
-    v->arch.debugreg[2] = read_debugreg(2);
-    v->arch.debugreg[3] = read_debugreg(3);
-    v->arch.debugreg[6] = vmcb_get_dr6(vmcb);
-    v->arch.debugreg[7] = vmcb_get_dr7(vmcb);
+    v->arch.dr[0] = read_debugreg(0);
+    v->arch.dr[1] = read_debugreg(1);
+    v->arch.dr[2] = read_debugreg(2);
+    v->arch.dr[3] = read_debugreg(3);
+    v->arch.dr6   = vmcb_get_dr6(vmcb);
+    v->arch.dr7   = vmcb_get_dr7(vmcb);
 }
 
 static void __restore_debug_registers(struct vmcb_struct *vmcb, struct vcpu *v)
@@ -247,12 +247,12 @@ static void __restore_debug_registers(struct vmcb_struct *vmcb, struct vcpu *v)
         wrmsrl(MSR_AMD64_DR3_ADDRESS_MASK, v->arch.hvm.svm.dr_mask[3]);
     }
 
-    write_debugreg(0, v->arch.debugreg[0]);
-    write_debugreg(1, v->arch.debugreg[1]);
-    write_debugreg(2, v->arch.debugreg[2]);
-    write_debugreg(3, v->arch.debugreg[3]);
-    vmcb_set_dr6(vmcb, v->arch.debugreg[6]);
-    vmcb_set_dr7(vmcb, v->arch.debugreg[7]);
+    write_debugreg(0, v->arch.dr[0]);
+    write_debugreg(1, v->arch.dr[1]);
+    write_debugreg(2, v->arch.dr[2]);
+    write_debugreg(3, v->arch.dr[3]);
+    vmcb_set_dr6(vmcb, v->arch.dr6);
+    vmcb_set_dr7(vmcb, v->arch.dr7);
 }
 
 /*
@@ -264,7 +264,8 @@ static void __restore_debug_registers(struct vmcb_struct *vmcb, struct vcpu *v)
 static void svm_restore_dr(struct vcpu *v)
 {
     struct vmcb_struct *vmcb = v->arch.hvm.svm.vmcb;
-    if ( unlikely(v->arch.debugreg[7] & DR7_ACTIVE_MASK) )
+
+    if ( unlikely(v->arch.dr7 & DR7_ACTIVE_MASK) )
         __restore_debug_registers(vmcb, v);
 }
 
index 7a49075e858a7fc2f36ff37d9f816f4318d328bf..8d0e4b682c2651ba1fd4b71e21820e7ec49faa7f 100644 (file)
@@ -603,13 +603,13 @@ static void vmx_save_dr(struct vcpu *v)
     v->arch.hvm.vmx.exec_control |= CPU_BASED_MOV_DR_EXITING;
     vmx_update_cpu_exec_control(v);
 
-    v->arch.debugreg[0] = read_debugreg(0);
-    v->arch.debugreg[1] = read_debugreg(1);
-    v->arch.debugreg[2] = read_debugreg(2);
-    v->arch.debugreg[3] = read_debugreg(3);
-    v->arch.debugreg[6] = read_debugreg(6);
+    v->arch.dr[0] = read_debugreg(0);
+    v->arch.dr[1] = read_debugreg(1);
+    v->arch.dr[2] = read_debugreg(2);
+    v->arch.dr[3] = read_debugreg(3);
+    v->arch.dr6   = read_debugreg(6);
     /* DR7 must be saved as it is used by vmx_restore_dr(). */
-    __vmread(GUEST_DR7, &v->arch.debugreg[7]);
+    __vmread(GUEST_DR7, &v->arch.dr7);
 }
 
 static void __restore_debug_registers(struct vcpu *v)
@@ -619,11 +619,11 @@ static void __restore_debug_registers(struct vcpu *v)
 
     v->arch.hvm.flag_dr_dirty = 1;
 
-    write_debugreg(0, v->arch.debugreg[0]);
-    write_debugreg(1, v->arch.debugreg[1]);
-    write_debugreg(2, v->arch.debugreg[2]);
-    write_debugreg(3, v->arch.debugreg[3]);
-    write_debugreg(6, v->arch.debugreg[6]);
+    write_debugreg(0, v->arch.dr[0]);
+    write_debugreg(1, v->arch.dr[1]);
+    write_debugreg(2, v->arch.dr[2]);
+    write_debugreg(3, v->arch.dr[3]);
+    write_debugreg(6, v->arch.dr6);
     /* DR7 is loaded from the VMCS. */
 }
 
@@ -636,7 +636,7 @@ static void __restore_debug_registers(struct vcpu *v)
 static void vmx_restore_dr(struct vcpu *v)
 {
     /* NB. __vmread() is not usable here, so we cannot read from the VMCS. */
-    if ( unlikely(v->arch.debugreg[7] & DR7_ACTIVE_MASK) )
+    if ( unlikely(v->arch.dr7 & DR7_ACTIVE_MASK) )
         __restore_debug_registers(v);
 }
 
@@ -1917,7 +1917,7 @@ static void vmx_set_info_guest(struct vcpu *v)
 
     vmx_vmcs_enter(v);
 
-    __vmwrite(GUEST_DR7, v->arch.debugreg[7]);
+    __vmwrite(GUEST_DR7, v->arch.dr7);
 
     /* 
      * If the interruptibility-state field indicates blocking by STI,
index b85c65f5568488efd80e3da7c35e651e5b1d300c..aecf517cf0e8a9af1555cdf1adc4e5c0d69bca98 100644 (file)
@@ -286,19 +286,18 @@ static unsigned int check_guest_io_breakpoint(struct vcpu *v,
     unsigned int width, i, match = 0;
     unsigned long start;
 
-    if ( !(v->arch.debugreg[5]) || !(v->arch.pv.ctrlreg[4] & X86_CR4_DE) )
+    if ( !v->arch.pv.dr7_emul || !(v->arch.pv.ctrlreg[4] & X86_CR4_DE) )
         return 0;
 
     for ( i = 0; i < 4; i++ )
     {
-        if ( !(v->arch.debugreg[5] &
-               (3 << (i * DR_ENABLE_SIZE))) )
+        if ( !(v->arch.pv.dr7_emul & (3 << (i * DR_ENABLE_SIZE))) )
             continue;
 
-        start = v->arch.debugreg[i];
+        start = v->arch.dr[i];
         width = 0;
 
-        switch ( (v->arch.debugreg[7] >>
+        switch ( (v->arch.dr7 >>
                   (DR_CONTROL_SHIFT + i * DR_CONTROL_SIZE)) & 0xc )
         {
         case DR_LEN_1: width = 1; break;
@@ -1112,7 +1111,7 @@ static int write_msr(unsigned int reg, uint64_t val,
         if ( !boot_cpu_has(X86_FEATURE_DBEXT) || (val >> 32) )
             break;
         curr->arch.pv.dr_mask[0] = val;
-        if ( curr->arch.debugreg[7] & DR7_ACTIVE_MASK )
+        if ( curr->arch.dr7 & DR7_ACTIVE_MASK )
             wrmsrl(MSR_AMD64_DR0_ADDRESS_MASK, val);
         return X86EMUL_OKAY;
 
@@ -1120,7 +1119,7 @@ static int write_msr(unsigned int reg, uint64_t val,
         if ( !boot_cpu_has(X86_FEATURE_DBEXT) || (val >> 32) )
             break;
         curr->arch.pv.dr_mask[reg - MSR_AMD64_DR1_ADDRESS_MASK + 1] = val;
-        if ( curr->arch.debugreg[7] & DR7_ACTIVE_MASK )
+        if ( curr->arch.dr7 & DR7_ACTIVE_MASK )
             wrmsrl(reg, val);
         return X86EMUL_OKAY;
 
@@ -1361,7 +1360,7 @@ int pv_emulate_privileged_op(struct cpu_user_regs *regs)
             ctxt.bpmatch |= DR_STEP;
         if ( ctxt.bpmatch )
         {
-            curr->arch.debugreg[6] |= ctxt.bpmatch | DR_STATUS_RESERVED_ONE;
+            curr->arch.dr6 |= ctxt.bpmatch | DR_STATUS_RESERVED_ONE;
             if ( !(curr->arch.pv.trap_bounce.flags & TBF_EXCEPTION) )
                 pv_inject_hw_exception(TRAP_debug, X86_EVENT_NO_EC);
         }
index 1b609117a3a257637fef126c37702bf01050f346..757ffd159c78324a6b65a069232ad4e226bdab12 100644 (file)
@@ -78,7 +78,7 @@ void pv_emul_instruction_done(struct cpu_user_regs *regs, unsigned long rip)
     regs->eflags &= ~X86_EFLAGS_RF;
     if ( regs->eflags & X86_EFLAGS_TF )
     {
-        current->arch.debugreg[6] |= DR_STEP | DR_STATUS_RESERVED_ONE;
+        current->arch.dr6 |= DR_STEP | DR_STATUS_RESERVED_ONE;
         pv_inject_hw_exception(TRAP_debug, X86_EVENT_NO_EC);
     }
 }
index f834ae2b31312923d7f1f73b25a524c06838ae6c..9b532199a87e192f694f748057c42655be458f75 100644 (file)
@@ -1891,8 +1891,8 @@ void do_debug(struct cpu_user_regs *regs)
     }
 
     /* Save debug status register where guest OS can peek at it */
-    v->arch.debugreg[6] |= (dr6 & ~X86_DR6_DEFAULT);
-    v->arch.debugreg[6] &= (dr6 | ~X86_DR6_DEFAULT);
+    v->arch.dr6 |= (dr6 & ~X86_DR6_DEFAULT);
+    v->arch.dr6 &= (dr6 | ~X86_DR6_DEFAULT);
 
     pv_inject_hw_exception(TRAP_debug, X86_EVENT_NO_EC);
 }
@@ -2055,19 +2055,19 @@ void activate_debugregs(const struct vcpu *curr)
 {
     ASSERT(curr == current);
 
-    write_debugreg(0, curr->arch.debugreg[0]);
-    write_debugreg(1, curr->arch.debugreg[1]);
-    write_debugreg(2, curr->arch.debugreg[2]);
-    write_debugreg(3, curr->arch.debugreg[3]);
-    write_debugreg(6, curr->arch.debugreg[6]);
+    write_debugreg(0, curr->arch.dr[0]);
+    write_debugreg(1, curr->arch.dr[1]);
+    write_debugreg(2, curr->arch.dr[2]);
+    write_debugreg(3, curr->arch.dr[3]);
+    write_debugreg(6, curr->arch.dr6);
 
     /*
      * Avoid writing the subsequently getting replaced value when getting
      * called from set_debugreg() below. Eventual future callers will need
      * to take this into account.
      */
-    if ( curr->arch.debugreg[7] & DR7_ACTIVE_MASK )
-        write_debugreg(7, curr->arch.debugreg[7]);
+    if ( curr->arch.dr7 & DR7_ACTIVE_MASK )
+        write_debugreg(7, curr->arch.dr7);
 
     if ( boot_cpu_has(X86_FEATURE_DBEXT) )
     {
@@ -2094,6 +2094,7 @@ long set_debugreg(struct vcpu *v, unsigned int reg, unsigned long value)
         if ( !access_ok(value, sizeof(long)) )
             return -EPERM;
 
+        v->arch.dr[reg] = value;
         if ( v == curr )
         {
             switch ( reg )
@@ -2122,6 +2123,8 @@ long set_debugreg(struct vcpu *v, unsigned int reg, unsigned long value)
          */
         value &= ~DR_STATUS_RESERVED_ZERO; /* reserved bits => 0 */
         value |=  DR_STATUS_RESERVED_ONE;  /* reserved bits => 1 */
+
+        v->arch.dr6 = value;
         if ( v == curr )
             write_debugreg(6, value);
         break;
@@ -2164,8 +2167,7 @@ long set_debugreg(struct vcpu *v, unsigned int reg, unsigned long value)
                 }
             }
 
-            /* Guest DR5 is a handy stash for I/O intercept information. */
-            v->arch.debugreg[5] = io_enable;
+            v->arch.pv.dr7_emul = io_enable;
             value &= ~io_enable;
 
             /*
@@ -2173,14 +2175,14 @@ long set_debugreg(struct vcpu *v, unsigned int reg, unsigned long value)
              * debug registers at this point as they were not restored during
              * context switch.  Updating DR7 itself happens later.
              */
-            if ( (v == curr) &&
-                 !(v->arch.debugreg[7] & DR7_ACTIVE_MASK) )
+            if ( (v == curr) && !(v->arch.dr7 & DR7_ACTIVE_MASK) )
                 activate_debugregs(v);
         }
         else
             /* Zero the emulated controls if %dr7 isn't active. */
-            v->arch.debugreg[5] = 0;
+            v->arch.pv.dr7_emul = 0;
 
+        v->arch.dr7 = value;
         if ( v == curr )
             write_debugreg(7, value);
         break;
@@ -2189,7 +2191,6 @@ long set_debugreg(struct vcpu *v, unsigned int reg, unsigned long value)
         return -ENODEV;
     }
 
-    v->arch.debugreg[reg] = value;
     return 0;
 }
 
index 15de43c3e60f2c524a5669b198cc370aecd0af43..402f62d937d7abbff4b48119eafe7581a1b44e05 100644 (file)
@@ -156,7 +156,7 @@ void vm_event_fill_regs(vm_event_request_t *req)
     req->data.regs.x86.rflags = regs->rflags;
     req->data.regs.x86.rip    = regs->rip;
 
-    req->data.regs.x86.dr7 = curr->arch.debugreg[7];
+    req->data.regs.x86.dr7 = curr->arch.dr7;
     req->data.regs.x86.cr0 = curr->arch.hvm.guest_cr[0];
     req->data.regs.x86.cr2 = curr->arch.hvm.guest_cr[2];
     req->data.regs.x86.cr3 = curr->arch.hvm.guest_cr[3];
index e1153f76b252a1cfabdeef11a373c3f16045a938..886bd87e592121069170ddc55e125759dd7e8baf 100644 (file)
@@ -101,7 +101,7 @@ int x86emul_read_dr(unsigned int reg, unsigned long *val,
     switch ( reg )
     {
     case 0 ... 3:
-        *val = curr->arch.debugreg[reg];
+        *val = curr->arch.dr[reg];
         break;
 
     case 4:
@@ -110,7 +110,7 @@ int x86emul_read_dr(unsigned int reg, unsigned long *val,
 
         /* Fallthrough */
     case 6:
-        *val = curr->arch.debugreg[6];
+        *val = curr->arch.dr6;
         break;
 
     case 5:
@@ -119,8 +119,7 @@ int x86emul_read_dr(unsigned int reg, unsigned long *val,
 
         /* Fallthrough */
     case 7:
-        *val = (curr->arch.debugreg[7] |
-                curr->arch.debugreg[5]);
+        *val = curr->arch.dr7 | curr->arch.pv.dr7_emul;
         break;
 
     ud_fault:
index 503f8ff2deedc017f9af86b508287a9bd2f67df5..1a88cac08314b7038516a8748708f549d65f947d 100644 (file)
@@ -547,6 +547,12 @@ struct pv_vcpu
     spinlock_t shadow_ldt_lock;
 #endif
 
+    /*
+     * %dr7 bits the guest has set, but aren't loaded into hardware, and are
+     * completely emulated.
+     */
+    uint32_t dr7_emul;
+
     /* data breakpoint extension MSRs */
     uint32_t dr_mask[4];
 
@@ -565,7 +571,11 @@ struct arch_vcpu
     void              *fpu_ctxt;
     unsigned long      vgc_flags;
     struct cpu_user_regs user_regs;
-    unsigned long      debugreg[8];
+
+    /* Debug registers. */
+    unsigned long dr[4];
+    unsigned long dr7; /* Ideally int, but __vmread() needs long. */
+    unsigned int dr6;
 
     /* other state */