[Android-virt] [PATCH] arm: kvm: Fix register sync and some GDB support

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

 



From: Christoffer Dall <c.dall at virtualopensystems.com>

The register copies between the kernel and QEMU did not properly
consider QEMUs mode of putting all current registers in a given array
regardless of the mode and at the same time having banked registers for
the same registers. With this commit we should be sure to be in sync
always.

Also introduces a little bit of GDB support. QEMU does indeed translate
virtual addresses to physical by reading guest memory directly in order
to access guest memory for debugging, so guest LPAE support with GDB
would rely on having the LPAE page table format supported in QEMU.

Signed-off-by: Christoffer Dall <c.dall at virtualopensystems.com>
---
 gdbstub.c           |    1 +
 target-arm/cpu.h    |    1 +
 target-arm/helper.c |    2 +
 target-arm/kvm.c    |   72 ++++++++++++++++++++++++++++++++++++++++++++++++++-
 4 files changed, 74 insertions(+), 2 deletions(-)

diff --git a/gdbstub.c b/gdbstub.c
index 7d470b6..bdc1c85 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -1913,6 +1913,7 @@ static void gdb_set_cpu_pc(GDBState *s, target_ulong pc)
     s->c_cpu->pc = pc;
     s->c_cpu->npc = pc + 4;
 #elif defined (TARGET_ARM)
+    cpu_synchronize_state(s->c_cpu);
     s->c_cpu->regs[15] = pc;
 #elif defined (TARGET_SH4)
     s->c_cpu->pc = pc;
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index d19e6c4..2e8f705 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -247,6 +247,7 @@ void arm_translate_init(void);
 int cpu_arm_exec(CPUARMState *s);
 void cpu_arm_close(CPUARMState *s);
 void do_interrupt(CPUARMState *);
+int bank_number(CPUState *env, int mode);
 void switch_mode(CPUARMState *, int);
 uint32_t do_arm_semihosting(CPUARMState *env);
 
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 6e5c3e8..9051dde 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -715,7 +715,7 @@ uint32_t HELPER(get_r13_banked)(CPUState *env, uint32_t mode)
 #else
 
 /* Map CPU modes onto saved register banks.  */
-static inline int bank_number(CPUState *env, int mode)
+int bank_number(CPUState *env, int mode)
 {
     switch (mode) {
     case ARM_CPU_MODE_USR:
diff --git a/target-arm/kvm.c b/target-arm/kvm.c
index f0899f6..ca85724 100644
--- a/target-arm/kvm.c
+++ b/target-arm/kvm.c
@@ -40,12 +40,25 @@ int kvm_arch_init_vcpu(CPUState *env)
 int kvm_arch_put_registers(CPUState *env, int level)
 {
     struct kvm_regs regs;
+    int mode, bn;
     int ret;
 
     ret = kvm_vcpu_ioctl(env, KVM_GET_REGS, &regs);
     if (ret < 0)
         return ret;
 
+    /* We make sure the banked regs are properly set */
+    mode = env->uncached_cpsr & CPSR_M;
+    bn = bank_number(env, mode);
+    if (mode == ARM_CPU_MODE_FIQ)
+        memcpy(env->fiq_regs, env->regs + 8, 5 * sizeof(uint32_t));
+    else
+        memcpy(env->usr_regs, env->regs + 8, 5 * sizeof(uint32_t));
+    env->banked_r13[bn] = env->regs[13];
+    env->banked_r14[bn] = env->regs[14];
+    env->banked_spsr[bn] = env->spsr;
+
+    /* Now we can safely copy stuff down to the kernel */
     memcpy(regs.regs0_7, env->regs, sizeof(uint32_t) * 8);
     memcpy(regs.usr_regs8_12, env->usr_regs, sizeof(uint32_t) * 5);
     memcpy(regs.fiq_regs8_12, env->fiq_regs, sizeof(uint32_t) * 5);
@@ -80,14 +93,19 @@ int kvm_arch_put_registers(CPUState *env, int level)
 int kvm_arch_get_registers(CPUState *env)
 {
     struct kvm_regs regs;
+    int mode, bn;
     int32_t ret;
 
     ret = kvm_vcpu_ioctl(env, KVM_GET_REGS, &regs);
     if (ret < 0)
         return ret;
+
+    /* First, let's transfer the banked state */
+    cpsr_write(env, regs.cpsr, 0xFFFFFFFF);
     memcpy(env->regs, regs.regs0_7, sizeof(uint32_t) * 8);
     memcpy(env->usr_regs, regs.usr_regs8_12, sizeof(uint32_t) * 5);
     memcpy(env->fiq_regs, regs.fiq_regs8_12, sizeof(uint32_t) * 5);
+
     env->banked_r13[5] = regs.reg13[MODE_FIQ];
     env->banked_r13[4] = regs.reg13[MODE_IRQ];
     env->banked_r13[1] = regs.reg13[MODE_SVC];
@@ -101,17 +119,33 @@ int kvm_arch_get_registers(CPUState *env)
     env->banked_r14[3] = regs.reg14[MODE_UND];
     env->banked_r14[0] = regs.reg14[MODE_USR];
     env->regs[15] = regs.reg15;
-    cpsr_write(env, regs.cpsr, 0xFFFFFFFF);
     env->banked_spsr[5] = regs.spsr[MODE_FIQ];
     env->banked_spsr[4] = regs.spsr[MODE_IRQ];
     env->banked_spsr[1] = regs.spsr[MODE_SVC];
     env->banked_spsr[2] = regs.spsr[MODE_ABT];
     env->banked_spsr[3] = regs.spsr[MODE_UND];
 
+    /* We make sure the current mode regs are properly set */
+    mode = env->uncached_cpsr & CPSR_M;
+    bn = bank_number(env, mode);
+    if (mode == ARM_CPU_MODE_FIQ)
+        memcpy(env->regs + 8, env->fiq_regs, 5 * sizeof(uint32_t));
+    else
+        memcpy(env->regs + 8, env->usr_regs, 5 * sizeof(uint32_t));
+    env->regs[13] = env->banked_r13[bn];
+    env->regs[14] = env->banked_r14[bn];
+    env->spsr = env->banked_spsr[bn];
+
     //env->cp15.c0_cpuid = regs.cp15.c0_midr;
     env->cp15.c1_sys = regs.cp15.c1_sys;
     env->cp15.c2_base0 = regs.cp15.c2_base0;
     env->cp15.c2_base1 = regs.cp15.c2_base1;
+
+    /* This is ugly, but necessary for GDB compatibility */
+    env->cp15.c2_control = regs.cp15.c2_control;
+    env->cp15.c2_mask = ~(((uint32_t)0xffffffffu) >> regs.cp15.c2_control);
+    env->cp15.c2_base_mask = ~((uint32_t)0x3fffu >> regs.cp15.c2_control);
+
     env->cp15.c3 = regs.cp15.c3_dacr;
 
     return 0;
@@ -190,3 +224,39 @@ int kvm_arch_on_sigbus(int code, void *addr)
 {
     return 1;
 }
+
+void kvm_arch_update_guest_debug(CPUState *env, struct kvm_guest_debug *dbg)
+{
+    fprintf(stderr, "%s: some args...\n", __func__);
+}
+
+int kvm_arch_insert_sw_breakpoint(CPUState *env, struct kvm_sw_breakpoint *bp)
+{
+    fprintf(stderr, "%s: some args...\n", __func__);
+    return -EINVAL;
+}
+
+int kvm_arch_insert_hw_breakpoint(target_ulong addr,
+                                  target_ulong len, int type)
+{
+    fprintf(stderr, "%s: some args...\n", __func__);
+    return -EINVAL;
+}
+
+int kvm_arch_remove_hw_breakpoint(target_ulong addr,
+                                  target_ulong len, int type)
+{
+    fprintf(stderr, "%s: some args...\n", __func__);
+    return -EINVAL;
+}
+
+int kvm_arch_remove_sw_breakpoint(CPUState *env, struct kvm_sw_breakpoint *bp)
+{
+    fprintf(stderr, "%s: some args...\n", __func__);
+    return -EINVAL;
+}
+
+void kvm_arch_remove_all_hw_breakpoints(void)
+{
+    fprintf(stderr, "%s: no args...\n", __func__);
+}



[Index of Archives]     [Linux KVM]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux