pw_boot_armv7m: add pw_boot_PostMain()
Adds a hook which is invoked after main() returns which is
provided by the user and must never return.
This is immediately used by lm3s6965evb-qemu to remove QEMU
specific details out of pw_boot_armv7m.
Change-Id: If4c68411c7158354ac0d7cd472f959cbcdfcd13b
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/16701
Commit-Queue: Ewout van Bekkum <ewout@google.com>
Reviewed-by: Keir Mierle <keir@google.com>
diff --git a/pw_boot_armv7m/BUILD.gn b/pw_boot_armv7m/BUILD.gn
index 2e3c6ff..85fb257 100644
--- a/pw_boot_armv7m/BUILD.gn
+++ b/pw_boot_armv7m/BUILD.gn
@@ -22,10 +22,6 @@
# TODO(frolv): Move this into pw_boot module when it is created.
pw_boot_BACKEND = ""
- # Whether or not to include code that signals to QEMU to shut down the
- # emulator. This should only be enabled on QEMU targets.
- pw_boot_armv7m_QEMU_SHUTDOWN = false
-
# This list should contain the necessary defines for setting pw_boot linker
# script memory regions.
pw_boot_armv7m_LINK_CONFIG_DEFINES = []
@@ -49,9 +45,6 @@
":armv7m_linker_script",
"$dir_pw_preprocessor",
]
- if (pw_boot_armv7m_QEMU_SHUTDOWN) {
- defines = [ "PW_BOOT_ARMV7M_QEMU_SHUTDOWN=1" ]
- }
public = [ "public/pw_boot_armv7m/boot.h" ]
sources = [ "core_init.c" ]
}
diff --git a/pw_boot_armv7m/core_init.c b/pw_boot_armv7m/core_init.c
index 49200a8..c1b7307 100644
--- a/pw_boot_armv7m/core_init.c
+++ b/pw_boot_armv7m/core_init.c
@@ -49,6 +49,7 @@
// 3.4. Static C++ constructors
// 3.5. pw_boot_PreMainInit()
// 3.6. main()
+// 3.7. pw_boot_PostMain()
#include <stdbool.h>
#include <stdint.h>
@@ -119,13 +120,8 @@
// Run main.
main();
-#if PW_BOOT_ARMV7M_QEMU_SHUTDOWN
- // QEMU requires a special command to tell the VM to shut down.
- volatile uint32_t* aircr = (uint32_t*)(0xE000ED0CU);
- *aircr = 0x5fa0004;
-#endif // PW_BOOT_ARMV7M_QEMU_SHUTDOWN
+ // In case main() returns, invoke this hook.
+ pw_boot_PostMain();
- // In case main() returns, just sit here until the device is reset.
- while (true) {
- }
+ PW_UNREACHABLE;
}
diff --git a/pw_boot_armv7m/docs.rst b/pw_boot_armv7m/docs.rst
index 7696a9b..74bdd86 100644
--- a/pw_boot_armv7m/docs.rst
+++ b/pw_boot_armv7m/docs.rst
@@ -41,6 +41,8 @@
// C++ static constructors are invoked.
pw_boot_PreMainInit(); // User-implemented function.
main(); // User-implemented function.
+ pw_boot_PostMain(); // User-implemented function.
+ PW_UNREACHABLE;
}
Setup
@@ -48,7 +50,8 @@
User-Implemented Functions
--------------------------
-This module expects three extern "C" functions to be defined outside this module.
+This module expects all of these extern "C" functions to be defined outside this
+module:
- ``int main()``: This is where applications reside.
- ``void pw_boot_PreStaticMemoryInit()``: This function executes just before
@@ -89,6 +92,13 @@
Depending on your platform, this might be turning on a UART, setting up
default clocks, etc.
+ - ``PW_NO_RETURN void pw_boot_PostMain()``: This function executes after main
+ has returned. This could be used for device specific teardown such as an
+ infinite loop, soft reset, or QEMU shutdown. In addition, if relevant for
+ your application, this would be the place to invoke the global static
+ destructors. This function must not return!
+
+
If any of these functions are unimplemented, executables will encounter a link
error.
diff --git a/pw_boot_armv7m/public/pw_boot_armv7m/boot.h b/pw_boot_armv7m/public/pw_boot_armv7m/boot.h
index dfe990f..9b683d5 100644
--- a/pw_boot_armv7m/public/pw_boot_armv7m/boot.h
+++ b/pw_boot_armv7m/public/pw_boot_armv7m/boot.h
@@ -95,7 +95,8 @@
// .data section in an ELF file).
// WARNING: Be EXTREMELY careful when in the context of this function as it
// violates the C spec in several ways as .bss has not yet been zero-initialized
-// and static values have not yet been loaded into memory.
+// and static values have not yet been loaded into memory. This function is NOT
+// implemented by pw_boot_armv7m.
void pw_boot_PreStaticMemoryInit();
// pw_boot hook: Before C++ static constructors are invoked (user supplied).
@@ -104,7 +105,8 @@
// after zero initialization of RAM and loading values into static memory
// (commonly labeled as the .data section in an ELF file). Per the naming, this
// function is called just before C++ static constructors are invoked. It is
-// safe to run C code, but NOT safe to call out to any C++ code.
+// safe to run C code, but NOT safe to call out to any C++ code. This function
+// is NOT implemented by pw_boot_armv7m.
void pw_boot_PreStaticConstructorInit();
// pw_boot hook: Before main is invoked (user supplied).
@@ -116,4 +118,11 @@
// pw_boot_armv7m.
void pw_boot_PreMainInit();
+// pw_boot hook: After main returned (user supplied).
+//
+// This is a hook function that users of pw_boot must supply. It is called by
+// pw_boot_Entry() after main() has returned. This function must not return!
+// This function is NOT implemented by pw_boot_armv7m.
+PW_NO_RETURN void pw_boot_PostMain();
+
PW_EXTERN_C_END
diff --git a/pw_preprocessor/public/pw_preprocessor/compiler.h b/pw_preprocessor/public/pw_preprocessor/compiler.h
index 550109e..8f87dbd 100644
--- a/pw_preprocessor/public/pw_preprocessor/compiler.h
+++ b/pw_preprocessor/public/pw_preprocessor/compiler.h
@@ -70,7 +70,7 @@
// Indicate to the compiler that the annotated function won't return. Example:
//
-// void HandleAssertFailure(ErrorCode error_code) PW_NO_RETURN;
+// PW_NO_RETURN void HandleAssertFailure(ErrorCode error_code);
//
#define PW_NO_RETURN __attribute__((noreturn))
diff --git a/targets/lm3s6965evb-qemu/early_boot.c b/targets/lm3s6965evb-qemu/early_boot.c
index 27bf869..0d1922f 100644
--- a/targets/lm3s6965evb-qemu/early_boot.c
+++ b/targets/lm3s6965evb-qemu/early_boot.c
@@ -13,6 +13,7 @@
// the License.
#include "pw_boot_armv7m/boot.h"
+#include "pw_preprocessor/compiler.h"
#include "pw_sys_io_baremetal_lm3s6965evb/init.h"
void pw_boot_PreStaticMemoryInit() {
@@ -28,3 +29,14 @@
void pw_boot_PreStaticConstructorInit() {}
void pw_boot_PreMainInit() { pw_sys_io_Init(); }
+
+PW_NO_RETURN void pw_boot_PostMain() {
+ // QEMU requires a special command to tell the VM to shut down.
+ volatile uint32_t* aircr = (uint32_t*)(0xE000ED0CU);
+ *aircr = 0x5fa0004;
+
+ // In case main() returns, just sit here until the device is reset.
+ while (1) {
+ }
+ PW_UNREACHABLE;
+}
diff --git a/targets/lm3s6965evb-qemu/target_toolchains.gni b/targets/lm3s6965evb-qemu/target_toolchains.gni
index bd4044b..d2d2d02 100644
--- a/targets/lm3s6965evb-qemu/target_toolchains.gni
+++ b/targets/lm3s6965evb-qemu/target_toolchains.gni
@@ -33,9 +33,6 @@
pw_unit_test_AUTOMATIC_RUNNER = get_path_info(_test_runner_script, "abspath")
- # Tell QEMU to shut down after running a binary.
- pw_boot_armv7m_QEMU_SHUTDOWN = true
-
# Facade backends
pw_assert_BACKEND = dir_pw_assert_basic
pw_boot_BACKEND = dir_pw_boot_armv7m
diff --git a/targets/stm32f429i-disc1/early_boot.c b/targets/stm32f429i-disc1/early_boot.c
index 0e07163..e372eaa 100644
--- a/targets/stm32f429i-disc1/early_boot.c
+++ b/targets/stm32f429i-disc1/early_boot.c
@@ -14,6 +14,7 @@
#include "pw_boot_armv7m/boot.h"
#include "pw_malloc/malloc.h"
+#include "pw_preprocessor/compiler.h"
#include "pw_sys_io_baremetal_stm32f429/init.h"
void pw_boot_PreStaticMemoryInit() {
@@ -38,3 +39,10 @@
}
void pw_boot_PreMainInit() { pw_sys_io_Init(); }
+
+PW_NO_RETURN void pw_boot_PostMain() {
+ // In case main() returns, just sit here until the device is reset.
+ while (1) {
+ }
+ PW_UNREACHABLE;
+}