Skip to content

Commit 4d03edc

Browse files
authored
Don't go through runtime initializers when there is no OTA command (#2697)
Leave that to the main app instead, so we don't reset peripherals twice. * ota: fix copy error for riscv headers * ota: initialize bootrom bit ops and add explanation
1 parent d5a6888 commit 4d03edc

File tree

6 files changed

+67
-28
lines changed

6 files changed

+67
-28
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,7 @@ system
33
tools/dist
44
docs/_build
55
ota/build
6+
ota/build-rp2350
7+
ota/build-rp2350-riscv
68
tools/libpico/build
79
platform.local.txt

lib/rp2040/ota.o

68 Bytes
Binary file not shown.

lib/rp2350-riscv/ota.o

76 Bytes
Binary file not shown.

lib/rp2350/ota.o

172 Bytes
Binary file not shown.

ota/CMakeLists.txt

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ target_compile_definitions(ota PUBLIC
6363
PICO_RP2040_B2_SUPPORTED=1
6464
PICO_PRINTF_SUPPORT_FLOAT=0
6565
PICO_PRINTF_SUPPORT_LONG_LONG=0
66+
PICO_RUNTIME_INIT_AEABI_BIT_OPS=00090
67+
PICO_RUNTIME_INIT_AEABI_MEM_OPS=00091
6668
LIB_PICO_PRINTF_NONE=1
6769
LFS_READONLY=1
6870
LFS_NO_DEBUG=1
@@ -112,5 +114,12 @@ target_link_libraries(ota
112114
add_custom_command(TARGET ota POST_BUILD
113115
COMMAND ../../system/${TUPLE}/bin/${TUPLE}-ld -r -A ${OBJARCH} -b binary -o ota.o ota.bin
114116
COMMAND ../../system/${TUPLE}/bin/${TUPLE}-objcopy --rename-section .data=.OTA ota.o ../../lib/${cpu}/ota.o
115-
COMMAND cp ../ota_command.h ../../include/${cpu}/pico_base/pico/.
116117
)
118+
119+
if(NOT ${cpu} MATCHES "rp2350-riscv$")
120+
# riscv build uses the same include directories in lib/rp2350-riscv/platform_inc.txt
121+
# so we don't copy in that case
122+
add_custom_command(TARGET ota POST_BUILD
123+
COMMAND cp ../ota_command.h ../../include/${cpu}/pico_base/pico/.
124+
)
125+
endif()

ota/ota.c

Lines changed: 55 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include <hardware/sync.h>
2525
#include <hardware/flash.h>
2626
#include <pico/time.h>
27+
#include <pico/runtime_init.h>
2728
#include <hardware/gpio.h>
2829
#include <hardware/uart.h>
2930
#include <hardware/watchdog.h>
@@ -54,26 +55,33 @@ void dumphex(uint32_t x) {
5455
}
5556

5657
extern OTACmdPage _ota_cmd;
57-
void do_ota() {
58+
static uint32_t blockToErase;
59+
60+
61+
bool has_ota() {
5862
if (*__FS_START__ == *__FS_END__) {
59-
return;
63+
return false;
6064
}
6165
if (!lfsMount(*__FS_START__, 4096, *__FS_END__ - *__FS_START__)) {
62-
uart_puts(uart0, "mount failed\n");
63-
return;
66+
return false;
6467
}
6568

6669
// We are very naughty and record the last block read, since it should be the actual data block of the
6770
// OTA structure. We'll erase it behind the scenes to avoid bringing in all of LittleFS write infra.
68-
uint32_t blockToErase;
6971
if (!lfsReadOTA(&_ota_cmd, &blockToErase)) {
70-
return;
72+
return false;
7173
}
7274

7375
if (memcmp(_ota_cmd.sign, "Pico OTA", 8)) {
74-
return; // No signature
76+
return false; // No signature
7577
}
7678

79+
return true;
80+
}
81+
82+
83+
84+
void do_ota() {
7785
uint32_t crc = 0xffffffff;
7886
const uint8_t *data = (const uint8_t *)&_ota_cmd;
7987
for (uint32_t i = 0; i < offsetof(OTACmdPage, crc32); i++) {
@@ -159,31 +167,18 @@ void do_ota() {
159167

160168
// Do a hard reset just in case the start up sequence is not the same
161169
watchdog_reboot(0, 0, 100);
170+
while (true) {
171+
tight_loop_contents();
172+
}
162173
}
163174

164-
165175
#pragma GCC push_options
166176
#pragma GCC optimize("O0")
167-
int main(int a, char **b) {
168-
(void) a;
169-
(void) b;
170-
171-
#ifdef DEBUG
172-
uart_init(uart0, 115200);
173-
gpio_set_function(0, GPIO_FUNC_UART);
174-
gpio_set_function(1, GPIO_FUNC_UART);
175-
uart_set_hw_flow(uart0, false, false);
176-
uart_set_format(uart0, 8, 1, UART_PARITY_NONE);
177-
#endif
178-
179-
do_ota();
180-
177+
__attribute__((noreturn))
178+
void boot_normal() {
181179
#ifdef __riscv
182180
extern void __mainapp();
183181
__mainapp();
184-
185-
// Should never get here!
186-
return 0;
187182
#else
188183
// Reset the interrupt/etc. vectors to the real app. Will be copied to RAM in app's runtime_init
189184
scb_hw->vtor = (uint32_t)0x10003000;
@@ -194,10 +189,43 @@ int main(int a, char **b) {
194189
register void (*fcn)(void) = (void (*)(void)) *(uint32_t *)0x10003004;
195190
sp = (uint32_t *)_sp;
196191
fcn();
192+
(void)sp;
193+
#endif
194+
195+
__builtin_unreachable();
196+
}
197+
198+
void check_ota() {
199+
// this runs before the full runtime and hardware is initialized to prevent
200+
// initialization happening again in the application. Care must be taken that
201+
// no uninitialized peripheral or part of the runtime is used.
202+
// If necessary, init routines can be moved before check_ota() by adjusting
203+
// their PICO_RUNTIME_INIT_* in CMakeLists.txt.
204+
// refer to this source for existing init routines:
205+
// https://github.com/raspberrypi/pico-sdk/blob/2.1.0/src/rp2_common/pico_runtime_init/include/pico/runtime_init.h
206+
if (!has_ota()) {
207+
boot_normal();
208+
}
209+
}
210+
PICO_RUNTIME_INIT_FUNC_RUNTIME(check_ota, "00099");
211+
212+
int main(int a, char **b) {
213+
(void) a;
214+
(void) b;
197215

198-
// Should never get here!
199-
return *sp;
216+
#ifdef DEBUG
217+
uart_init(uart0, 115200);
218+
gpio_set_function(0, GPIO_FUNC_UART);
219+
gpio_set_function(1, GPIO_FUNC_UART);
220+
uart_set_hw_flow(uart0, false, false);
221+
uart_set_format(uart0, 8, 1, UART_PARITY_NONE);
200222
#endif
223+
224+
// if we arrive here, it looks like we have an OTA command in the LittleFS
225+
do_ota();
226+
227+
// fallback to normal boot if do_ota() failed, e.g. due to CRC failure or corruption
228+
boot_normal();
201229
}
202230
#pragma GCC pop_options
203231

0 commit comments

Comments
 (0)