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