Skip to content
This repository has been archived by the owner on Nov 5, 2019. It is now read-only.

Commit

Permalink
BKPT, if DHCSR.C_DEBUGEN, interrupts CPU
Browse files Browse the repository at this point in the history
- add some more registers for SCB, DCB
  • Loading branch information
ilg-ul committed Jul 25, 2016
1 parent 3cb3c6c commit 6fca397
Show file tree
Hide file tree
Showing 5 changed files with 170 additions and 13 deletions.
17 changes: 17 additions & 0 deletions gdbstub.c
Original file line number Diff line number Diff line change
Expand Up @@ -1252,6 +1252,12 @@ static void gdb_vm_state_change(void *opaque, int running, RunState state)
const char *type;
int ret;

#if defined(CONFIG_GNU_ARM_ECLIPSE)
#if defined(DEBUG_GDB)
printf("vm_state %d, %d\n", running, state);
#endif
#endif

if (running || s->state == RS_INACTIVE) {
return;
}
Expand Down Expand Up @@ -1498,6 +1504,10 @@ void gdb_exit(CPUArchState *env, int code)
#ifndef CONFIG_USER_ONLY
qemu_chr_delete(s->chr);
#endif

#if defined(CONFIG_GNU_ARM_ECLIPSE)
gdbserver_state = NULL;
#endif
}

#ifdef CONFIG_USER_ONLY
Expand Down Expand Up @@ -1804,3 +1814,10 @@ int gdbserver_start(const char *device)
return 0;
}
#endif

#if defined(CONFIG_GNU_ARM_ECLIPSE)
int gdbserver_is_started(void)
{
return (gdbserver_state != NULL);
}
#endif
91 changes: 78 additions & 13 deletions hw/cortexm/cortexm-nvic.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@
* NVIC. Much of that is also implemented here.
*/

#include "config.h"
#if defined(CONFIG_GNU_ARM_ECLIPSE)
#include "sysemu/sysemu.h"
#include "exec/gdbstub.h"
#endif

#include "hw/sysbus.h"
#include "qemu/timer.h"
#include "hw/arm/arm.h"
Expand Down Expand Up @@ -187,6 +193,9 @@ static uint32_t nvic_readl(CortexMNVICState *s, uint32_t offset)
}
case 0x1c: /* SysTick Calibration Value. */
return 10000;

// System Control Block 0xE000ED00 - 0xE000ED8C

case 0xd00: /* CPUID Base. */
cpu = ARM_CPU(current_cpu);
return cpu->midr;
Expand Down Expand Up @@ -264,18 +273,26 @@ static uint32_t nvic_readl(CortexMNVICState *s, uint32_t offset)
if (s->gic.irq_state[ARMV7M_EXCP_USAGE].enabled)
val |= (1 << 18);
return val;

case 0xd28: /* Configurable Fault Status. */
/* TODO: Implement Fault Status. */
qemu_log_mask(LOG_UNIMP, "Configurable Fault Status unimplemented\n");
return 0;
return s->scb.cfsr;

case 0xd2c: /* Hard Fault Status. */
return s->scb.hfsr & 0xC0000003;

case 0xd30: /* Debug Fault Status. */
return s->scb.dfsr;

case 0xd34: /* Mem Manage Address. */
return s->scb.mmfar;

case 0xd38: /* Bus Fault Address. */
return s->scb.bfar;

case 0xd3c: /* Aux Fault Status. */
/* TODO: Implement fault status registers. */
qemu_log_mask(LOG_UNIMP, "Fault status registers unimplemented\n");
return 0;
return s->scb.afsr;

// Reserved for CPUID registers, 0xE000ED40 - 0xE000ED84
case 0xd40: /* PFR0. */
return 0x00000030;
case 0xd44: /* PRF1. */
Expand All @@ -302,16 +319,26 @@ static uint32_t nvic_readl(CortexMNVICState *s, uint32_t offset)
return 0x01111110;
case 0xd70: /* ISAR4. */
return 0x01310102;

#if defined(CONFIG_GNU_ARM_ECLIPSE)

// Debug Control Block 0xE000EDF0 - 0xE000EEFF

case 0xDF0: /* DHCSR. */
return s->dcb.dhcsr & 0x0000001F;

case 0xDF4: /* DCRSR. */
qemu_log_mask(LOG_GUEST_ERROR, "NVIC: read WO DCRSR\n");
return 0;

case 0xDF8: /* DCRDR. */
return s->dcb.dcrdr;

case 0xDFC: /* DEMCR. */
/* TODO: Implement debug registers. */
qemu_log_mask(LOG_UNIMP, "NVIC: debug register %08X unimplemented\n",
offset);
return 0;
return s->dcb.demcr & 0x10F03F1;

#endif

default:
qemu_log_mask(LOG_GUEST_ERROR, "NVIC: Bad read offset 0x%x\n", offset);
return 0;
Expand Down Expand Up @@ -355,6 +382,8 @@ static void nvic_writel(CortexMNVICState *s, uint32_t offset, uint32_t value)
systick_reload(s, 1);
s->systick.control &= ~SYSTICK_COUNTFLAG;
break;

// System Control Block 0xE000ED00 - 0xE000ED8C
case 0xd04: /* Interrupt Control State. */
if (value & (1 << 31)) {
cortexm_nvic_set_pending(s, ARMV7M_EXCP_NMI);
Expand Down Expand Up @@ -413,7 +442,9 @@ static void nvic_writel(CortexMNVICState *s, uint32_t offset, uint32_t value)
qemu_log_mask(LOG_UNIMP,
"NVIC: fault status registers unimplemented\n");
break;

#if defined(CONFIG_GNU_ARM_ECLIPSE)

case 0xD88: /* CPACR. */
if (value & (((3UL << 10 * 2) | (3UL << 11 * 2)))) {
/* Attempt to enable CP10 & CP11 (the FPU). */
Expand All @@ -423,15 +454,31 @@ static void nvic_writel(CortexMNVICState *s, uint32_t offset, uint32_t value)
}
break;

// Debug Control Block 0xE000EDF0 - 0xE000EEFF
// All registers are 32-bits wide.
// See also SCB.DFSR 0xE000ED30

case 0xDF0: /* DHCSR. */
if ((value & 0xFFFF0000) == 0xA05F0000) {
s->dcb.dhcsr = value & 0x0000001E;
}
break;

case 0xDF4: /* DCRSR. */
s->dcb.dcrsr = value & 0x0001003F;
// TODO: implement read/write register
break;

case 0xDF8: /* DCRDR. */
s->dcb.dcrdr = value;
break;

case 0xDFC: /* DEMCR. */
/* TODO: Implement debug registers. */
qemu_log_mask(LOG_UNIMP, "NVIC: debug register %08X unimplemented\n",
offset);
s->dcb.demcr = value & 0x010F03F1;
break;

#endif

case 0xf00: /* Software Triggered Interrupt Register */
if ((value & 0x1ff) < s->num_irq) {
gic_set_pending_private(&s->gic, 0, value & 0x1ff);
Expand Down Expand Up @@ -608,6 +655,24 @@ static void cortexm_nvic_reset_callback(DeviceState *dev)
/* The NVIC as a whole is always enabled. */
s->gic.ctlr = 1;
systick_reset(s);

// System Control Block
s->scb.scr = 0;
s->scb.ccr = 0; // Implementation dependent
s->scb.cfsr = 0;
s->scb.hfsr = 0;
s->scb.dfsr = 0;
s->scb.mmfar = 0;
s->scb.bfar = 0;
s->scb.afsr = 0;

// Debug Control Block

s->dcb.dhcsr = gdbserver_is_started() ? 1 : 0; // C_DEBUGEN[0]

s->dcb.dcrsr = 0;
s->dcb.dcrdr = 0;
s->dcb.demcr = 0;
}

static void cortexm_nvic_class_init_callback(ObjectClass *klass, void *data)
Expand Down
4 changes: 4 additions & 0 deletions include/exec/gdbstub.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,10 @@ int gdbserver_start(int);
int gdbserver_start(const char *port);
#endif

#if defined(CONFIG_GNU_ARM_ECLIPSE)
int gdbserver_is_started(void);
#endif

/**
* gdb_has_xml:
* This is an ugly hack to cope with both new and old gdb.
Expand Down
23 changes: 23 additions & 0 deletions include/hw/cortexm/cortexm-nvic.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,29 @@ typedef struct {
MemoryRegion container;
uint32_t num_irq;
qemu_irq sysresetreq;

// System Control Block 0xE000ED00 - 0xE000ED8C
struct {
uint32_t scr; // 0xE000ED10, RW, 0x00000000, System Control Block
uint32_t ccr; // 0xE000ED14, RW, IMPL, Configuration & Control Register
// 0xE000ED24, RW, System Handler Control and State Register
uint32_t cfsr; // 0xE000ED28, RW, 0x00000000, Configurable Fault Status Register
uint32_t hfsr; // 0xE000ED2C, RW, 0x00000000, Hard Fault Status Register
uint32_t dfsr; // 0xE000ED30, RW, 0x00000000, Debug Fault Status Register
uint32_t mmfar; // 0xE000ED34, RW, UNK, MemManage Fault Address Register
uint32_t bfar; // 0xE000ED38, RW, UNK, Bus Fault Address Register
uint32_t afsr; // 0xE000ED3C, RW, UNK, Auxiliary Fault Status Register
} scb;

// Debug Control Block 0xE000EDF0 - 0xE000EEFF
// All registers are 32-bits wide.
struct {
uint32_t dhcsr; // 0xE000EDF0, RW, Debug Halting Control and Status Register,
uint32_t dcrsr; // 0xE000EDF4, WO, Debug Core Register Selector Register
uint32_t dcrdr; // 0xE000EDF8, RW, Debug Core Register Data Register
uint32_t demcr; // 0xE000EDFC, RW, 0x00000000, Debug Exception and Monitor Control Register
} dcb;

} CortexMNVICState;

/* ------------------------------------------------------------------------- */
Expand Down
48 changes: 48 additions & 0 deletions target-arm/helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

#if defined(CONFIG_GNU_ARM_ECLIPSE)
#include "hw/intc/gic_internal.h"
#include "hw/cortexm/cortexm-nvic.h"
#endif

#define ARM_CPU_FREQ 1000000000 /* FIXME: 1 GHz, should be configurable */
Expand Down Expand Up @@ -5577,6 +5578,43 @@ void arm_v7m_cpu_do_interrupt(CPUState *cs)
armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_MEM);
return;
case EXCP_BKPT:

#if defined(CONFIG_GNU_ARM_ECLIPSE)
/*
* The Breakpoint (BKPT) instruction provides for software
* breakpoints. It can generate a DebugMonitor exception or
* cause a running system to halt depending on the debug
* configuration.
*
* C1.5 Debug event behavior
*
* Entry to Debug state. If halting debug is enabled, a
* debug event halts the processor in Debug state. Setting
* the DHCSR.C_DEBUGEN bit to 1 enables halting debug.
*
* A DebugMonitor exception. If halting debug is disabled and
* the DebugMonitor exception is enabled, a debug event causes
* a DebugMonitor exception when the group priority of the
* DebugMonitor exception is greater than the current execution
* priority.
*
* Debug Fault Status Register, DFSR
* Shows which debug event occurred.
* BKPT, bit[1] Indicates a debug event generated by BKPT
* instruction execution or a breakpoint match in FPB:
* 0 No breakpoint debug event.
* 1 At least one breakpoint debug event.
*
* HardFault on breakpoint (BKPT) escalation
* Status bit HFSR.DEBUGEVT
* Vector catch bit DEMCR.VC_HARDERR
* A BKPT instruction is executed while halting debug is
* disabled and the DebugMonitor is disabled or the DebugMonitor
* priority is lower than or equal to the execution priority.
* The exception escalates to a HardFault.
*/
#endif

if (semihosting_enabled()) {
int nr;
nr = arm_lduw_code(env, env->regs[15], env->bswap_code) & 0xff;
Expand All @@ -5589,6 +5627,16 @@ void arm_v7m_cpu_do_interrupt(CPUState *cs)
return;
}
}

#if defined(CONFIG_GNU_ARM_ECLIPSE)
CortexMNVICState* nvic = CORTEXM_NVIC_STATE(env->nvic);
// Check DHCSR.C_DEBUGEN
if (nvic->dcb.dhcsr & 1) {
cpu_interrupt(cs, CPU_INTERRUPT_DEBUG);
return;
}
#endif

armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_DEBUG);
return;
case EXCP_IRQ:
Expand Down

0 comments on commit 6fca397

Please sign in to comment.