I'm working on a set of debugging tools for some in-house Cortex-M4 cores. I'm building embedded (no OS) ELF images using a gcc/binutils toolchain and simulating them using a modified version of QEMU. I'm creating the interrupt vector tables at the start (i.e. 0) of my images, and correctly initialising the stack pointer, and start address (i.e. the address of main).
The target programs are running as expected, and the debug tools which are built using the GDB remote protocol are working correctly.
What I'm currently trying to understand is how to initiate a soft-reset from GDB. That is, arrange for the target program to be reinitialised with the stack pointer reset to the initial value in the vector table, and the PC back at the start address.
I have already demonstrated to myself that the action of setting the PC value to 0, and running the core is not appropriate, and the result was that my "UsageFault" exception handler was invoked. (I assume that the core is in the wrong mode to execute this kind of action).
Is there a technique, i.e. by register writes using GDB remote protocol that I can soft-reset the simulated core, that is without having to power-cycle the QEMU session?
You can make SW restart by writing SYSRESETREQ bit + KEY into AIRCR register:
AIRCR_REG_ADDRESS = 0xe000ed0c
AIRCR_KEY = 0x05fa0000
AIRCR_SYSRESETREQ_BIT = 0x00000004
AIRCR_REG = AIRCR_KEY | AIRCR_SYSRESETREQ_BIT
More info is here
This is working with all cortex-M
This is a snippet of code for a Cortex-M3 I use to jump to any location with valid code in (including jumping to 0):
IRQn_Type interrupt = (IRQn_Type)0;
app_fn jump = *(app_fn *)(jumpaddr + sizeof(int)); //Reset is 2nd in table
uint32_t stack_adr = *(uint32_t *)(jumpaddr); //Stack pointer is 1st in table
//Disable interrupts before jumping
SysTick->CTRL &= ~ST_CTRL_ENABLE;
while (interrupt <= CANActivity_IRQn)
{
NVIC_DisableIRQ(interrupt);
interrupt++;
}
//Set the new stack pointer
__set_MSP(stack_adr);
//Set the new vector address
SCB->VTOR = (location & 0x1FFFFF80);
//Leap of faith!
jump();
This code assumes jumpaddr is the base address of a vector table, as the stack pointer is first in the table and reset handler is second in the table.
Disabling interrupts is a must as you could have an interrupt go off after you have moved the stack pointer which normally causes an exception.
Of course, doing it this way will not reset any peripherals so that would need to be done before enabling the interrupts again.
Edit:
You can find the contents of __set_MSP here.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With