aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristoffer Dall <c.dall@virtualopensystems.com>2012-03-12 02:53:49 -0400
committerPeter Maydell <peter.maydell@linaro.org>2012-04-05 15:41:41 +0000
commit2251fee73205a3d8f35f58b390e6c99e89dc294f (patch)
tree531b5c36149867d9c7417534766f06806fd57be9
parent487cb243531f50ca7c7038d44b9ef5ae436dec03 (diff)
arm: kvm: Fix register sync and some GDB support
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@virtualopensystems.com>
-rw-r--r--target-arm/cpu.h1
-rw-r--r--target-arm/helper.c2
-rw-r--r--target-arm/kvm.c72
3 files changed, 73 insertions, 2 deletions
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index 16b17654a..e8f730e15 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -246,6 +246,7 @@ CPUARMState *cpu_arm_init(const char *cpu_model);
void arm_translate_init(void);
int cpu_arm_exec(CPUARMState *s);
void do_interrupt(CPUARMState *);
+int bank_number(CPUARMState *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 155ab1953..cfebffdf5 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -717,7 +717,7 @@ uint32_t HELPER(get_r13_banked)(CPUARMState *env, uint32_t mode)
#else
/* Map CPU modes onto saved register banks. */
-static inline int bank_number(CPUARMState *env, int mode)
+int bank_number(CPUARMState *env, int mode)
{
switch (mode) {
case ARM_CPU_MODE_USR:
diff --git a/target-arm/kvm.c b/target-arm/kvm.c
index ace5cd980..29bb51fc4 100644
--- a/target-arm/kvm.c
+++ b/target-arm/kvm.c
@@ -40,12 +40,25 @@ int kvm_arch_init_vcpu(CPUARMState *env)
int kvm_arch_put_registers(CPUARMState *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(CPUARMState *env, int level)
int kvm_arch_get_registers(CPUARMState *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(CPUARMState *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(CPUARMState *env, struct kvm_guest_debug *dbg)
+{
+ fprintf(stderr, "%s: not implemented\n", __func__);
+}
+
+int kvm_arch_insert_sw_breakpoint(CPUARMState *env, struct kvm_sw_breakpoint *bp)
+{
+ fprintf(stderr, "%s: not implemented\n", __func__);
+ return -EINVAL;
+}
+
+int kvm_arch_insert_hw_breakpoint(target_ulong addr,
+ target_ulong len, int type)
+{
+ fprintf(stderr, "%s: not implemented\n", __func__);
+ return -EINVAL;
+}
+
+int kvm_arch_remove_hw_breakpoint(target_ulong addr,
+ target_ulong len, int type)
+{
+ fprintf(stderr, "%s: not implemented\n", __func__);
+ return -EINVAL;
+}
+
+int kvm_arch_remove_sw_breakpoint(CPUARMState *env, struct kvm_sw_breakpoint *bp)
+{
+ fprintf(stderr, "%s: not implemented\n", __func__);
+ return -EINVAL;
+}
+
+void kvm_arch_remove_all_hw_breakpoints(void)
+{
+ fprintf(stderr, "%s: not implemented\n", __func__);
+}