Repository navigation
Expand file tree
/
Copy pathfirmware_loader.cpp
More file actions
92 lines (83 loc) · 2.93 KB
/
Copy pathfirmware_loader.cpp
File metadata and controls
92 lines (83 loc) · 2.93 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
#include <cstdint>
#include "firmware_image.h"
#include "firmware_update_engine.h"
#include "firmware_update_layout.h"
#include "hardware/structs/m0plus.h"
#include "hardware/structs/scb.h"
#include "hardware/sync.h"
#include "hardware/watchdog.h"
#include "pico/bootrom.h"
#include "pico/stdlib.h"
#include "rp2040_firmware_storage.h"
#ifndef K2_BOARD_ID
#error "K2_BOARD_ID must identify the board-specific firmware image"
#endif
namespace {
using firmware_update::BoardRevision;
using firmware_update::BootDecision;
using firmware_update::FirmwareImageManifest;
[[noreturn]] void enter_usb_recovery()
{
reset_usb_boot(0, 0);
while (true) {
tight_loop_contents();
}
}
[[noreturn]] void start_active_application(const uint8_t* slot)
{
const auto* manifest =
reinterpret_cast<const FirmwareImageManifest*>(slot);
const uint8_t* payload =
slot + firmware_update::kManifestSectorSize;
const uint32_t* vectors = reinterpret_cast<const uint32_t*>(
payload + manifest->vector_offset);
// Do not use watchdog_reboot(pc, sp, 0) here. On RP2040 that ROM shortcut
// jumps to pc before performing a normal flash boot, so the watchdog reset
// has disabled XIP by the time a relocated flash address is entered.
//
// The loader has no active IRQ-driven services. Keep XIP configured,
// install the application's vector table, and enter its normal reset
// handler. That handler initializes .data/.bss and runs the Pico SDK
// runtime initialization just as it does after a conventional boot.
watchdog_disable();
save_and_disable_interrupts();
ppb_hw->syst_csr = 0;
ppb_hw->nvic_icer = UINT32_MAX;
ppb_hw->nvic_icpr = UINT32_MAX;
// Clear pending PendSV and SysTick exceptions.
scb_hw->icsr = (1u << 27) | (1u << 25);
scb_hw->vtor = reinterpret_cast<uintptr_t>(vectors);
const uint32_t stack_pointer = vectors[0];
const uint32_t reset_handler = vectors[1];
__asm volatile(
"dsb\n"
"isb\n"
"msr msp, %0\n"
"cpsie i\n"
"bx %1\n"
:
: "r"(stack_pointer), "r"(reset_handler)
: "memory");
__builtin_unreachable();
while (true) {
tight_loop_contents();
}
}
} // namespace
int main()
{
static_assert(K2_BOARD_ID == static_cast<int>(BoardRevision::B0C) ||
K2_BOARD_ID == static_cast<int>(BoardRevision::B3B));
constexpr BoardRevision board = static_cast<BoardRevision>(K2_BOARD_ID);
const auto* active = reinterpret_cast<const uint8_t*>(
firmware_update::kXipBase + firmware_update::kActiveOffset);
Rp2040FirmwareStorage storage;
switch (firmware_update::process_firmware_boot(storage, board)) {
case BootDecision::StartActive:
start_active_application(active);
case BootDecision::EnterUsbRecovery:
case BootDecision::Interrupted:
case BootDecision::FlashError:
enter_usb_recovery();
}
}