mirror of
https://github.com/espressif/esp-idf.git
synced 2025-12-07 17:08:49 +00:00
bootloader: override the 2nd stage bootloader
Add the possibility to have user bootloader components. This is performed from an application/project, by creating bootloader components. To do so, it is required to create a `bootloader_component` directory containing the custom modules to be compiled with the bootloader. Thanks to this, two solutions are available to override the bootloader now: - Using hooks within a user bootloader component - Using a user defined `main` bootloader component to totally override the old implementation Please check the two new examples in `examples/custom_bootloader` * Closes https://github.com/espressif/esp-idf/issues/7043
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
# For more information about build system see
|
||||
# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html
|
||||
# The following five lines of boilerplate have to be in your project's
|
||||
# CMakeLists in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(main)
|
||||
8
examples/custom_bootloader/bootloader_override/Makefile
Normal file
8
examples/custom_bootloader/bootloader_override/Makefile
Normal file
@@ -0,0 +1,8 @@
|
||||
#
|
||||
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
|
||||
# project subdirectory.
|
||||
#
|
||||
|
||||
PROJECT_NAME := bootloader_override
|
||||
|
||||
include $(IDF_PATH)/make/project.mk
|
||||
49
examples/custom_bootloader/bootloader_override/README.md
Normal file
49
examples/custom_bootloader/bootloader_override/README.md
Normal file
@@ -0,0 +1,49 @@
|
||||
# Bootloader override
|
||||
|
||||
(See the README.md file in the upper level for more information about bootloader examples.)
|
||||
|
||||
The purpose of this example is to show how to override the second stage bootloader from a regular project.
|
||||
|
||||
**NOTE**: Overriding the bootloader is not supported with `Makefile` build system, it is only available with `CMake`.
|
||||
|
||||
## How to use example
|
||||
|
||||
Simply compile it:
|
||||
```
|
||||
idf.py build
|
||||
```
|
||||
|
||||
And flash it with the following commands:
|
||||
```
|
||||
idf.py flash
|
||||
```
|
||||
|
||||
This custom bootloader does not do more than the older bootloader, it only prints an extra message on start up:
|
||||
```
|
||||
[boot] Custom bootloader has been initialized correctly.
|
||||
```
|
||||
|
||||
## Organisation of this example
|
||||
|
||||
This project contains an application, in the `main` directory that represents a user program.
|
||||
It also contains a `bootloader_components` directory that, as it name states, contains a component that will override the current bootloader implementation.
|
||||
|
||||
Below is a short explanation of files in the project folder.
|
||||
|
||||
```
|
||||
├── CMakeLists.txt
|
||||
├── main
|
||||
│ ├── CMakeLists.txt
|
||||
│ └── main.c User application
|
||||
├── bootloader_components
|
||||
│ └── main
|
||||
│ ├── component.mk
|
||||
│ ├── CMakeLists.txt
|
||||
│ ├── ld/
|
||||
│ │ └── ...
|
||||
│ └── bootloader_start.c Implementation of the second stage bootloader
|
||||
└── README.md This is the file you are currently reading
|
||||
```
|
||||
|
||||
As stated in the `README.md` file in the upper level, when the bootloader components is named `main`, it overrides
|
||||
the whole second stage bootloader code.
|
||||
@@ -0,0 +1,9 @@
|
||||
idf_component_register(SRCS "bootloader_start.c"
|
||||
REQUIRES bootloader bootloader_support)
|
||||
|
||||
idf_build_get_property(target IDF_TARGET)
|
||||
# Use the linker script files from the actual bootloader
|
||||
set(scripts "${IDF_PATH}/components/bootloader/subproject/main/ld/${target}/bootloader.ld"
|
||||
"${IDF_PATH}/components/bootloader/subproject/main/ld/${target}/bootloader.rom.ld")
|
||||
|
||||
target_linker_script(${COMPONENT_LIB} INTERFACE "${scripts}")
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <stdbool.h>
|
||||
#include "esp_log.h"
|
||||
#include "bootloader_init.h"
|
||||
#include "bootloader_utility.h"
|
||||
#include "bootloader_common.h"
|
||||
|
||||
static const char* TAG = "boot";
|
||||
|
||||
static int select_partition_number(bootloader_state_t *bs);
|
||||
|
||||
/*
|
||||
* We arrive here after the ROM bootloader finished loading this second stage bootloader from flash.
|
||||
* The hardware is mostly uninitialized, flash cache is down and the app CPU is in reset.
|
||||
* We do have a stack, so we can do the initialization in C.
|
||||
*/
|
||||
void __attribute__((noreturn)) call_start_cpu0(void)
|
||||
{
|
||||
// 1. Hardware initialization
|
||||
if (bootloader_init() != ESP_OK) {
|
||||
bootloader_reset();
|
||||
}
|
||||
|
||||
#ifdef CONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP
|
||||
// If this boot is a wake up from the deep sleep then go to the short way,
|
||||
// try to load the application which worked before deep sleep.
|
||||
// It skips a lot of checks due to it was done before (while first boot).
|
||||
bootloader_utility_load_boot_image_from_deep_sleep();
|
||||
// If it is not successful try to load an application as usual.
|
||||
#endif
|
||||
|
||||
// 2. Select the number of boot partition
|
||||
bootloader_state_t bs = {0};
|
||||
int boot_index = select_partition_number(&bs);
|
||||
if (boot_index == INVALID_INDEX) {
|
||||
bootloader_reset();
|
||||
}
|
||||
|
||||
// 2.1 Print a custom message!
|
||||
esp_rom_printf("[%s] Custom bootloader has been initialized correctly.\n", TAG);
|
||||
|
||||
// 3. Load the app image for booting
|
||||
bootloader_utility_load_boot_image(&bs, boot_index);
|
||||
}
|
||||
|
||||
// Select the number of boot partition
|
||||
static int select_partition_number(bootloader_state_t *bs)
|
||||
{
|
||||
// 1. Load partition table
|
||||
if (!bootloader_utility_load_partition_table(bs)) {
|
||||
ESP_LOGE(TAG, "load partition table error!");
|
||||
return INVALID_INDEX;
|
||||
}
|
||||
|
||||
// 2. Select the number of boot partition
|
||||
return bootloader_utility_get_selected_boot_partition(bs);
|
||||
}
|
||||
|
||||
// Return global reent struct if any newlib functions are linked to bootloader
|
||||
struct _reent *__getreent(void)
|
||||
{
|
||||
return _GLOBAL_REENT;
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
from __future__ import print_function
|
||||
|
||||
import ttfw_idf
|
||||
|
||||
|
||||
@ttfw_idf.idf_example_test(env_tag='Example_GENERIC', target=['esp32', 'esp32s2', 'esp32c3'])
|
||||
def test_custom_bootloader_impl_example(env, _): # type: ignore
|
||||
# Test with default build configurations
|
||||
dut = env.get_dut('main', 'examples/custom_bootloader/bootloader_override')
|
||||
dut.start_app()
|
||||
|
||||
# Expect to read a message from the custom bootloader
|
||||
dut.expect('Custom bootloader has been initialized correctly.')
|
||||
|
||||
# Expect to read a message from the user application
|
||||
dut.expect('Application started!')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_custom_bootloader_impl_example()
|
||||
@@ -0,0 +1,2 @@
|
||||
idf_component_register(SRCS "bootloader_override_example_main.c"
|
||||
INCLUDE_DIRS ".")
|
||||
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <stdio.h>
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
/**
|
||||
* Nothing special is done here, everything interesting in this example
|
||||
* is done in the custom bootloader code, located in:
|
||||
* `bootloader_components/main/bootloader_start.c`
|
||||
*/
|
||||
printf("Application started!\n");
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
#
|
||||
# "main" pseudo-component makefile.
|
||||
#
|
||||
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
|
||||
Reference in New Issue
Block a user