Flash status: scan PICOBIN blocks for per-slot validity and version
This commit is contained in:
@@ -227,7 +227,12 @@ func cmdFlashStatus(args []string) error {
|
|||||||
slog.Info("flash-status",
|
slog.Info("flash-status",
|
||||||
"via", t.name,
|
"via", t.name,
|
||||||
"boot_partition", status.BootPartition,
|
"boot_partition", status.BootPartition,
|
||||||
"boot_type", status.BootType)
|
"slot_a_valid", status.SlotA.Valid,
|
||||||
|
"slot_a_version", status.SlotA.Version,
|
||||||
|
"slot_a_hash_ok", status.SlotA.HashOK,
|
||||||
|
"slot_b_valid", status.SlotB.Valid,
|
||||||
|
"slot_b_version", status.SlotB.Version,
|
||||||
|
"slot_b_hash_ok", status.SlotB.HashOK)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -128,12 +128,21 @@ struct RequestFlashStatus {
|
|||||||
auto as_tuple() { return std::tie(); }
|
auto as_tuple() { return std::tie(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct SlotInfo {
|
||||||
|
bool valid;
|
||||||
|
uint32_t version;
|
||||||
|
bool hash_ok;
|
||||||
|
auto as_tuple() const { return std::tie(valid, version, hash_ok); }
|
||||||
|
auto as_tuple() { return std::tie(valid, version, hash_ok); }
|
||||||
|
};
|
||||||
|
|
||||||
struct ResponseFlashStatus {
|
struct ResponseFlashStatus {
|
||||||
static constexpr int8_t ext_id = 15;
|
static constexpr int8_t ext_id = 15;
|
||||||
int8_t boot_partition;
|
int8_t boot_partition;
|
||||||
uint8_t boot_type;
|
SlotInfo slot_a;
|
||||||
auto as_tuple() const { return std::tie(boot_partition, boot_type); }
|
SlotInfo slot_b;
|
||||||
auto as_tuple() { return std::tie(boot_partition, boot_type); }
|
auto as_tuple() const { return std::tie(boot_partition, slot_a, slot_b); }
|
||||||
|
auto as_tuple() { return std::tie(boot_partition, slot_a, slot_b); }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct RequestListTests {
|
struct RequestListTests {
|
||||||
|
|||||||
@@ -3,12 +3,15 @@
|
|||||||
#include "pico/bootrom.h"
|
#include "pico/bootrom.h"
|
||||||
#include "hardware/flash.h"
|
#include "hardware/flash.h"
|
||||||
#include "hardware/watchdog.h"
|
#include "hardware/watchdog.h"
|
||||||
|
#include "boot/picobin.h"
|
||||||
#include "dispatch.h"
|
#include "dispatch.h"
|
||||||
#include "net.h"
|
#include "net.h"
|
||||||
#include "debug_log.h"
|
#include "debug_log.h"
|
||||||
|
|
||||||
static constexpr uint32_t XIP_BASE_ADDR = 0x10000000;
|
static constexpr uint32_t XIP_BASE_ADDR = 0x10000000;
|
||||||
static constexpr uint32_t FLASH_SIZE = 2 * 1024 * 1024;
|
static constexpr uint32_t FLASH_SIZE = 2 * 1024 * 1024;
|
||||||
|
static constexpr uint32_t SLOT_A_OFFSET = 0x00000;
|
||||||
|
static constexpr uint32_t SLOT_B_OFFSET = 0x80000;
|
||||||
static boot_reason detected_boot_reason;
|
static boot_reason detected_boot_reason;
|
||||||
|
|
||||||
static void poke_watchdog() {
|
static void poke_watchdog() {
|
||||||
@@ -88,16 +91,43 @@ std::optional<ResponseFlashWrite> handle_flash_write(const responder&, const Req
|
|||||||
return ResponseFlashWrite{};
|
return ResponseFlashWrite{};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static SlotInfo scan_slot(uint32_t flash_offset) {
|
||||||
|
SlotInfo info{};
|
||||||
|
constexpr uint32_t scan_limit = 4096;
|
||||||
|
auto* scan = reinterpret_cast<const uint32_t*>(XIP_BASE_ADDR + flash_offset);
|
||||||
|
auto* scan_end = scan + scan_limit / 4;
|
||||||
|
while (scan < scan_end && *scan != PICOBIN_BLOCK_MARKER_START) scan++;
|
||||||
|
if (scan >= scan_end) return info;
|
||||||
|
info.valid = true;
|
||||||
|
|
||||||
|
auto* p = reinterpret_cast<const uint8_t*>(scan + 1);
|
||||||
|
auto* end = reinterpret_cast<const uint8_t*>(scan + 64);
|
||||||
|
while (p + 2 <= end) {
|
||||||
|
uint8_t type = p[0];
|
||||||
|
uint8_t size_words = p[1];
|
||||||
|
if (type == PICOBIN_BLOCK_ITEM_2BS_LAST) break;
|
||||||
|
uint32_t item_bytes = static_cast<uint32_t>(size_words) * 4;
|
||||||
|
if (p + item_bytes > end) break;
|
||||||
|
if (type == PICOBIN_BLOCK_ITEM_1BS_VERSION && size_words >= 2) {
|
||||||
|
auto* words = reinterpret_cast<const uint16_t*>(p + 4);
|
||||||
|
uint16_t minor = words[0];
|
||||||
|
uint16_t major = words[1];
|
||||||
|
info.version = (static_cast<uint32_t>(major) << 16) | minor;
|
||||||
|
}
|
||||||
|
p += item_bytes;
|
||||||
|
}
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
std::optional<ResponseFlashStatus> handle_flash_status(const responder&, const RequestFlashStatus&) {
|
std::optional<ResponseFlashStatus> handle_flash_status(const responder&, const RequestFlashStatus&) {
|
||||||
ResponseFlashStatus resp;
|
ResponseFlashStatus resp;
|
||||||
boot_info_t bi;
|
boot_info_t bi;
|
||||||
if (rom_get_boot_info(&bi)) {
|
if (rom_get_boot_info(&bi))
|
||||||
resp.boot_partition = bi.partition;
|
resp.boot_partition = bi.partition;
|
||||||
resp.boot_type = bi.boot_type;
|
else
|
||||||
} else {
|
|
||||||
resp.boot_partition = -1;
|
resp.boot_partition = -1;
|
||||||
resp.boot_type = 0;
|
resp.slot_a = scan_slot(SLOT_A_OFFSET);
|
||||||
}
|
resp.slot_b = scan_slot(SLOT_B_OFFSET);
|
||||||
return resp;
|
return resp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -63,9 +63,17 @@ type RequestReboot struct{}
|
|||||||
type ResponseReboot struct{}
|
type ResponseReboot struct{}
|
||||||
|
|
||||||
type RequestFlashStatus struct{}
|
type RequestFlashStatus struct{}
|
||||||
|
|
||||||
|
type SlotInfo struct {
|
||||||
|
Valid bool
|
||||||
|
Version uint32
|
||||||
|
HashOK bool
|
||||||
|
}
|
||||||
|
|
||||||
type ResponseFlashStatus struct {
|
type ResponseFlashStatus struct {
|
||||||
BootPartition int8
|
BootPartition int8
|
||||||
BootType uint8
|
SlotA SlotInfo
|
||||||
|
SlotB SlotInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
type RequestListTests struct{}
|
type RequestListTests struct{}
|
||||||
|
|||||||
Reference in New Issue
Block a user