1.. _module-pw_boot_cortex_m: 2 3---------------- 4pw_boot_cortex_m 5---------------- 6 7The ARM Cortex-M boot module provides a linker script and some early 8initialization of static memory regions and C++ constructors. This is enough to 9get many ARMv7-M and ARMv8-M cores booted and ready to run C++ code. 10 11This module is currently designed to support a very minimal device memory layout 12configuration: 13 14- One contiguous region for RAM. 15- One contiguous region for flash. 16- Static, in-flash vector table at the default location expected by the SoC. 17 18Note that this module is not yet particularly suited for projects that utilize 19a bootloader, as it's relatively opinionated regarding where code is stored. 20 21.. warning:: 22 23 This module is currently NOT stable! Depending on this module may cause 24 breakages as this module is updated. 25 26Sequence 27======== 28 29The high level pw_boot_cortex_m boot sequence looks like the following 30pseudo-code invocation of the user-implemented functions: 31 32.. code-block:: cpp 33 34 void pw_boot_Entry() { // Boot entry point. 35 // Set VTOR. 36 // Interrupts disabled. 37 pw_boot_PreStaticMemoryInit(); // User-implemented function. 38 // Static memory initialization. 39 // Interrupts enabled. 40 pw_boot_PreStaticConstructorInit(); // User-implemented function. 41 // C++ static constructors are invoked. 42 pw_boot_PreMainInit(); // User-implemented function. 43 main(); // User-implemented function. 44 pw_boot_PostMain(); // User-implemented function. 45 PW_UNREACHABLE; 46 } 47 48Setup 49===== 50 51Processor Selection 52------------------- 53Set the ``pw_boot_BACKEND`` variable to the appropriate target for the processor 54in use. 55 56- ``pw_boot_cortex_m:armv7m`` for ARMv7-M cores. 57 58- ``pw_boot_cortex_m:armv8m`` for ARMv8-M cores. This sets the MSPLIM register 59 so that the main stack pointer (MSP) cannot descend outside the bounds of the 60 main stack defined in the linker script. The MSP of the entry point is also 61 adjusted to be within the bounds. 62 63User-Implemented Functions 64-------------------------- 65This module expects all of these extern "C" functions to be defined outside this 66module: 67 68- ``int main()``: This is where applications reside. 69- ``void pw_boot_PreStaticMemoryInit()``: This function executes just before 70 static memory has been zeroed and static data is intialized. This function 71 should set up any early initialization that should be done before static 72 memory is initialized, such as: 73 74 - Setup the interrupt vector table and VTOR if required. 75 - Enabling the FPU or other coprocessors. 76 - Opting into extra restrictions such as disabling unaligned access to ensure 77 the restrictions are active during static RAM initialization. 78 - Initial CPU clock, flash, and memory configurations including potentially 79 enabling extra memory regions with .bss and .data sections, such as SDRAM 80 or backup powered SRAM. 81 - Fault handler initialization if required before static memory 82 initialization. 83 84 .. warning:: 85 86 Code running in this hook is violating the C spec as static values are not 87 yet initialized, meaning they have not been loaded (.data) nor 88 zero-initialized (.bss). 89 90 Interrupts are disabled until after this function returns. 91 92- ``void pw_boot_PreStaticConstructorInit()``: This function executes just 93 before C++ static constructors are called. At this point, other static memory 94 has been zero or data initialized. This function should set up any early 95 initialization that should be done before C++ static constructors are run, 96 such as: 97 98 - Run time dependencies such as Malloc, and ergo sometimes the RTOS. 99 - Persistent memory that survives warm reboots. 100 - Enabling the MPU to catch nullptr dereferences during construction. 101 - Main stack watermarking. 102 - Further fault handling configuration necessary for your platform which were 103 not safe before pw_boot_PreStaticRamInit(). 104 - Boot count and/or boot session UUID management. 105 106- ``void pw_boot_PreMainInit()``: This function executes just before main, and 107 can be used for any device initialization that isn't application specific. 108 Depending on your platform, this might be turning on a UART, setting up 109 default clocks, etc. 110 111- ``PW_NO_RETURN void pw_boot_PostMain()``: This function executes after main 112 has returned. This could be used for device specific teardown such as an 113 infinite loop, soft reset, or QEMU shutdown. In addition, if relevant for your 114 application, this would be the place to invoke the global static 115 destructors. This function must not return! 116 117 118If any of these functions are unimplemented, executables will encounter a link 119error. 120 121Required Configs 122---------------- 123This module has a number of required configuration options that mold the linker 124script to fit to a wide variety of ARM Cortex-M SoCs. 125 126Vector Table 127------------ 128Targets using ``pw_boot_cortex_m`` will need to provide an ARMv7-M interrupt 129vector table (ARMv7-M Architecture Reference Manual DDI 0403E.b section B1.5.2 130and B1.5.3). This is done by storing an array into the ``.vector_table`` 131section, and properly configuring ``PW_BOOT_VECTOR_TABLE_*`` preprocessor 132defines to cover the address region your SoC expects the vector table to be 133located at (often the beginning of the flash region). If using a bootloader, 134ensure VTOR (Vector Table Offset Register) is configured to point to the vector 135table, otherwise ensure that execution begins at ``pw_boot_Entry`` which will 136set VTOR as its first operation. If in doubt, refer to the hardware vendor's 137documentation to determine where the vector table and reset handler should be 138located. 139 140Example vector table: 141 142.. code-block:: cpp 143 144 typedef void (*InterruptHandler)(); 145 146 PW_KEEP_IN_SECTION(".vector_table") 147 const InterruptHandler vector_table[] = { 148 // The starting location of the stack pointer. 149 // This address is NOT an interrupt handler/function pointer, it is simply 150 // the address that the main stack pointer should be initialized to. The 151 // value is reinterpret casted because it needs to be in the vector table. 152 [0] = reinterpret_cast<InterruptHandler>(&pw_boot_stack_high_addr), 153 154 // Reset handler, dictates how to handle reset interrupt. This is the 155 // address that the Program Counter (PC) is initialized to at boot. 156 [1] = pw_boot_Entry, 157 158 // NMI handler. 159 [2] = DefaultFaultHandler, 160 // HardFault handler. 161 [3] = DefaultFaultHandler, 162 ... 163 }; 164 165Usage 166===== 167 168Publicly exported symbols 169------------------------- 170The linker script provided by this module exports a number of symbols that 171may be used to retrieve the locations of specific memory regions at runtime. 172These symbols are declared as ``uint8_t`` variables. The variables themselves 173do not contain the addresses, they only reside at the memory location they 174reference. To retrieve the memory locations, simply take the reference of the 175symbol (e.g. ``&pw_boot_vector_table_addr``). 176 177``pw_boot_heap_[low/high]_addr``: Beginning and end of the memory range of the heap. 178These addresses may be identical, indicating a heap with a size of zero bytes. 179 180``pw_boot_stack_[low/high]_addr``: Beginning and end of the memory range of the main 181stack. This might not be the only stack in the system. 182 183``pw_boot_vector_table_addr``: Beginning of the ARMv7-M interrupt vector table. 184 185Configuration 186============= 187These configuration options can be controlled by appending list items to 188``pw_boot_cortex_m_LINK_CONFIG_DEFINES`` as part of a Pigweed target 189configuration. 190 191``PW_BOOT_HEAP_SIZE`` (required): 192How much memory (in bytes) to reserve for the heap. This can be zero. 193 194``PW_BOOT_MIN_STACK_SIZE`` (required): 195The minimum size reserved for the main stack. If statically allocated memory 196begins to cut into the minimum, a link error will be emitted. 197 198``PW_BOOT_FLASH_BEGIN`` (required): 199The start address of the MCU's flash region. This region must NOT include the 200vector table. (i.e. if the VECTOR_TABLE is in flash, the flash region 201should begin *after* the vtable) 202 203``PW_BOOT_FLASH_SIZE`` (required): 204Size of the flash region in bytes. 205 206``PW_BOOT_RAM_BEGIN`` (required): 207The start address of the MCU's RAM region. 208 209``PW_BOOT_RAM_SIZE`` (required): 210Size of the RAM region in bytes. 211 212``PW_BOOT_VECTOR_TABLE_BEGIN`` (required): 213Address the target MCU expects the link-time vector table to be located at. This 214is typically the beginning of the flash region. While the vector table may be 215changed later in the boot process, a minimal vector table MUST be present for 216the MCU to operate as expected. 217 218``PW_BOOT_VECTOR_TABLE_SIZE`` (required): 219Number of bytes to reserve for the ARMv7-M vector table. 220 221Alternatively the linker script can be replaced by setting 222``pw_boot_cortex_m_LINKER_SCRIPT`` to a valid ``pw_linker_script`` target 223as part of a Pigweed target configuration. 224 225Dependencies 226============ 227- :bdg-ref-primary-line:`module-pw_preprocessor` 228