KVM: arm64: introduce vcpu->arch.debug_ptr
authorAlex Bennée <alex.bennee@linaro.org>
Tue, 7 Jul 2015 16:30:00 +0000 (17:30 +0100)
committerMarc Zyngier <marc.zyngier@arm.com>
Tue, 21 Jul 2015 11:50:25 +0000 (12:50 +0100)
This introduces a level of indirection for the debug registers. Instead
of using the sys_regs[] directly we store registers in a structure in
the vcpu. The new kvm_arm_reset_debug_ptr() sets the debug ptr to the
guest context.

Because we no longer give the sys_regs offset for the sys_reg_desc->reg
field, but instead the index into a debug-specific struct we need to
add a number of additional trap functions for each register. Also as the
generic generic user-space access code no longer works we have
introduced a new pair of function pointers to the sys_reg_desc structure
to override the generic code when needed.

Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
arch/arm/include/asm/kvm_host.h
arch/arm/kvm/arm.c
arch/arm64/include/asm/kvm_asm.h
arch/arm64/include/asm/kvm_host.h
arch/arm64/kernel/asm-offsets.c
arch/arm64/kvm/debug.c
arch/arm64/kvm/hyp.S
arch/arm64/kvm/sys_regs.c
arch/arm64/kvm/sys_regs.h

index 2b0bc8c5755288eae965cbad806f2b740c9526e2..dcba0fa5176e990f8a23333f08e34e192351b407 100644 (file)
@@ -234,5 +234,6 @@ static inline void kvm_arch_sched_in(struct kvm_vcpu *vcpu, int cpu) {}
 static inline void kvm_arm_init_debug(void) {}
 static inline void kvm_arm_setup_debug(struct kvm_vcpu *vcpu) {}
 static inline void kvm_arm_clear_debug(struct kvm_vcpu *vcpu) {}
+static inline void kvm_arm_reset_debug_ptr(struct kvm_vcpu *vcpu) {}
 
 #endif /* __ARM_KVM_HOST_H__ */
index 77151b111d32d3f6c00b6d7fd2e4516a0fb59211..9ce5cf02ed178a55894aefd70c7b8da92407afa7 100644 (file)
@@ -278,6 +278,8 @@ int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu)
        /* Set up the timer */
        kvm_timer_vcpu_init(vcpu);
 
+       kvm_arm_reset_debug_ptr(vcpu);
+
        return 0;
 }
 
index f5e40dae291ab2c20a6af7a98b154bc74af627f5..67fa0de3d48324cc19a06871904f619189ed27da 100644 (file)
 #define        CNTKCTL_EL1     20      /* Timer Control Register (EL1) */
 #define        PAR_EL1         21      /* Physical Address Register */
 #define MDSCR_EL1      22      /* Monitor Debug System Control Register */
-#define DBGBCR0_EL1    23      /* Debug Breakpoint Control Registers (0-15) */
-#define DBGBCR15_EL1   38
-#define DBGBVR0_EL1    39      /* Debug Breakpoint Value Registers (0-15) */
-#define DBGBVR15_EL1   54
-#define DBGWCR0_EL1    55      /* Debug Watchpoint Control Registers (0-15) */
-#define DBGWCR15_EL1   70
-#define DBGWVR0_EL1    71      /* Debug Watchpoint Value Registers (0-15) */
-#define DBGWVR15_EL1   86
-#define MDCCINT_EL1    87      /* Monitor Debug Comms Channel Interrupt Enable Reg */
+#define MDCCINT_EL1    23      /* Monitor Debug Comms Channel Interrupt Enable Reg */
 
 /* 32bit specific registers. Keep them at the end of the range */
-#define        DACR32_EL2      88      /* Domain Access Control Register */
-#define        IFSR32_EL2      89      /* Instruction Fault Status Register */
-#define        FPEXC32_EL2     90      /* Floating-Point Exception Control Register */
-#define        DBGVCR32_EL2    91      /* Debug Vector Catch Register */
-#define        TEECR32_EL1     92      /* ThumbEE Configuration Register */
-#define        TEEHBR32_EL1    93      /* ThumbEE Handler Base Register */
-#define        NR_SYS_REGS     94
+#define        DACR32_EL2      24      /* Domain Access Control Register */
+#define        IFSR32_EL2      25      /* Instruction Fault Status Register */
+#define        FPEXC32_EL2     26      /* Floating-Point Exception Control Register */
+#define        DBGVCR32_EL2    27      /* Debug Vector Catch Register */
+#define        TEECR32_EL1     28      /* ThumbEE Configuration Register */
+#define        TEEHBR32_EL1    29      /* ThumbEE Handler Base Register */
+#define        NR_SYS_REGS     30
 
 /* 32bit mapping */
 #define c0_MPIDR       (MPIDR_EL1 * 2) /* MultiProcessor ID Register */
index cfb675466e86c32664810c9e2fcbe636d58fecb9..9b99402b14df08b8f5906580da7dfe92df4533aa 100644 (file)
@@ -108,11 +108,25 @@ struct kvm_vcpu_arch {
        /* Exception Information */
        struct kvm_vcpu_fault_info fault;
 
-       /* Debug state */
+       /* Guest debug state */
        u64 debug_flags;
 
+       /*
+        * We maintain more than a single set of debug registers to support
+        * debugging the guest from the host and to maintain separate host and
+        * guest state during world switches. vcpu_debug_state are the debug
+        * registers of the vcpu as the guest sees them.  host_debug_state are
+        * the host registers which are saved and restored during world switches.
+        *
+        * debug_ptr points to the set of debug registers that should be loaded
+        * onto the hardware when running the guest.
+        */
+       struct kvm_guest_debug_arch *debug_ptr;
+       struct kvm_guest_debug_arch vcpu_debug_state;
+
        /* Pointer to host CPU context */
        kvm_cpu_context_t *host_cpu_context;
+       struct kvm_guest_debug_arch host_debug_state;
 
        /* VGIC state */
        struct vgic_cpu vgic_cpu;
@@ -242,5 +256,6 @@ static inline void kvm_arch_sched_in(struct kvm_vcpu *vcpu, int cpu) {}
 void kvm_arm_init_debug(void);
 void kvm_arm_setup_debug(struct kvm_vcpu *vcpu);
 void kvm_arm_clear_debug(struct kvm_vcpu *vcpu);
+void kvm_arm_reset_debug_ptr(struct kvm_vcpu *vcpu);
 
 #endif /* __ARM64_KVM_HOST_H__ */
index 5c900d49b90683ebd6f684a6663761d543c2842c..d88630899a2423bf6fb93465f0ed85282da80b2d 100644 (file)
@@ -116,10 +116,16 @@ int main(void)
   DEFINE(VCPU_FAR_EL2,         offsetof(struct kvm_vcpu, arch.fault.far_el2));
   DEFINE(VCPU_HPFAR_EL2,       offsetof(struct kvm_vcpu, arch.fault.hpfar_el2));
   DEFINE(VCPU_DEBUG_FLAGS,     offsetof(struct kvm_vcpu, arch.debug_flags));
+  DEFINE(VCPU_DEBUG_PTR,       offsetof(struct kvm_vcpu, arch.debug_ptr));
+  DEFINE(DEBUG_BCR,            offsetof(struct kvm_guest_debug_arch, dbg_bcr));
+  DEFINE(DEBUG_BVR,            offsetof(struct kvm_guest_debug_arch, dbg_bvr));
+  DEFINE(DEBUG_WCR,            offsetof(struct kvm_guest_debug_arch, dbg_wcr));
+  DEFINE(DEBUG_WVR,            offsetof(struct kvm_guest_debug_arch, dbg_wvr));
   DEFINE(VCPU_HCR_EL2,         offsetof(struct kvm_vcpu, arch.hcr_el2));
   DEFINE(VCPU_MDCR_EL2,        offsetof(struct kvm_vcpu, arch.mdcr_el2));
   DEFINE(VCPU_IRQ_LINES,       offsetof(struct kvm_vcpu, arch.irq_lines));
   DEFINE(VCPU_HOST_CONTEXT,    offsetof(struct kvm_vcpu, arch.host_cpu_context));
+  DEFINE(VCPU_HOST_DEBUG_STATE, offsetof(struct kvm_vcpu, arch.host_debug_state));
   DEFINE(VCPU_TIMER_CNTV_CTL,  offsetof(struct kvm_vcpu, arch.timer_cpu.cntv_ctl));
   DEFINE(VCPU_TIMER_CNTV_CVAL, offsetof(struct kvm_vcpu, arch.timer_cpu.cntv_cval));
   DEFINE(KVM_TIMER_CNTVOFF,    offsetof(struct kvm, arch.timer.cntvoff));
index d439eb8f3239ecaab16abc29a30d23f03cc9bc01..e0947b77faaab4ca39eba43be2766c0d60a4c961 100644 (file)
@@ -66,6 +66,15 @@ void kvm_arm_init_debug(void)
        __this_cpu_write(mdcr_el2, kvm_call_hyp(__kvm_get_mdcr_el2));
 }
 
+/**
+ * kvm_arm_reset_debug_ptr - reset the debug ptr to point to the vcpu state
+ */
+
+void kvm_arm_reset_debug_ptr(struct kvm_vcpu *vcpu)
+{
+       vcpu->arch.debug_ptr = &vcpu->arch.vcpu_debug_state;
+}
+
 /**
  * kvm_arm_setup_debug - set up debug related stuff
  *
index 8264f5b4817c63c0befa5e256124051a5b07f190..d93c0a23630e65eeb704da5a8e23d44e7de14a99 100644 (file)
@@ -596,6 +596,7 @@ __restore_sysregs:
 /* Save debug state */
 __save_debug:
        // x2: ptr to CPU context
+       // x3: ptr to debug reg struct
        // x4/x5/x6-22/x24-26: trashed
 
        mrs     x26, id_aa64dfr0_el1
@@ -606,15 +607,15 @@ __save_debug:
        sub     w25, w26, w25           // How many WPs to skip
 
        mov     x5, x24
-       add     x4, x2, #CPU_SYSREG_OFFSET(DBGBCR0_EL1)
+       add     x4, x3, #DEBUG_BCR
        save_debug dbgbcr
-       add     x4, x2, #CPU_SYSREG_OFFSET(DBGBVR0_EL1)
+       add     x4, x3, #DEBUG_BVR
        save_debug dbgbvr
 
        mov     x5, x25
-       add     x4, x2, #CPU_SYSREG_OFFSET(DBGWCR0_EL1)
+       add     x4, x3, #DEBUG_WCR
        save_debug dbgwcr
-       add     x4, x2, #CPU_SYSREG_OFFSET(DBGWVR0_EL1)
+       add     x4, x3, #DEBUG_WVR
        save_debug dbgwvr
 
        mrs     x21, mdccint_el1
@@ -624,6 +625,7 @@ __save_debug:
 /* Restore debug state */
 __restore_debug:
        // x2: ptr to CPU context
+       // x3: ptr to debug reg struct
        // x4/x5/x6-22/x24-26: trashed
 
        mrs     x26, id_aa64dfr0_el1
@@ -634,15 +636,15 @@ __restore_debug:
        sub     w25, w26, w25           // How many WPs to skip
 
        mov     x5, x24
-       add     x4, x2, #CPU_SYSREG_OFFSET(DBGBCR0_EL1)
+       add     x4, x3, #DEBUG_BCR
        restore_debug dbgbcr
-       add     x4, x2, #CPU_SYSREG_OFFSET(DBGBVR0_EL1)
+       add     x4, x3, #DEBUG_BVR
        restore_debug dbgbvr
 
        mov     x5, x25
-       add     x4, x2, #CPU_SYSREG_OFFSET(DBGWCR0_EL1)
+       add     x4, x3, #DEBUG_WCR
        restore_debug dbgwcr
-       add     x4, x2, #CPU_SYSREG_OFFSET(DBGWVR0_EL1)
+       add     x4, x3, #DEBUG_WVR
        restore_debug dbgwvr
 
        ldr     x21, [x2, #CPU_SYSREG_OFFSET(MDCCINT_EL1)]
@@ -682,6 +684,7 @@ ENTRY(__kvm_vcpu_run)
        bl __save_sysregs
 
        compute_debug_state 1f
+       add     x3, x0, #VCPU_HOST_DEBUG_STATE
        bl      __save_debug
 1:
        activate_traps
@@ -697,6 +700,8 @@ ENTRY(__kvm_vcpu_run)
        bl __restore_fpsimd
 
        skip_debug_state x3, 1f
+       ldr     x3, [x0, #VCPU_DEBUG_PTR]
+       kern_hyp_va x3
        bl      __restore_debug
 1:
        restore_guest_32bit_state
@@ -717,6 +722,8 @@ __kvm_vcpu_return:
        bl __save_sysregs
 
        skip_debug_state x3, 1f
+       ldr     x3, [x0, #VCPU_DEBUG_PTR]
+       kern_hyp_va x3
        bl      __save_debug
 1:
        save_guest_32bit_state
@@ -739,6 +746,7 @@ __kvm_vcpu_return:
        // already been saved. Note that we nuke the whole 64bit word.
        // If we ever add more flags, we'll have to be more careful...
        str     xzr, [x0, #VCPU_DEBUG_FLAGS]
+       add     x3, x0, #VCPU_HOST_DEBUG_STATE
        bl      __restore_debug
 1:
        restore_host_regs
index c370b4014799697c292a99cf24721a425fcb3790..158bae7c52cc46a0bbace8407087b6110ac67c14 100644 (file)
@@ -211,6 +211,203 @@ static bool trap_debug_regs(struct kvm_vcpu *vcpu,
        return true;
 }
 
+/*
+ * reg_to_dbg/dbg_to_reg
+ *
+ * A 32 bit write to a debug register leave top bits alone
+ * A 32 bit read from a debug register only returns the bottom bits
+ *
+ * All writes will set the KVM_ARM64_DEBUG_DIRTY flag to ensure the
+ * hyp.S code switches between host and guest values in future.
+ */
+static inline void reg_to_dbg(struct kvm_vcpu *vcpu,
+                             const struct sys_reg_params *p,
+                             u64 *dbg_reg)
+{
+       u64 val = *vcpu_reg(vcpu, p->Rt);
+
+       if (p->is_32bit) {
+               val &= 0xffffffffUL;
+               val |= ((*dbg_reg >> 32) << 32);
+       }
+
+       *dbg_reg = val;
+       vcpu->arch.debug_flags |= KVM_ARM64_DEBUG_DIRTY;
+}
+
+static inline void dbg_to_reg(struct kvm_vcpu *vcpu,
+                             const struct sys_reg_params *p,
+                             u64 *dbg_reg)
+{
+       u64 val = *dbg_reg;
+
+       if (p->is_32bit)
+               val &= 0xffffffffUL;
+
+       *vcpu_reg(vcpu, p->Rt) = val;
+}
+
+static inline bool trap_bvr(struct kvm_vcpu *vcpu,
+                           const struct sys_reg_params *p,
+                           const struct sys_reg_desc *rd)
+{
+       u64 *dbg_reg = &vcpu->arch.vcpu_debug_state.dbg_bvr[rd->reg];
+
+       if (p->is_write)
+               reg_to_dbg(vcpu, p, dbg_reg);
+       else
+               dbg_to_reg(vcpu, p, dbg_reg);
+
+       return true;
+}
+
+static int set_bvr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
+               const struct kvm_one_reg *reg, void __user *uaddr)
+{
+       __u64 *r = &vcpu->arch.vcpu_debug_state.dbg_bvr[rd->reg];
+
+       if (copy_from_user(uaddr, r, KVM_REG_SIZE(reg->id)) != 0)
+               return -EFAULT;
+       return 0;
+}
+
+static int get_bvr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
+       const struct kvm_one_reg *reg, void __user *uaddr)
+{
+       __u64 *r = &vcpu->arch.vcpu_debug_state.dbg_bvr[rd->reg];
+
+       if (copy_to_user(uaddr, r, KVM_REG_SIZE(reg->id)) != 0)
+               return -EFAULT;
+       return 0;
+}
+
+static inline void reset_bvr(struct kvm_vcpu *vcpu,
+                            const struct sys_reg_desc *rd)
+{
+       vcpu->arch.vcpu_debug_state.dbg_bvr[rd->reg] = rd->val;
+}
+
+static inline bool trap_bcr(struct kvm_vcpu *vcpu,
+                           const struct sys_reg_params *p,
+                           const struct sys_reg_desc *rd)
+{
+       u64 *dbg_reg = &vcpu->arch.vcpu_debug_state.dbg_bcr[rd->reg];
+
+       if (p->is_write)
+               reg_to_dbg(vcpu, p, dbg_reg);
+       else
+               dbg_to_reg(vcpu, p, dbg_reg);
+
+       return true;
+}
+
+static int set_bcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
+               const struct kvm_one_reg *reg, void __user *uaddr)
+{
+       __u64 *r = &vcpu->arch.vcpu_debug_state.dbg_bcr[rd->reg];
+
+       if (copy_from_user(uaddr, r, KVM_REG_SIZE(reg->id)) != 0)
+               return -EFAULT;
+
+       return 0;
+}
+
+static int get_bcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
+       const struct kvm_one_reg *reg, void __user *uaddr)
+{
+       __u64 *r = &vcpu->arch.vcpu_debug_state.dbg_bcr[rd->reg];
+
+       if (copy_to_user(uaddr, r, KVM_REG_SIZE(reg->id)) != 0)
+               return -EFAULT;
+       return 0;
+}
+
+static inline void reset_bcr(struct kvm_vcpu *vcpu,
+                            const struct sys_reg_desc *rd)
+{
+       vcpu->arch.vcpu_debug_state.dbg_bcr[rd->reg] = rd->val;
+}
+
+static inline bool trap_wvr(struct kvm_vcpu *vcpu,
+                           const struct sys_reg_params *p,
+                           const struct sys_reg_desc *rd)
+{
+       u64 *dbg_reg = &vcpu->arch.vcpu_debug_state.dbg_wvr[rd->reg];
+
+       if (p->is_write)
+               reg_to_dbg(vcpu, p, dbg_reg);
+       else
+               dbg_to_reg(vcpu, p, dbg_reg);
+
+       return true;
+}
+
+static int set_wvr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
+               const struct kvm_one_reg *reg, void __user *uaddr)
+{
+       __u64 *r = &vcpu->arch.vcpu_debug_state.dbg_wvr[rd->reg];
+
+       if (copy_from_user(uaddr, r, KVM_REG_SIZE(reg->id)) != 0)
+               return -EFAULT;
+       return 0;
+}
+
+static int get_wvr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
+       const struct kvm_one_reg *reg, void __user *uaddr)
+{
+       __u64 *r = &vcpu->arch.vcpu_debug_state.dbg_wvr[rd->reg];
+
+       if (copy_to_user(uaddr, r, KVM_REG_SIZE(reg->id)) != 0)
+               return -EFAULT;
+       return 0;
+}
+
+static inline void reset_wvr(struct kvm_vcpu *vcpu,
+                            const struct sys_reg_desc *rd)
+{
+       vcpu->arch.vcpu_debug_state.dbg_wvr[rd->reg] = rd->val;
+}
+
+static inline bool trap_wcr(struct kvm_vcpu *vcpu,
+                           const struct sys_reg_params *p,
+                           const struct sys_reg_desc *rd)
+{
+       u64 *dbg_reg = &vcpu->arch.vcpu_debug_state.dbg_wcr[rd->reg];
+
+       if (p->is_write)
+               reg_to_dbg(vcpu, p, dbg_reg);
+       else
+               dbg_to_reg(vcpu, p, dbg_reg);
+
+       return true;
+}
+
+static int set_wcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
+               const struct kvm_one_reg *reg, void __user *uaddr)
+{
+       __u64 *r = &vcpu->arch.vcpu_debug_state.dbg_wcr[rd->reg];
+
+       if (copy_from_user(uaddr, r, KVM_REG_SIZE(reg->id)) != 0)
+               return -EFAULT;
+       return 0;
+}
+
+static int get_wcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
+       const struct kvm_one_reg *reg, void __user *uaddr)
+{
+       __u64 *r = &vcpu->arch.vcpu_debug_state.dbg_wcr[rd->reg];
+
+       if (copy_to_user(uaddr, r, KVM_REG_SIZE(reg->id)) != 0)
+               return -EFAULT;
+       return 0;
+}
+
+static inline void reset_wcr(struct kvm_vcpu *vcpu,
+                            const struct sys_reg_desc *rd)
+{
+       vcpu->arch.vcpu_debug_state.dbg_wcr[rd->reg] = rd->val;
+}
+
 static void reset_amair_el1(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
 {
        u64 amair;
@@ -240,16 +437,16 @@ static void reset_mpidr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
 #define DBG_BCR_BVR_WCR_WVR_EL1(n)                                     \
        /* DBGBVRn_EL1 */                                               \
        { Op0(0b10), Op1(0b000), CRn(0b0000), CRm((n)), Op2(0b100),     \
-         trap_debug_regs, reset_val, (DBGBVR0_EL1 + (n)), 0 },         \
+         trap_bvr, reset_bvr, n, 0, get_bvr, set_bvr },                \
        /* DBGBCRn_EL1 */                                               \
        { Op0(0b10), Op1(0b000), CRn(0b0000), CRm((n)), Op2(0b101),     \
-         trap_debug_regs, reset_val, (DBGBCR0_EL1 + (n)), 0 },         \
+         trap_bcr, reset_bcr, n, 0, get_bcr, set_bcr },                \
        /* DBGWVRn_EL1 */                                               \
        { Op0(0b10), Op1(0b000), CRn(0b0000), CRm((n)), Op2(0b110),     \
-         trap_debug_regs, reset_val, (DBGWVR0_EL1 + (n)), 0 },         \
+         trap_wvr, reset_wvr, n, 0,  get_wvr, set_wvr },               \
        /* DBGWCRn_EL1 */                                               \
        { Op0(0b10), Op1(0b000), CRn(0b0000), CRm((n)), Op2(0b111),     \
-         trap_debug_regs, reset_val, (DBGWCR0_EL1 + (n)), 0 }
+         trap_wcr, reset_wcr, n, 0,  get_wcr, set_wcr }
 
 /*
  * Architected system registers.
@@ -516,28 +713,55 @@ static bool trap_debug32(struct kvm_vcpu *vcpu,
        return true;
 }
 
-#define DBG_BCR_BVR_WCR_WVR(n)                                 \
-       /* DBGBVRn */                                           \
-       { Op1( 0), CRn( 0), CRm((n)), Op2( 4), trap_debug32,    \
-         NULL, (cp14_DBGBVR0 + (n) * 2) },                     \
-       /* DBGBCRn */                                           \
-       { Op1( 0), CRn( 0), CRm((n)), Op2( 5), trap_debug32,    \
-         NULL, (cp14_DBGBCR0 + (n) * 2) },                     \
-       /* DBGWVRn */                                           \
-       { Op1( 0), CRn( 0), CRm((n)), Op2( 6), trap_debug32,    \
-         NULL, (cp14_DBGWVR0 + (n) * 2) },                     \
-       /* DBGWCRn */                                           \
-       { Op1( 0), CRn( 0), CRm((n)), Op2( 7), trap_debug32,    \
-         NULL, (cp14_DBGWCR0 + (n) * 2) }
-
-#define DBGBXVR(n)                                             \
-       { Op1( 0), CRn( 1), CRm((n)), Op2( 1), trap_debug32,    \
-         NULL, cp14_DBGBXVR0 + n * 2 }
+/* AArch32 debug register mappings
+ *
+ * AArch32 DBGBVRn is mapped to DBGBVRn_EL1[31:0]
+ * AArch32 DBGBXVRn is mapped to DBGBVRn_EL1[63:32]
+ *
+ * All control registers and watchpoint value registers are mapped to
+ * the lower 32 bits of their AArch64 equivalents. We share the trap
+ * handlers with the above AArch64 code which checks what mode the
+ * system is in.
+ */
+
+static inline bool trap_xvr(struct kvm_vcpu *vcpu,
+                           const struct sys_reg_params *p,
+                           const struct sys_reg_desc *rd)
+{
+       u64 *dbg_reg = &vcpu->arch.vcpu_debug_state.dbg_bvr[rd->reg];
+
+       if (p->is_write) {
+               u64 val = *dbg_reg;
+
+               val &= 0xffffffffUL;
+               val |= *vcpu_reg(vcpu, p->Rt) << 32;
+               *dbg_reg = val;
+
+               vcpu->arch.debug_flags |= KVM_ARM64_DEBUG_DIRTY;
+       } else {
+               *vcpu_reg(vcpu, p->Rt) = *dbg_reg >> 32;
+       }
+
+       return true;
+}
+
+#define DBG_BCR_BVR_WCR_WVR(n)                                         \
+       /* DBGBVRn */                                                   \
+       { Op1( 0), CRn( 0), CRm((n)), Op2( 4), trap_bvr, NULL, n },     \
+       /* DBGBCRn */                                                   \
+       { Op1( 0), CRn( 0), CRm((n)), Op2( 5), trap_bcr, NULL, n },     \
+       /* DBGWVRn */                                                   \
+       { Op1( 0), CRn( 0), CRm((n)), Op2( 6), trap_wvr, NULL, n },     \
+       /* DBGWCRn */                                                   \
+       { Op1( 0), CRn( 0), CRm((n)), Op2( 7), trap_wcr, NULL, n }
+
+#define DBGBXVR(n)                                                     \
+       { Op1( 0), CRn( 1), CRm((n)), Op2( 1), trap_xvr, NULL, n }
 
 /*
  * Trapped cp14 registers. We generally ignore most of the external
  * debug, on the principle that they don't really make sense to a
- * guest. Revisit this one day, whould this principle change.
+ * guest. Revisit this one day, would this principle change.
  */
 static const struct sys_reg_desc cp14_regs[] = {
        /* DBGIDR */
@@ -1303,6 +1527,9 @@ int kvm_arm_sys_reg_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg
        if (!r)
                return get_invariant_sys_reg(reg->id, uaddr);
 
+       if (r->get_user)
+               return (r->get_user)(vcpu, r, reg, uaddr);
+
        return reg_to_user(uaddr, &vcpu_sys_reg(vcpu, r->reg), reg->id);
 }
 
@@ -1321,6 +1548,9 @@ int kvm_arm_sys_reg_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg
        if (!r)
                return set_invariant_sys_reg(reg->id, uaddr);
 
+       if (r->set_user)
+               return (r->set_user)(vcpu, r, reg, uaddr);
+
        return reg_from_user(&vcpu_sys_reg(vcpu, r->reg), uaddr, reg->id);
 }
 
index d411e251412c316bb28b7d971b4dbc0c6e996ee3..eaa324e4db4da1149adfe7ae012b895353f05e91 100644 (file)
@@ -55,6 +55,12 @@ struct sys_reg_desc {
 
        /* Value (usually reset value) */
        u64 val;
+
+       /* Custom get/set_user functions, fallback to generic if NULL */
+       int (*get_user)(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
+                       const struct kvm_one_reg *reg, void __user *uaddr);
+       int (*set_user)(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
+                       const struct kvm_one_reg *reg, void __user *uaddr);
 };
 
 static inline void print_sys_reg_instr(const struct sys_reg_params *p)