pw_boot_armv7m: Initial commit
pw_boot_armv7m provides a generic linker script and startup script to
speed up device bringup on ARMv7-M based cores.
Change-Id: Ia4abe78ab1d6bde017608eeb46b2e780bf53dad1
diff --git a/docs/BUILD.gn b/docs/BUILD.gn
index dee8a15..c5325bb 100644
--- a/docs/BUILD.gn
+++ b/docs/BUILD.gn
@@ -41,6 +41,7 @@
":core_docs",
":target_docs",
"$dir_pw_bloat:docs",
+ "$dir_pw_boot_armv7m:docs",
"$dir_pw_build:docs",
"$dir_pw_cpu_exception:docs",
"$dir_pw_cpu_exception_armv7m:docs",
diff --git a/modules.gni b/modules.gni
index fbbee69..6a65579 100644
--- a/modules.gni
+++ b/modules.gni
@@ -18,6 +18,7 @@
dir_pw_base64 = "$dir_pigweed/pw_base64"
dir_pw_bloat = "$dir_pigweed/pw_bloat"
+dir_pw_boot_armv7m = "$dir_pigweed/pw_boot_armv7m"
dir_pw_build = "$dir_pigweed/pw_build"
dir_pw_cpu_exception = "$dir_pigweed/pw_cpu_exception"
dir_pw_cpu_exception_armv7m = "$dir_pigweed/pw_cpu_exception_armv7m"
diff --git a/pw_dumb_io_baremetal_stm32f429/bloaty_config.bloaty b/pw_boot_armv7m/BUILD
similarity index 65%
copy from pw_dumb_io_baremetal_stm32f429/bloaty_config.bloaty
copy to pw_boot_armv7m/BUILD
index 0b92d47..0c78627 100644
--- a/pw_dumb_io_baremetal_stm32f429/bloaty_config.bloaty
+++ b/pw_boot_armv7m/BUILD
@@ -1,4 +1,4 @@
-# Copyright 2019 The Pigweed Authors
+# Copyright 2020 The Pigweed Authors
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
@@ -12,18 +12,14 @@
# License for the specific language governing permissions and limitations under
# the License.
-source_filter: "^SEG .+$"
+package(default_visibility = ["//visibility:public"])
-custom_data_source: {
- name: "segment_names"
- base_data_source: "segments"
+licenses(["notice"]) # Apache License 2.0
- rewrite: {
- pattern: "LOAD #0"
- replacement: "SEG FLASH"
- }
- rewrite: {
- pattern: "LOAD #1"
- replacement: "SEG RAM"
- }
-}
+filegroup(
+ name = "pw_dumb_io_baremetal_stm32f429",
+ srcs = [
+ "core_init.c",
+ "public/pw_boot_armv7m/boot.h",
+ ],
+)
diff --git a/pw_boot_armv7m/BUILD.gn b/pw_boot_armv7m/BUILD.gn
new file mode 100644
index 0000000..6376d58
--- /dev/null
+++ b/pw_boot_armv7m/BUILD.gn
@@ -0,0 +1,48 @@
+# Copyright 2020 The Pigweed Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not
+# use this file except in compliance with the License. You may obtain a copy of
+# the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations under
+# the License.
+
+import("$dir_pw_build/linker_script.gni")
+import("$dir_pw_docgen/docs.gni")
+
+if (dir_pw_boot_backend == dir_pw_boot_armv7m) {
+ config("default_config") {
+ include_dirs = [ "public" ]
+ }
+
+ pw_linker_script("armv7m_linker_script") {
+ # pw_boot_armv7m_config is a scope provided by the target.
+ assert(defined(pw_boot_armv7m_config),
+ "pw_boot_armv7m depends on pw_boot_armv7m_config being defined!")
+ defines = pw_boot_armv7m_config.defines
+ linker_script = "basic_armv7m.ld"
+ }
+
+ source_set("pw_boot_armv7m") {
+ public_configs = [ ":default_config" ]
+ deps = [
+ ":armv7m_linker_script",
+ "$dir_pw_preprocessor",
+ ]
+ public = [
+ "public/pw_boot_armv7m/boot.h",
+ ]
+ sources = [ "core_init.c" ] + public
+ }
+}
+
+pw_doc_group("docs") {
+ sources = [
+ "docs.rst",
+ ]
+}
diff --git a/pw_boot_armv7m/basic_armv7m.ld b/pw_boot_armv7m/basic_armv7m.ld
new file mode 100644
index 0000000..3f38aeb
--- /dev/null
+++ b/pw_boot_armv7m/basic_armv7m.ld
@@ -0,0 +1,197 @@
+/*
+ * Copyright 2020 The Pigweed Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+/* This relatively simplified linker script will work with many ARMv7-M cores
+ * that have on-board memory-mapped RAM and FLASH. For more complex projects and
+ * devices, it's possible this linker script will not be sufficient as-is.
+ *
+ * This linker script is likely not suitable for a project with a bootloader.
+ */
+
+/* Provide useful error messages when required configurations are not set. */
+#ifndef PW_BOOT_INTERRUPT_VECTOR_TABLE_BEGIN
+#error "PW_BOOT_INTERRUPT_VECTOR_TABLE_BEGIN is not defined, and is required to use pw_boot_armv7m"
+#endif // PW_BOOT_INTERRUPT_VECTOR_TABLE_BEGIN
+
+#ifndef PW_BOOT_INTERRUPT_VECTOR_TABLE_SIZE
+#error "PW_BOOT_INTERRUPT_VECTOR_TABLE_SIZE is not defined, and is required to use pw_boot_armv7m"
+#endif // PW_BOOT_INTERRUPT_VECTOR_TABLE_SIZE
+
+#ifndef PW_BOOT_FLASH_BEGIN
+#error "PW_BOOT_FLASH_BEGIN is not defined, and is required to use pw_boot_armv7m"
+#endif // PW_BOOT_FLASH_BEGIN
+
+#ifndef PW_BOOT_FLASH_SIZE
+#error "PW_BOOT_FLASH_SIZE is not defined, and is required to use pw_boot_armv7m"
+#endif // PW_BOOT_FLASH_SIZE
+
+#ifndef PW_BOOT_RAM_BEGIN
+#error "PW_BOOT_RAM_BEGIN is not defined, and is required to use pw_boot_armv7m"
+#endif // PW_BOOT_RAM_BEGIN
+
+#ifndef PW_BOOT_RAM_SIZE
+#error "PW_BOOT_RAM_SIZE is not defined, and is required to use pw_boot_armv7m"
+#endif // PW_BOOT_RAM_SIZE
+
+#ifndef PW_BOOT_HEAP_SIZE
+#error "PW_BOOT_HEAP_SIZE is not defined, and is required to use pw_boot_armv7m"
+#endif // PW_BOOT_HEAP_SIZE
+
+#ifndef PW_BOOT_MIN_STACK_SIZE
+#error "PW_BOOT_MIN_STACK_SIZE is not defined, and is required to use pw_boot_armv7m"
+#endif // PW_BOOT_MIN_STACK_SIZE
+
+
+/* Note: This technically doesn't set the firmware's entry point. Setting the
+ * firmware entry point is done by setting vector_table[1]
+ * (Reset_Handler). However, this DOES tell the compiler how to optimize
+ * when --gc-sections is enabled.
+ */
+ENTRY(pw_BootEntry)
+
+MEMORY
+{
+ /* TODO(pwbug/57): Make it possible for projects to freely customize
+ * memory regions.
+ */
+
+ /* Vector Table (typically in flash) */
+ INTERRUPT_VECTOR_TABLE(rx) : \
+ ORIGIN = PW_BOOT_INTERRUPT_VECTOR_TABLE_BEGIN, \
+ LENGTH = PW_BOOT_INTERRUPT_VECTOR_TABLE_SIZE
+ /* Internal Flash */
+ FLASH(rx) : \
+ ORIGIN = PW_BOOT_FLASH_BEGIN, \
+ LENGTH = PW_BOOT_FLASH_SIZE
+ /* Internal SRAM */
+ RAM(rwx) : \
+ ORIGIN = PW_BOOT_RAM_BEGIN, \
+ LENGTH = PW_BOOT_RAM_SIZE
+}
+
+SECTIONS
+{
+ /* This is the link-time vector table. If used, the VTOR (Vector Table Offset
+ * Register) MUST point to this memory location in order to be used. This can
+ * be done by ensuring this section exists at the default location of the VTOR
+ * so it's used on reset, or by explicitly setting the VTOR in a bootloader
+ * manually to point to &pw_vector_table_addr before interrupts are enabled.
+ */
+ .vector_table : ALIGN(512)
+ {
+ pw_vector_table_addr = .;
+ KEEP(*(.vector_table))
+ } >INTERRUPT_VECTOR_TABLE
+
+ /* Main executable code. */
+ .code : ALIGN(8)
+ {
+ . = ALIGN(8);
+ /* Application code. */
+ *(.text)
+ *(.text*)
+ KEEP(*(.init))
+ KEEP(*(.fini))
+
+ . = ALIGN(8);
+ /* Constants.*/
+ *(.rodata)
+ *(.rodata*)
+
+ /* .preinit_array, .init_array, .fini_array are used by libc.
+ * Each section is a list of function pointers that are called pre-main and
+ * post-exit for object initialization and tear-down.
+ * Since the region isn't explicitly referenced, specify KEEP to prevent
+ * link-time garbage collection. SORT is used for sections that have strict
+ * init/de-init ordering requirements. */
+ . = ALIGN(8);
+ PROVIDE_HIDDEN(__preinit_array_start = .);
+ KEEP(*(.preinit_array*))
+ PROVIDE_HIDDEN(__preinit_array_end = .);
+
+ PROVIDE_HIDDEN(__init_array_start = .);
+ KEEP(*(SORT(.init_array.*)))
+ KEEP(*(.init_array*))
+ PROVIDE_HIDDEN(__init_array_end = .);
+
+ PROVIDE_HIDDEN(__fini_array_start = .);
+ KEEP(*(SORT(.fini_array.*)))
+ KEEP(*(.fini_array*))
+ PROVIDE_HIDDEN(__fini_array_end = .);
+ } >FLASH
+
+ /* Used by unwind-arm/ */
+ .ARM : ALIGN(8) {
+ __exidx_start = .;
+ *(.ARM.exidx*)
+ __exidx_end = .;
+ } >FLASH
+
+ /* Explicitly initialized global and static data. (.data)*/
+ .static_init_ram : ALIGN(8)
+ {
+ *(.data)
+ *(.data*)
+ . = ALIGN(8);
+ } >RAM AT> FLASH
+
+ /* Zero initialized global/static data. (.bss)
+ * This section is zero initialized in pw_BootEntry(). */
+ .zero_init_ram : ALIGN(8)
+ {
+ *(.bss)
+ *(.bss*)
+ *(COMMON)
+ . = ALIGN(8);
+ } >RAM
+
+ .heap : ALIGN(8)
+ {
+ pw_heap_low_addr = .;
+ . = . + PW_BOOT_HEAP_SIZE;
+ . = ALIGN(8);
+ pw_heap_high_addr = .;
+ } >RAM
+
+ /* Link-time check for stack overlaps. */
+ .stack (NOLOAD) : ALIGN(8)
+ {
+ /* Set the address that the main stack pointer should be initialized to. */
+ pw_stack_low_addr = .;
+ HIDDEN(_stack_size = ORIGIN(RAM) + LENGTH(RAM) - .);
+ /* Align the stack to a lower address to ensure it isn't out of range. */
+ HIDDEN(_stack_high = (. + _stack_size) & ~0x7);
+ ASSERT(_stack_high - . >= PW_BOOT_MIN_STACK_SIZE,
+ "Error: Not enough RAM for desired minimum stack size.");
+ . = _stack_high;
+ pw_stack_high_addr = .;
+ } >RAM
+}
+
+/* Symbols used by core_init.c: */
+/* Start of .static_init_ram in FLASH. */
+_pw_static_init_flash_start = LOADADDR(.static_init_ram);
+
+/* Region of .static_init_ram in RAM. */
+_pw_static_init_ram_start = ADDR(.static_init_ram);
+_pw_static_init_ram_end = _pw_static_init_ram_start + SIZEOF(.static_init_ram);
+
+/* Region of .zero_init_ram. */
+_pw_zero_init_ram_start = ADDR(.zero_init_ram);
+_pw_zero_init_ram_end = _pw_zero_init_ram_start + SIZEOF(.zero_init_ram);
+
+/* arm-none-eabi expects `end` symbol to point to start of heap for sbrk. */
+PROVIDE(end = _pw_zero_init_ram_end);
diff --git a/pw_dumb_io_baremetal_stm32f429/bloaty_config.bloaty b/pw_boot_armv7m/bloaty_config.bloaty
similarity index 92%
rename from pw_dumb_io_baremetal_stm32f429/bloaty_config.bloaty
rename to pw_boot_armv7m/bloaty_config.bloaty
index 0b92d47..b67ec76 100644
--- a/pw_dumb_io_baremetal_stm32f429/bloaty_config.bloaty
+++ b/pw_boot_armv7m/bloaty_config.bloaty
@@ -1,4 +1,4 @@
-# Copyright 2019 The Pigweed Authors
+# Copyright 2020 The Pigweed Authors
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
@@ -19,11 +19,11 @@
base_data_source: "segments"
rewrite: {
- pattern: "LOAD #0"
+ pattern: "LOAD #1"
replacement: "SEG FLASH"
}
rewrite: {
- pattern: "LOAD #1"
+ pattern: "LOAD #2"
replacement: "SEG RAM"
}
}
diff --git a/pw_boot_armv7m/core_init.c b/pw_boot_armv7m/core_init.c
new file mode 100644
index 0000000..209cac4
--- /dev/null
+++ b/pw_boot_armv7m/core_init.c
@@ -0,0 +1,109 @@
+// Copyright 2020 The Pigweed Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+// !!!WARNING!!!
+//
+// Some of the code in this file is run without static initialization expected
+// by C/C++. Any accesses to statically initialized objects/variables before
+// memory is initialized will result in undefined values and violates the C
+// specification. Only code run after memory initialization is complete will be
+// compliant and truly safe to run. In general, make early initialization code
+// run AFTER memory initialization has completed unless it is ABSOLUTELY
+// NECESSARY to modify the way memory is initialized.
+//
+// This file is similar to a traditional assembly startup file. It turns out
+// that everything typically done in ARMv7-M assembly startup can be done
+// straight from C code. This makes startup code easier to maintain, modify,
+// and read.
+//
+// When execution begins due to SoC power-on (or the device is reset), three
+// key things must happen to properly enter C++ execution context:
+// 1. Static variables must be loaded from flash to RAM.
+// 2. Zero-initialized variables must be zero-initialized.
+// 3. Statically allocated objects must have their constructors run.
+// The SoC doesn't inherently have a notion of how to do this, so this is
+// handled in StaticInit();
+//
+// Following this, execution is handed over to pw_PreMainInit() to facilitate
+// platform, project, or application pre-main initialization. When
+// pw_PreMainInit() returns, main() is executed.
+//
+// The simple flow is as follows:
+// 1. Power on
+// 2. PC and SP set (from vector_table by SoC, or by bootloader)
+// 3. pw_BootEntry()
+// 3.1. Static-init RAM (.data, .bss, C++ constructors)
+// 3.2. pw_PreMainInit()
+// 3.3. main()
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "pw_boot_armv7m/boot.h"
+#include "pw_preprocessor/compiler.h"
+
+// Extern symbols provided by linker script.
+// These symbols tell us where various memory sections start and end.
+extern uint8_t _pw_static_init_ram_start;
+extern uint8_t _pw_static_init_ram_end;
+extern uint8_t _pw_static_init_flash_start;
+extern uint8_t _pw_zero_init_ram_start;
+extern uint8_t _pw_zero_init_ram_end;
+
+// Functions called as part of firmware initialization.
+void __libc_init_array(void);
+
+// WARNING: Be EXTREMELY careful when running code before this function
+// completes. The context before this function violates the C spec
+// (Section 6.7.8, paragraph 10 for example, which requires uninitialized static
+// values to be zero-initialized).
+void StaticInit(void) {
+ // Static-init RAM (load static values into ram, .data section init).
+ memcpy(&_pw_static_init_ram_start,
+ &_pw_static_init_flash_start,
+ &_pw_static_init_ram_end - &_pw_static_init_ram_start);
+
+ // Zero-init RAM (.bss section init).
+ memset(&_pw_zero_init_ram_start,
+ 0,
+ &_pw_zero_init_ram_end - &_pw_zero_init_ram_start);
+
+ // Call static constructors.
+ __libc_init_array();
+}
+
+// WARNING: This code is run immediately upon boot, and performs initialization
+// of RAM. Note that code running before this function finishes memory
+// initialization will violate the C spec (Section 6.7.8, paragraph 10 for
+// example, which requires uninitialized static values to be zero-initialized).
+// Be EXTREMELY careful when running code before this function finishes RAM
+// initialization.
+//
+// This function runs immediately at boot because it is at index 1 of the
+// interrupt vector table.
+void pw_BootEntry() {
+ StaticInit();
+
+ // This function is not provided by pw_boot_armv7m, a platform layer, project,
+ // or application is expected to implement it.
+ pw_PreMainInit();
+
+ // Run main.
+ main();
+
+ // In case main() returns, just sit here until the device is reset.
+ while (true) {
+ }
+}
diff --git a/pw_boot_armv7m/docs.rst b/pw_boot_armv7m/docs.rst
new file mode 100644
index 0000000..c9b3fff
--- /dev/null
+++ b/pw_boot_armv7m/docs.rst
@@ -0,0 +1,148 @@
+.. _chapter-pw-boot-armv7m:
+
+.. default-domain:: cpp
+
+.. highlight:: sh
+
+--------------
+pw_boot_armv7m
+--------------
+
+The ARMv7-M boot module provides a linker script and some early initialization
+of static memory regions and C++ constructors. This is enough to get many
+ARMv7-M cores booted and ready to run C++ code.
+
+This module is currently designed to support a very minimal device memory layout
+configuration:
+
+ - One contiguous region for RAM.
+ - One contiguous region for flash.
+ - Static, in-flash vector table at the default location expected by the SoC.
+
+Note that this module is not yet particularly suited for projects that utilize
+a bootloader, as it's relatively opinionated regarding where code is stored.
+
+.. warning::
+ This module is currently NOT stable! Depending on this module may cause
+ breakages as this module is updated.
+
+Setup
+=====
+
+User-Implemented Functions
+--------------------------
+This module expects two extern "C" functions to be defined outside this module.
+
+ - ``int main()``: This is where applications reside.
+ - ``void pw_PreMainInit()``: This function executes just before main, and
+ can be used for any device initialization that isn't application specific.
+ Depending on your platform, this might be turning on a UART, setting up
+ default clocks, etc.
+
+If either of these functions are unimplemented, executables will encounter a
+link error.
+
+Required Configs
+----------------
+This module has a number of required configuration options that mold the linker
+script to fit to a wide variety of ARMv7-M SoCs. The ``pw_boot_armv7m_config``
+GN variable has a ``defines`` member that can be used to modify these linker
+script options. See the documentation section on configuration for information
+regarding which configuration options are required.
+
+Vector Table
+------------
+Targets using pw_boot_armv7m will need to provide an ARMv7-M interrupt vector
+table (ARMv7-M Architecture Reference Manual DDI 0403E.b section B1.5.2 and
+B1.5.3). This is done by storing an array into the ``.vector_table`` section,
+and properly configuring ``PW_BOOT_INTERRUPT_VECTOR_TABLE_*`` preprocessor
+defines to cover the address region your SoC expects the vector table to be
+located at (often the beginning of the flash region). If using a bootloader,
+ensure VTOR (Vector Table Offset Register) is configured to point to the vector
+table. Otherwise, refer to the hardware vendor's documentation to determine
+where the vector table should be located such that it resides where VTOR is
+initialized to by default.
+
+Example vector table:
+
+.. code-block:: cpp
+
+ typedef void (*InterruptHandler)();
+
+ PW_KEEP_IN_SECTION(".vector_table")
+ const InterruptHandler vector_table[] = {
+ // The starting location of the stack pointer.
+ // This address is NOT an interrupt handler/function pointer, it is simply
+ // the address that the main stack pointer should be initialized to. The
+ // value is reinterpret casted because it needs to be in the vector table.
+ [0] = reinterpret_cast<InterruptHandler>(&pw_stack_high_addr),
+
+ // Reset handler, dictates how to handle reset interrupt. This is the
+ // address that the Program Counter (PC) is initialized to at boot.
+ [1] = pw_BootEntry,
+
+ // NMI handler.
+ [2] = DefaultFaultHandler,
+ // HardFault handler.
+ [3] = DefaultFaultHandler,
+ ...
+ };
+
+Usage
+=====
+
+Publicly exported symbols
+-------------------------
+The linker script provided by this module exports a number of symbols that
+may be used to retrieve the locations of specific memory regions at runtime.
+These symbols are declared as ``uint8_t`` variables. The variables themselves
+do not contain the addresses, they only reside at the memory location they
+reference. To retrieve the memory locations, simply take the reference of the
+symbol (e.g. ``&pw_vector_table_addr``).
+
+``pw_heap_[low/high]_addr``: Beginning and end of the memory range of the heap.
+These addresses may be identical, indicating a heap with a size of zero bytes.
+
+``pw_stack_[low/high]_addr``: Beginning and end of the memory range of the main
+stack. This might not be the only stack in the system.
+
+``pw_vector_table_addr``: Beginning of the ARMv7-M interrupt vector table.
+
+Configuration
+=============
+These configuration options can be controlled by appending to
+``pw_boot_armv7m_config.defines`` as part of a Pigweed target config file.
+
+**PW_BOOT_HEAP_SIZE** (required):
+How much memory (in bytes) to reserve for the heap. This can be zero.
+
+**PW_BOOT_MIN_STACK_SIZE** (required):
+The minimum size reserved for the main stack. If statically allocated memory
+begins to cut into the minimum, a link error will be emitted.
+
+**PW_BOOT_FLASH_BEGIN** (required):
+The start address of the MCU's flash region. This region must NOT include the
+vector table. (i.e. if the INTERRUPT_VECTOR_TABLE is in flash, the flash region
+should begin *after* the vtable)
+
+**PW_BOOT_FLASH_SIZE** (required):
+Size of the flash region in bytes.
+
+**PW_BOOT_RAM_BEGIN** (required):
+The start address of the MCU's RAM region.
+
+**PW_BOOT_RAM_SIZE** (required):
+Size of the RAM region in bytes.
+
+**PW_BOOT_INTERRUPT_VECTOR_TABLE_BEGIN** (required):
+Address the target MCU expects the link-time vector table to be located at. This
+is typically the beginning of the flash region. While the vector table may be
+changed later in the boot process, a minimal vector table MUST be present for
+the MCU to operate as expected.
+
+**PW_BOOT_INTERRUPT_VECTOR_TABLE_SIZE** (required):
+Number of bytes to reserve for the ARMv7-M vector table.
+
+Dependencies
+============
+ * pw_preprocessor module
diff --git a/pw_boot_armv7m/public/pw_boot_armv7m/boot.h b/pw_boot_armv7m/public/pw_boot_armv7m/boot.h
new file mode 100644
index 0000000..ab0da28
--- /dev/null
+++ b/pw_boot_armv7m/public/pw_boot_armv7m/boot.h
@@ -0,0 +1,90 @@
+// Copyright 2020 The Pigweed Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+#pragma once
+
+// This module is similar to a traditional assembly startup file paired with a
+// linker script. It turns out that everything typically done in ARMv7-M
+// assembly startup can be done straight from C code. This makes startup code
+// easier to maintain, modify, and read.
+//
+// Core initialization is comprised of two primary parts:
+//
+// 1. Load boot information from ARMv7-M Vector Table: The ARMv7-M vector table
+// (See ARMv7-M Architecture Reference Manual DDI 0403E.b section B1.5)
+// dictates the starting Program Counter (PC) and Stack Pointer (SP) when the
+// SoC powers on. The vector table also contains a number of other vectors to
+// handle different exceptions. This module does not provide a vector table,
+// but it does account for it in the linker script.
+//
+// 2. Initialize static memory: When execution begins due to SoC power-on (or
+// the device is reset), static memory regions must be initialized to ensure
+// they contains the expected values when code begins to run. The SoC doesn't
+// inherently have a notion of how to do this, so before ANYTHING else the
+// memory must be initialized. This is done at the beginning of
+// pw_BootEntry().
+//
+//
+// The simple flow is as follows:
+// Power on -> PC and SP set (from vector_table by SoC) -> pw_BootEntry()
+//
+// In pw_BootEntry():
+// Initialize memory -> pw_PreMainInit() -> main()
+
+#include "pw_preprocessor/compiler.h"
+#include "pw_preprocessor/util.h"
+
+PW_EXTERN_C_START
+
+// The following extern symbols are provided by the linker script, and their
+// values are accessible via the reference of the symbol.
+//
+// Example:
+// if (stack_pointer < &pw_stack_low_addr) {
+// PW_LOG_ERROR("Main stack overflowed!")
+// }
+
+// pw_stack_[low/high]_addr indicate the range of the main stack. Note that this
+// might not be the only stack in the system.
+//
+// The main stack pointer (sp_main) should be initialized to pw_stack_high_addr.
+// This can be done by inserting the address into index 0 of the ARMv7-M vector
+// table. (See ARMv7-M Architecture Reference Manual DDI 0403E.b section B1.5.3)
+extern uint8_t pw_stack_low_addr;
+extern uint8_t pw_stack_high_addr;
+
+// pw_heap_[low/high]_addr indicate the address range reserved for the heap.
+extern uint8_t pw_heap_low_addr;
+extern uint8_t pw_heap_high_addr;
+
+// The address that denotes the beginning of the .vector_table section. This
+// can be used to set VTOR (vector table offset register) by the bootloader.
+extern uint8_t pw_vector_table_addr;
+
+// Forward declaration of main. Pigweed applications are expected to implement
+// this function. An implementation of main() is NOT provided by this module.
+int main();
+
+// For this module to work as expected, index 1 of the ARMv7-M vector table
+// (which usually points to Reset_Handler) must be set to point to this
+// function. This function is implemented by pw_boot_armv7m, and does early
+// memory initialization.
+PW_NO_PROLOGUE void pw_BootEntry();
+
+// This function is called by pw_BootEntry() after memory initialization but
+// before main. This allows targets to have pre-main initialization of the
+// device and seamlessly swap out the main() implementation. This function is
+// NOT implemented by pw_boot_armv7m.
+void pw_PreMainInit();
+
+PW_EXTERN_C_END
diff --git a/pw_build/linker_script.gni b/pw_build/linker_script.gni
new file mode 100644
index 0000000..da64e95
--- /dev/null
+++ b/pw_build/linker_script.gni
@@ -0,0 +1,132 @@
+# Copyright 2020 The Pigweed Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not
+# use this file except in compliance with the License. You may obtain a copy of
+# the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations under
+# the License.
+
+import("$dir_pw_build/exec.gni")
+
+# Preprocess a linker script and turn it into a target.
+#
+# Note: to use this template, pw_cc_command must be specified in your target's
+# config. It should match the name of the C compiler your target uses (e.g.
+# arm-none-eabi-gcc).
+#
+# In lieu of direct GN support for linker scripts, this template makes it
+# possible to run the C Preprocessor on a linker script file so defines can
+# be properly evaluated before the linker script is passed to the dir_pw_build
+#
+# TODO(pwbug/53): This template serves as a stand-in until native GN support for
+# linker scripts is added.
+#
+# Args:
+# linker_script: The linker script to send through the C preprocessor.
+#
+# defines: Preprocessor defines to apply when running the C preprocessor.
+#
+# cflags: Flags to pass to the C compiler.
+#
+# inputs: Files that, when changed, should trigger a re-build of the linker
+# script. linker_script is implicitly added to this by the template.
+#
+# Example:
+#
+# pw_linker_script("generic_linker_script") {
+# defines = [
+# "PW_HEAP_SIZE=1K",
+# "PW_NOINIT_SIZE=512"
+# ]
+# linker_script = "basic_script.ld"
+# }
+#
+template("pw_linker_script") {
+ assert(
+ defined(pw_cc_command) && pw_cc_command != "",
+ "pw_cc_command has not been properly configured. This variable must be " +
+ "defined to enable linker script preprocessing.")
+
+ assert(
+ defined(invoker.linker_script) && invoker.linker_script != "",
+ "$target_name did not set `linker_script` to refer to a valid linker " +
+ "script. This variable is required for linker script targets.")
+
+ _final_linker_script = "${target_gen_dir}/${target_name}_final.ld"
+
+ # This action invokes the C compiler provided by the target to preprocess the
+ # linker script.
+ pw_exec("${target_name}_preprocess") {
+ program = pw_cc_command
+ inputs = [
+ invoker.linker_script,
+ ]
+ args = [
+ # Run compiler in preprocessor-only mode.
+ "-E",
+
+ # Do not generate linemarkers in output.
+ "-P",
+
+ # Do not discard comments.
+ "-C",
+
+ # Treat the following file as a C file.
+ "-x",
+ "c",
+ rebase_path(invoker.linker_script),
+ ]
+
+ # Include any explicitly listed c flags.
+ if (defined(invoker.cflags)) {
+ args += cflags
+ }
+
+ # Add defines.
+ if (defined(invoker.defines)) {
+ args += process_file_template(invoker.defines, "-D{{source_name_part}}")
+ }
+
+ # Set output file.
+ args += [
+ "-o",
+ _final_linker_script,
+ ]
+ outputs = [
+ _final_linker_script,
+ ]
+ }
+
+ # This config adds a the linker script produced by the preprocess action to
+ # the linker flags.
+ config("${target_name}_config") {
+ inputs = [
+ invoker.linker_script,
+ ]
+ if (!defined(invoker.ldflags)) {
+ ldflags = []
+ }
+ ldflags += [ "-T" + rebase_path(_final_linker_script) ]
+ }
+
+ # The target that adds the linker script config to this library and everything
+ # that depends on it.
+ source_set(target_name) {
+ inputs = [
+ _final_linker_script,
+ ]
+ if (defined(invoker.inputs)) {
+ inputs += invoker.inputs
+ }
+ all_dependent_configs = [ ":${target_name}_config" ]
+ deps = [
+ ":${target_name}_preprocess",
+ ]
+ }
+}
diff --git a/pw_dumb_io_baremetal_stm32f429/BUILD b/pw_dumb_io_baremetal_stm32f429/BUILD
index 2d9f88b..595b3c4 100644
--- a/pw_dumb_io_baremetal_stm32f429/BUILD
+++ b/pw_dumb_io_baremetal_stm32f429/BUILD
@@ -19,7 +19,6 @@
filegroup(
name = "pw_dumb_io_baremetal_stm32f429",
srcs = [
- "core_init.c",
"dumb_io_baremetal.cc",
],
)
diff --git a/pw_dumb_io_baremetal_stm32f429/BUILD.gn b/pw_dumb_io_baremetal_stm32f429/BUILD.gn
index 7eaf6f1..1a3a04a 100644
--- a/pw_dumb_io_baremetal_stm32f429/BUILD.gn
+++ b/pw_dumb_io_baremetal_stm32f429/BUILD.gn
@@ -17,21 +17,9 @@
# This if statement allows docs to always build even if the target isn't
# compatible with this backend.
if (dir_pw_dumb_io_backend == dir_pw_dumb_io_baremetal_stm32f429) {
- config("linker_script_config") {
- _linker_script = "stm32f429.ld"
- inputs = [
- _linker_script,
- ]
- ldflags = [ "-T" + rebase_path("$_linker_script") ]
- }
-
- source_set("linker_script") {
- public_configs = [ ":linker_script_config" ]
- }
-
source_set("pw_dumb_io_baremetal_stm32f429") {
public_deps = [
- ":linker_script",
+ "$dir_pw_boot_armv7m",
]
deps = [
"$dir_pw_dumb_io:default_putget_bytes",
@@ -39,7 +27,6 @@
"$dir_pw_preprocessor",
]
sources = [
- "core_init.c",
"dumb_io_baremetal.cc",
]
}
diff --git a/pw_dumb_io_baremetal_stm32f429/core_init.c b/pw_dumb_io_baremetal_stm32f429/core_init.c
deleted file mode 100644
index 15d012e..0000000
--- a/pw_dumb_io_baremetal_stm32f429/core_init.c
+++ /dev/null
@@ -1,131 +0,0 @@
-// Copyright 2019 The Pigweed Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License"); you may not
-// use this file except in compliance with the License. You may obtain a copy of
-// the License at
-//
-// https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-// License for the specific language governing permissions and limitations under
-// the License.
-
-// !!!WARNING!!!
-//
-// Some of the code in this file is run without static initialization expected
-// by C/C++. Any accesses to statically initialized objects/variables before
-// memory is initialized will result in undefined values and violates the C
-// specification. Only code run after memory initialization is complete will be
-// compliant and truly safe to run. In general, make early initialization code
-// run AFTER memory initialization has complete unless it is ABSOLUTELY
-// NECESSARY to modify the way memory is initialized.
-//
-// This file is similar to a traditional assembly startup file. It turns out
-// that everything typically done in ARMv7-M assembly startup can be done
-// straight from C code. This makes startup code easier to maintain, modify,
-// and read.
-//
-// Core initialization is comprised of two primary parts:
-//
-// 1. Initialize ARMv7-M Vector Table: The ARMv7-M vector table (See ARMv7-M
-// Architecture Reference Manual DDI 0403E.b section B1.5) dictates the
-// starting program counter (PC) and stack pointer (SP) when the SoC powers
-// on. The vector table also contains a number of other vectors to handle
-// different exceptions. This file omits many of the vectors and only
-// configures the four most important ones.
-//
-// 2. Initialize Memory: When execution begins due to SoC power-on (or the
-// device is reset), memory must be initialized to ensure it contains the
-// expected values when code begins to run. The SoC doesn't inherently have a
-// notion of how to do this, so before ANYTHING else the memory must be
-// initialized. This is done at the beginning of pw_FirmwareInit().
-//
-//
-// The simple flow is as follows:
-// Power on -> PC and SP set (from vector_table by SoC) -> pw_FirmwareInit()
-//
-// In pw_FirmwareInit():
-// Initialize memory -> initialize board (pre-main init) -> main()
-
-#include <stdbool.h>
-#include <stdint.h>
-#include <string.h>
-
-#include "pw_preprocessor/compiler.h"
-
-// Extern symbols referenced in the vector table.
-extern const uint8_t _stack_end[];
-extern uint8_t _static_init_ram_start[];
-extern uint8_t _static_init_ram_end[];
-extern uint8_t _static_init_flash_start[];
-extern uint8_t _zero_init_ram_start[];
-extern uint8_t _zero_init_ram_end[];
-
-// Functions called as part of firmware initialization.
-void __libc_init_array(void);
-void pw_BoardInit(void);
-int main(void);
-
-void DefaultFaultHandler(void) {
- while (true) {
- // Wait for debugger to attach.
- }
-}
-
-// WARNING: This code is run immediately upon boot, and performs initialization
-// of RAM. Note that code running before this function finishes memory
-// initialization will violate the C spec (Section 6.7.8, paragraph 10 for
-// example, which requires uninitialized static values to be zero-initialized).
-// Be EXTREMELY careful when running code before this function finishes RAM
-// initialization.
-//
-// This function runs immediately at boot because it is at index 1 of the
-// interrupt vector table.
-PW_NO_PROLOGUE void pw_FirmwareInit() {
- // Begin memory initialization.
- // Static-init RAM.
- memcpy(_static_init_ram_start,
- _static_init_flash_start,
- _static_init_ram_end - _static_init_ram_start);
-
- // Zero-init RAM.
- memset(_zero_init_ram_start, 0, _zero_init_ram_end - _zero_init_ram_start);
-
- // Call static constructors.
- __libc_init_array();
-
- // End memory initialization.
-
- // Do any necessary board init.
- pw_BoardInit();
-
- // Run main.
- main();
-
- // In case main() returns, just sit here until the device is reset.
- while (true) {
- }
-}
-
-// This is the device's interrupt vector table. It's not referenced in any
-// code because the platform (STM32F4xx) expects this table to be present at the
-// beginning of flash.
-//
-// For more information, see ARMv7-M Architecture Reference Manual DDI 0403E.b
-// section B1.5.3.
-PW_KEEP_IN_SECTION(".vector_table")
-const uint32_t vector_table[] = {
- // The starting location of the stack pointer.
- [0] = (uint32_t)_stack_end,
-
- // Reset handler, dictates how to handle reset interrupt. This is also run
- // at boot.
- [1] = (uint32_t)pw_FirmwareInit,
-
- // NMI handler.
- [2] = (uint32_t)DefaultFaultHandler,
- // HardFault handler.
- [3] = (uint32_t)DefaultFaultHandler,
-};
diff --git a/pw_dumb_io_baremetal_stm32f429/dumb_io_baremetal.cc b/pw_dumb_io_baremetal_stm32f429/dumb_io_baremetal.cc
index 1c6b288..1810d28 100644
--- a/pw_dumb_io_baremetal_stm32f429/dumb_io_baremetal.cc
+++ b/pw_dumb_io_baremetal_stm32f429/dumb_io_baremetal.cc
@@ -14,6 +14,7 @@
#include <cinttypes>
+#include "pw_boot_armv7m/boot.h"
#include "pw_dumb_io/dumb_io.h"
#include "pw_preprocessor/compiler.h"
@@ -132,9 +133,49 @@
volatile UsartBlock& usart1 =
*reinterpret_cast<volatile UsartBlock*>(kApb2PeripheralBase + 0x1000U);
+// Default handler to insert into the ARMv7-M vector table (below).
+// This function exists for convenience. If a device isn't doing what you
+// expect, it might have hit a fault and ended up here.
+void DefaultFaultHandler(void) {
+ while (true) {
+ // Wait for debugger to attach.
+ }
+}
+
+// This is the device's interrupt vector table. It's not referenced in any
+// code because the platform (STM32F4xx) expects this table to be present at the
+// beginning of flash. The exact address is specified in the pw_boot_armv7m
+// configuration as part of the target config.
+//
+// For more information, see ARMv7-M Architecture Reference Manual DDI 0403E.b
+// section B1.5.3.
+
+// This typedef is for convenience when building the vector table. With the
+// exception of SP_main (0th entry in the vector table), all the entries of the
+// vector table are function pointers.
+typedef void (*InterruptHandler)();
+
+PW_KEEP_IN_SECTION(".vector_table")
+const InterruptHandler vector_table[] = {
+ // The starting location of the stack pointer.
+ // This address is NOT an interrupt handler/function pointer, it is simply
+ // the address that the main stack pointer should be initialized to. The
+ // value is reinterpret casted because it needs to be in the vector table.
+ [0] = reinterpret_cast<InterruptHandler>(&pw_stack_high_addr),
+
+ // Reset handler, dictates how to handle reset interrupt. This is the
+ // address that the Program Counter (PC) is initialized to at boot.
+ [1] = pw_BootEntry,
+
+ // NMI handler.
+ [2] = DefaultFaultHandler,
+ // HardFault handler.
+ [3] = DefaultFaultHandler,
+};
+
} // namespace
-extern "C" void pw_BoardInit() {
+extern "C" void pw_PreMainInit() {
// Enable 'A' GIPO clocks.
platform_rcc.ahb1_config |= kGpioAEnable;
diff --git a/pw_dumb_io_baremetal_stm32f429/stm32f429.ld b/pw_dumb_io_baremetal_stm32f429/stm32f429.ld
deleted file mode 100644
index 0a63372..0000000
--- a/pw_dumb_io_baremetal_stm32f429/stm32f429.ld
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Copyright 2019 The Pigweed Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-
-HIDDEN(_min_stack_size = 1K);
-
-/* Note: This technically doesn't set the firmware's entry point. Setting the
- * firmware entry point is done by setting vector_table[1] in core_init.c.
- * However, this DOES tell the compiler how to optimize when --gc-sections
- * is enabled.
- */
-ENTRY(pw_FirmwareInit)
-
-MEMORY
-{
- /* Internal Flash */
- FLASH(rx) : ORIGIN = 0x08000000, LENGTH = 512K
- /* Internal SRAM */
- RAM(rwx) : ORIGIN = 0x20000000, LENGTH = 192K
-}
-
-SECTIONS
-{
-
- /* Main executable code. */
- .code : ALIGN(8)
- {
- /* STM32F4xx expects the vector table to be at the beginning of flash. */
- KEEP(*(.vector_table))
-
- . = ALIGN(8);
- /* Application code. */
- *(.text)
- *(.text*)
- KEEP(*(.init))
- KEEP(*(.fini))
-
- . = ALIGN(8);
- /* Constants.*/
- *(.rodata)
- *(.rodata*)
-
- /* .preinit_array, .init_array, .fini_array are used by libc.
- * Each section is a list of function pointers that are called pre-main and
- * post-exit for object initialization and tear-down.
- * Since the region isn't explicitly referenced, specify KEEP to prevent
- * link-time garbage collection. SORT is used for sections that have strict
- * init/de-init ordering requirements. */
- . = ALIGN(8);
- PROVIDE_HIDDEN (__preinit_array_start = .);
- KEEP (*(.preinit_array*))
- PROVIDE_HIDDEN (__preinit_array_end = .);
-
- PROVIDE_HIDDEN (__init_array_start = .);
- KEEP (*(SORT(.init_array.*)))
- KEEP (*(.init_array*))
- PROVIDE_HIDDEN (__init_array_end = .);
-
- PROVIDE_HIDDEN (__fini_array_start = .);
- KEEP (*(SORT(.fini_array.*)))
- KEEP (*(.fini_array*))
- PROVIDE_HIDDEN (__fini_array_end = .);
- } >FLASH
-
- /* Used by unwind-arm/ */
- .ARM : ALIGN(8) {
- __exidx_start = .;
- *(.ARM.exidx*)
- __exidx_end = .;
- } >FLASH
-
- /* Explicitly initialized global and static data. (.data)*/
- .static_init_ram : ALIGN(8)
- {
- *(.data)
- *(.data*)
- . = ALIGN(8);
- } >RAM AT> FLASH
-
- /* Zero initialized global/static data. (.bss)
- * This section is zero initialized in pw_FirmwareInit(). */
- .zero_init_ram : ALIGN(8)
- {
- *(.bss)
- *(.bss*)
- *(COMMON)
- . = ALIGN(8);
- } >RAM
-
- /* Link-time check for stack overlaps. */
- .stack (NOLOAD) : ALIGN(8)
- {
- HIDDEN(_stack_size = ORIGIN(RAM) + LENGTH(RAM) - .);
- ASSERT(_stack_size >= _min_stack_size, "Error: Not enough RAM for stack.");
- . = . + _stack_size;
- } >RAM
-}
-
-/* Symbols used by core_init.c: */
-/* Top of stack to set stack pointer. */
-_stack_end = ORIGIN(RAM) + LENGTH(RAM);
-
-/* Start of .static_init_ram in FLASH. */
-_static_init_flash_start = LOADADDR(.static_init_ram);
-
-/* Region of .static_init_ram in RAM. */
-_static_init_ram_start = ADDR(.static_init_ram);
-_static_init_ram_end = _static_init_ram_start + SIZEOF(.static_init_ram);
-
-/* Region of .zero_init_ram. */
-_zero_init_ram_start = ADDR(.zero_init_ram);
-_zero_init_ram_end = _zero_init_ram_start + SIZEOF(.zero_init_ram);
-
-/* arm-none-eabi expects `end` symbol to point to start of heap for sbrk. */
-PROVIDE (end = _zero_init_ram_end);
diff --git a/pw_vars_default.gni b/pw_vars_default.gni
index c5458da..071aec1 100644
--- a/pw_vars_default.gni
+++ b/pw_vars_default.gni
@@ -92,10 +92,21 @@
# empty (but defined) variable.
#
# All of these should default to empty strings. For target-specific defaults,
-# modify these variables in a target confiruation file.
+# modify these variables in a target configuration file.
+
+# Backend for the pw_boot module.
+dir_pw_boot_backend = ""
+
+# Backend for the pw_cpu_exception module.
+dir_pw_cpu_exception_backend = ""
# Backend for the pw_dumb_io module.
dir_pw_dumb_io_backend = ""
-# Backend for the pw_cpu_exception module.
-dir_pw_cpu_exception_backend = ""
+############################## MODULE CONFIGS ##################################
+
+# Module configuration options for pw_boot_armv7m.
+pw_boot_armv7m_config = {
+ # C Preprocessor defines used for linker script configuration.
+ defines = []
+}
diff --git a/targets/stm32f429i-disc1/target_config.gni b/targets/stm32f429i-disc1/target_config.gni
index f768e23..0a1b382 100644
--- a/targets/stm32f429i-disc1/target_config.gni
+++ b/targets/stm32f429i-disc1/target_config.gni
@@ -29,6 +29,11 @@
pw_use_test_server = false
}
+# Expose the tool to use for preprocessing linker scripts.
+# TODO(pwbug/53): Temporary, will be removed when proper linker script support
+# is added to GN.
+pw_cc_command = "arm-none-eabi-gcc"
+
# Executable wrapper that includes some baremetal startup code.
template("stm32f429i_executable") {
target("executable", target_name) {
@@ -45,12 +50,7 @@
# Path to the bloaty config file for the output binaries.
pw_executable_config.bloaty_config_file =
- "$dir_pw_dumb_io_baremetal_stm32f429/bloaty_config.bloaty"
-
-# Path to a linker script target. This must be a target (e.g. source_set)
-# that provides a linker script (through a public config, for example).
-linker_script_target =
- "$dir_pw_dumb_io_baremetal_stm32f429:linker_script_target"
+ "$dir_pw_boot_armv7m/bloaty_config.bloaty"
if (pw_use_test_server) {
pw_automatic_test_runner =
@@ -58,5 +58,17 @@
}
# Facade backends
-dir_pw_cpu_exception_backend = "$dir_pw_cpu_exception_armv7m"
-dir_pw_dumb_io_backend = "$dir_pw_dumb_io_baremetal_stm32f429"
+dir_pw_boot_backend = dir_pw_boot_armv7m
+dir_pw_cpu_exception_backend = dir_pw_cpu_exception_armv7m
+dir_pw_dumb_io_backend = dir_pw_dumb_io_baremetal_stm32f429
+
+pw_boot_armv7m_config.defines += [
+ "PW_BOOT_FLASH_BEGIN=0x08000200",
+ "PW_BOOT_FLASH_SIZE=512K",
+ "PW_BOOT_HEAP_SIZE=0",
+ "PW_BOOT_MIN_STACK_SIZE=1K",
+ "PW_BOOT_RAM_BEGIN=0x20000000",
+ "PW_BOOT_RAM_SIZE=192K",
+ "PW_BOOT_INTERRUPT_VECTOR_TABLE_BEGIN=0x08000000",
+ "PW_BOOT_INTERRUPT_VECTOR_TABLE_SIZE=512",
+]