How to boot a Cortex-M3 or Cortex-M4 processor with uninitialized memory at address zero
Article ID: 103489924
Published date: 24 Jul 2017
Last updated: -
Applies to: Cortex-M3, Cortex-M4
How do I boot a Cortex-M3 or Cortex-M4 processor with uninitialized memory at address zero?
At Reset, Cortex-M3 and Cortex-M4 processors always boot from a vector table at address zero.
With uninitialized memory at address zero (for example, unprogrammed Flash or uninitialized RAM), the processor reads a spurious initial Main Stack Pointer value from address zero and a spurious code entry point (Reset vector) from address 0x4, possibly containing an illegal instruction set state specifier (ESPR.T bit) in bit.
The processor might lock up immediately or it might execute some spurious opcodes, with lock-up also remaining a possible outcome.
A clean boot-up can be achieved through the actions of a debugger connected to the processor's debug port (assuming that the SoC has implemented Debug features for the processor).
For systems where there is no possibility of damage to the SoC or to the connected systems, the processor can be allowed to exit from Reset, and potentially execute some spurious opcodes, before the debugger takes control.
However, where there is a possibility of damage or undesirable consequences from executing spurious opcodes, the SoC design must provide a suitable method of preventing initial execution, for example by holding the processor's functional reset, SYSRESETn, asserted after the release of the power-on reset, PORESETn.
While the processor is executing or is held in functional reset, the debugger can write to the NVIC to enable Halting Debug (DHCSR.C_DEBUGEN) and can set up a vector catch at reset (DEMCR.VC_CORERESET). The processor can then be halted by the vector catch. If the processor is still held in functional reset, this is achieved simply by releasing the reset. If the processor is not currently held in reset, this can be achieved by halting the processor with the DHCSR.C_HALT bit and then writing the AIRCR.VECTRESET bit.
The processor is now in a Debug Halt state, having fetched the initial Main Stack Pointer, the Reset Vector, and the EPSR.T bit from uninitialized memory.
Note that the method of holding the processor in reset until the debugger has set up the vector catch implies that the debugger then has the ability to subsequently release the SYSRESETn input to the processor. This requires some implementation-defined logic on the SoC to hold SYSRESETn asserted after PORESETn is released, possibly in the reset control logic on the SoC. The debugger must then be able to clear that SYSRESETn assertion, possibly by writing to a memory-mapped register in the system.
The ARMv7-M Architecture specifies that the debugger can access the processor's internal debug registers while the functional reset is asserted. It does not specify whether the external memory system can be accessed in this reset state. In the case of the Cortex-M3 and Cortex-M4 processors, debugger access to the memory system during functional reset is slightly unusual. Cortex-M3 r2p1 and Cortex-M4 r0p1 processors have the following behavior: the debugger can successfully read from any external address, and can successfully write to any address on the System bus. However, the write data value on the D-Code bus is tied to zero in this state, so the debugger can write to any address in the Code space but only with a write data value of zero.
After the processor is halted at the vector catch on reset, with invalid values in the main Stack Pointer and Program Counter, the correct and robust procedure from this point is to initialize at least a minimal vector table at address zero. The minimal vector table requires at least the first four entries to be valid. These entries are the initial Main Stack Pointer, and vectors (all with bit = 1) for the Reset, NMI, and Hard Fault handler entry points, because these exceptions cannot be inhibited and a Reset will always cause the vector table offset to revert to address 0x0. It is also necessary to download an executable code image to a suitable address in a writable and executable memory region, and then to restart operation by issuing a further self-reset (VECTRESET) so that the boot procedure starts again, but this time from the now populated vector table at address 0x0.
A makeshift alternative method exists for simple cases where writing to memory at address zero is inconvenient (for example, requiring Flash erase and reprogramming). An example of this might be a test case where it is not necessary to fully support the continuation of normal execution after the test. This alternative allows the debugger to use the DCRSR and DCRDR functions to fully modify the values already fetched from addresses 0x0 and 0x4, while the processor is halted in debug state. This requires:
The Main Stack Pointer to be written with a suitable 'top of stack' address in RAM
The DebugReturnAddress (basically the PC) to be written with the true address of the code entry point.
The xPSR to be written with 0x01000000 (setting the EPSR.T bit).
The executable test code to be downloaded into a suitable (writable and executable) memory region as pointed to by that DebugReturnAddress.
Note that for the makeshift method described above, there remains no valid vector table at address zero. The debugger or the code image can program the VTOR to point to a valid vector table, for example located in the downloaded code image itself, but if another reset occurs the reboot will revert to the (non-existent) vector table at address 0x0.