From babce63309fd19d774577f27bea62a265656b78c Mon Sep 17 00:00:00 2001 From: Chris Frantz Date: Mon, 6 Oct 2025 09:13:24 -0700 Subject: [PATCH 1/4] [ownership] Rename `RESCUE_GPIO` to `RESCUE_MISC_GPIO` Signed-off-by: Chris Frantz --- sw/device/silicon_creator/lib/ownership/datatypes.h | 6 +++--- sw/device/silicon_creator/lib/ownership/owner_block.c | 6 ++++-- sw/device/silicon_creator/lib/ownership/test_owner.c | 6 +++--- sw/device/silicon_creator/lib/rescue/rescue.c | 2 +- sw/device/silicon_creator/rom_ext/defs.bzl | 8 ++++---- 5 files changed, 15 insertions(+), 13 deletions(-) diff --git a/sw/device/silicon_creator/lib/ownership/datatypes.h b/sw/device/silicon_creator/lib/ownership/datatypes.h index 43e945d7e9f37..63b594b720e43 100644 --- a/sw/device/silicon_creator/lib/ownership/datatypes.h +++ b/sw/device/silicon_creator/lib/ownership/datatypes.h @@ -389,7 +389,7 @@ typedef struct owner_rescue_config { */ uint8_t protocol; /** - * The gpio configuration (if relevant, depending on `detect`). + * The misc & gpio configuration (if relevant, depending on `detect`). * * 7 2 1 0 * +---------------+--------+-------+ @@ -443,8 +443,8 @@ OT_ASSERT_SIZE(owner_rescue_config_t, 16); #define RESCUE_ENTER_ON_FAIL_BIT 7 #define RESCUE_TIMEOUT_SECONDS ((bitfield_field32_t){.mask = 0x7F, .index = 0}) -#define RESCUE_GPIO_PULL_EN_BIT 1 -#define RESCUE_GPIO_VALUE_BIT 0 +#define RESCUE_MISC_GPIO_PULL_EN_BIT 1 +#define RESCUE_MISC_GPIO_VALUE_BIT 0 #define RESCUE_DETECT ((bitfield_field32_t){.mask = 0x03, .index = 6}) #define RESCUE_DETECT_INDEX ((bitfield_field32_t){.mask = 0x3F, .index = 0}) diff --git a/sw/device/silicon_creator/lib/ownership/owner_block.c b/sw/device/silicon_creator/lib/ownership/owner_block.c index 1d0f5dc0b887f..f4cb48b4b1171 100644 --- a/sw/device/silicon_creator/lib/ownership/owner_block.c +++ b/sw/device/silicon_creator/lib/ownership/owner_block.c @@ -571,8 +571,10 @@ rom_error_t owner_block_info_isfb_erase_enable( rom_error_t owner_block_rescue_apply(const owner_rescue_config_t *rescue) { rescue_detect_t detect = bitfield_field32_read(rescue->detect, RESCUE_DETECT); uint32_t index = bitfield_field32_read(rescue->detect, RESCUE_DETECT_INDEX); - bool pull_en = bitfield_bit32_read(rescue->gpio, RESCUE_GPIO_PULL_EN_BIT); - bool gpio_value = bitfield_bit32_read(rescue->gpio, RESCUE_GPIO_VALUE_BIT); + bool pull_en = + bitfield_bit32_read(rescue->gpio, RESCUE_MISC_GPIO_PULL_EN_BIT); + bool gpio_value = + bitfield_bit32_read(rescue->gpio, RESCUE_MISC_GPIO_VALUE_BIT); switch (detect) { case kRescueDetectGpio: if (index <= kTopEarlgreyMuxedPadsLast) { diff --git a/sw/device/silicon_creator/lib/ownership/test_owner.c b/sw/device/silicon_creator/lib/ownership/test_owner.c index a2086130e428e..0ac5e64c2bb13 100644 --- a/sw/device/silicon_creator/lib/ownership/test_owner.c +++ b/sw/device/silicon_creator/lib/ownership/test_owner.c @@ -110,8 +110,8 @@ // The following preprocessor symbols are only relevant when // WITH_RESCUE_PROTOCOL is defined. -#ifndef WITH_RESCUE_GPIO_PARAM -#define WITH_RESCUE_GPIO_PARAM 0 +#ifndef WITH_RESCUE_MISC_GPIO_PARAM +#define WITH_RESCUE_MISC_GPIO_PARAM 0 #endif #ifndef WITH_RESCUE_INDEX #define WITH_RESCUE_INDEX 0 @@ -279,7 +279,7 @@ rom_error_t sku_creator_owner_init(boot_data_t *bootdata) { .length = sizeof(owner_rescue_config_t), }, .protocol = WITH_RESCUE_PROTOCOL, - .gpio = WITH_RESCUE_GPIO_PARAM, + .gpio = WITH_RESCUE_MISC_GPIO_PARAM, .timeout = WITH_RESCUE_TIMEOUT, .detect = (WITH_RESCUE_TRIGGER << 6) | WITH_RESCUE_INDEX, .start = WITH_RESCUE_START, diff --git a/sw/device/silicon_creator/lib/rescue/rescue.c b/sw/device/silicon_creator/lib/rescue/rescue.c index 97fb5ce162cc9..8f4dd83110a58 100644 --- a/sw/device/silicon_creator/lib/rescue/rescue.c +++ b/sw/device/silicon_creator/lib/rescue/rescue.c @@ -414,7 +414,7 @@ hardened_bool_t rescue_detect_entry(const owner_rescue_config_t *config) { protocol = config->protocol; detect = bitfield_field32_read(config->detect, RESCUE_DETECT); index = bitfield_field32_read(config->detect, RESCUE_DETECT_INDEX); - gpio_val = bitfield_bit32_read(config->gpio, RESCUE_GPIO_VALUE_BIT); + gpio_val = bitfield_bit32_read(config->gpio, RESCUE_MISC_GPIO_VALUE_BIT); } dbg_printf("info: rescue protocol %c\r\n", rescue_type); if (protocol != rescue_type) { diff --git a/sw/device/silicon_creator/rom_ext/defs.bzl b/sw/device/silicon_creator/rom_ext/defs.bzl index ca3d7de066c72..d6fa2153bbec0 100644 --- a/sw/device/silicon_creator/rom_ext/defs.bzl +++ b/sw/device/silicon_creator/rom_ext/defs.bzl @@ -121,7 +121,7 @@ TEST_OWNER_CONFIGS = { "WITH_RESCUE_INDEX=2", # GPIO param 3 means enable the internal pull resistor and trigger # rescue when the GPIO is high. - "WITH_RESCUE_GPIO_PARAM=3", + "WITH_RESCUE_MISC_GPIO_PARAM=3", # Timeout: 0x80=enter_on_fail, 0x05 = 5 seconds. "WITH_RESCUE_TIMEOUT=0x85", ], @@ -159,7 +159,7 @@ TEST_OWNER_CONFIGS = { "WITH_RESCUE_INDEX=2", # GPIO param 3 means enable the internal pull resistor and trigger # rescue when the GPIO is high. - "WITH_RESCUE_GPIO_PARAM=3", + "WITH_RESCUE_MISC_GPIO_PARAM=3", # Timeout: 0x80=enter_on_fail, 0x00 = No timeout. "WITH_RESCUE_TIMEOUT=0x80", # Restrict rescue to only one command @@ -188,7 +188,7 @@ TEST_OWNER_CONFIGS = { "WITH_RESCUE_INDEX=2", # GPIO param 3 means enable the internal pull resistor and trigger # rescue when the GPIO is high. - "WITH_RESCUE_GPIO_PARAM=3", + "WITH_RESCUE_MISC_GPIO_PARAM=3", # Timeout: 0x80=enter_on_fail, 0x05 = 5 seconds. "WITH_RESCUE_TIMEOUT=0x85", # Disallow all the rescue commands. @@ -207,7 +207,7 @@ TEST_OWNER_CONFIGS = { "WITH_RESCUE_INDEX=2", # GPIO param 3 means enable the internal pull resistor and trigger # rescue when the GPIO is high. - "WITH_RESCUE_GPIO_PARAM=3", + "WITH_RESCUE_MISC_GPIO_PARAM=3", # Timeout: 0x80=enter_on_fail, 0x05 = 5 seconds. "WITH_RESCUE_TIMEOUT=0x85", # Set rescue start and size to 0 to test writing past the end of the flash. From 94f3571c1f858776cd282b381e4433f79133472b Mon Sep 17 00:00:00 2001 From: Chris Frantz Date: Mon, 6 Oct 2025 10:32:42 -0700 Subject: [PATCH 2/4] [ownership, rescue] Allow rescue to be triggered by watchdog Allow rescue mode to be configured such that a watchdog timeout can trigger entry into rescue mode. 1. Add an configuration bit to the `RESCUE_MISC_GPIO` byte. 2. Trigger rescue when the configuration bit is true and the reset reason includes a watchdog timeout. 3. Add tests to verify entry into rescue after a watchdog timeout. Signed-off-by: Chris Frantz --- .../silicon_creator/lib/ownership/datatypes.h | 9 +-- sw/device/silicon_creator/lib/rescue/rescue.c | 11 +++- sw/device/silicon_creator/lib/rescue/rescue.h | 4 +- sw/device/silicon_creator/rom_ext/defs.bzl | 10 +++ .../silicon_creator/rom_ext/e2e/rescue/BUILD | 66 +++++++++++++++++++ .../rom_ext/e2e/rescue/watchdog_test.c | 63 ++++++++++++++++++ sw/device/silicon_creator/rom_ext/rom_ext.c | 7 +- 7 files changed, 161 insertions(+), 9 deletions(-) create mode 100644 sw/device/silicon_creator/rom_ext/e2e/rescue/watchdog_test.c diff --git a/sw/device/silicon_creator/lib/ownership/datatypes.h b/sw/device/silicon_creator/lib/ownership/datatypes.h index 63b594b720e43..64eb5c30b1a72 100644 --- a/sw/device/silicon_creator/lib/ownership/datatypes.h +++ b/sw/device/silicon_creator/lib/ownership/datatypes.h @@ -391,10 +391,10 @@ typedef struct owner_rescue_config { /** * The misc & gpio configuration (if relevant, depending on `detect`). * - * 7 2 1 0 - * +---------------+--------+-------+ - * | Reserved | PullEn | Value | - * +---------------+--------+-------+ + * 7 6 2 1 0 + * +-----+---------+--------+-------+ + * | WDT | Reserved| PullEn | Value | + * +-----+---------+--------+-------+ */ uint8_t gpio; /** @@ -443,6 +443,7 @@ OT_ASSERT_SIZE(owner_rescue_config_t, 16); #define RESCUE_ENTER_ON_FAIL_BIT 7 #define RESCUE_TIMEOUT_SECONDS ((bitfield_field32_t){.mask = 0x7F, .index = 0}) +#define RESCUE_MISC_GPIO_WATCHDOG_TIMEOUT_EN_BIT 7 #define RESCUE_MISC_GPIO_PULL_EN_BIT 1 #define RESCUE_MISC_GPIO_VALUE_BIT 0 #define RESCUE_DETECT ((bitfield_field32_t){.mask = 0x03, .index = 6}) diff --git a/sw/device/silicon_creator/lib/rescue/rescue.c b/sw/device/silicon_creator/lib/rescue/rescue.c index 8f4dd83110a58..8df9823ee0529 100644 --- a/sw/device/silicon_creator/lib/rescue/rescue.c +++ b/sw/device/silicon_creator/lib/rescue/rescue.c @@ -397,7 +397,8 @@ void rescue_skip_next_boot(void) { boot_svc_enter_rescue_req_init(kHardenedBoolTrue, &msg->enter_rescue_req); } -hardened_bool_t rescue_detect_entry(const owner_rescue_config_t *config) { +hardened_bool_t rescue_detect_entry(const owner_rescue_config_t *config, + uint32_t reset_reasons) { switch (rescue_requested) { case kRescueRequestEnter: return kHardenedBoolTrue; @@ -410,16 +411,24 @@ hardened_bool_t rescue_detect_entry(const owner_rescue_config_t *config) { rescue_detect_t detect = kRescueDetectBreak; uint32_t index = 0; uint32_t gpio_val = 0; + uint32_t wdt_enable = 0; if ((hardened_bool_t)config != kHardenedBoolFalse) { protocol = config->protocol; detect = bitfield_field32_read(config->detect, RESCUE_DETECT); index = bitfield_field32_read(config->detect, RESCUE_DETECT_INDEX); gpio_val = bitfield_bit32_read(config->gpio, RESCUE_MISC_GPIO_VALUE_BIT); + wdt_enable = bitfield_bit32_read(config->gpio, + RESCUE_MISC_GPIO_WATCHDOG_TIMEOUT_EN_BIT); } dbg_printf("info: rescue protocol %c\r\n", rescue_type); if (protocol != rescue_type) { dbg_printf("warning: rescue configured for protocol %c\r\n", protocol); } + + if (wdt_enable && bitfield_bit32_read(reset_reasons, kRstmgrReasonWatchdog)) { + return kHardenedBoolTrue; + } + switch (detect) { case kRescueDetectNone: break; diff --git a/sw/device/silicon_creator/lib/rescue/rescue.h b/sw/device/silicon_creator/lib/rescue/rescue.h index d2efb73870cdf..6b00c0ccc9df5 100644 --- a/sw/device/silicon_creator/lib/rescue/rescue.h +++ b/sw/device/silicon_creator/lib/rescue/rescue.h @@ -188,8 +188,10 @@ void rescue_skip_next_boot(void); * Detect rescue entry. * * @param config The ownership rescue config (if any). + * @param reset_reasons The reset reaons value from the rstmgr. * @return kHardenedBoolTrue if we should enter rescue mode. */ -hardened_bool_t rescue_detect_entry(const owner_rescue_config_t *config); +hardened_bool_t rescue_detect_entry(const owner_rescue_config_t *config, + uint32_t reset_reasons); #endif // OPENTITAN_SW_DEVICE_SILICON_CREATOR_LIB_RESCUE_RESCUE_H_ diff --git a/sw/device/silicon_creator/rom_ext/defs.bzl b/sw/device/silicon_creator/rom_ext/defs.bzl index d6fa2153bbec0..0799915b02553 100644 --- a/sw/device/silicon_creator/rom_ext/defs.bzl +++ b/sw/device/silicon_creator/rom_ext/defs.bzl @@ -147,6 +147,16 @@ TEST_OWNER_CONFIGS = { ], "rescue_module": ["//sw/device/silicon_creator/lib/rescue:rescue_xmodem"], }, + "xmodem_enter_on_watchdog": { + # Enable Xmodem rescue with enter-on-fail and a timeout. + "owner_defines": [ + # 0x58 is 'X'modem. + "WITH_RESCUE_PROTOCOL=0x58", + # misc_gpio: 0x80=enter_on_watchdog. + "WITH_RESCUE_MISC_GPIO_PARAM=0x80", + ], + "rescue_module": ["//sw/device/silicon_creator/lib/rescue:rescue_xmodem"], + }, "spidfu_restricted_commands": { # Enable USB-DFU triggered by SW_STRAPS value 3. "owner_defines": [ diff --git a/sw/device/silicon_creator/rom_ext/e2e/rescue/BUILD b/sw/device/silicon_creator/rom_ext/e2e/rescue/BUILD index 4ebfc7bc64247..845100af5692a 100644 --- a/sw/device/silicon_creator/rom_ext/e2e/rescue/BUILD +++ b/sw/device/silicon_creator/rom_ext/e2e/rescue/BUILD @@ -796,3 +796,69 @@ opentitan_test( test_harness = "//sw/host/tests/rescue:dfu_rescue_error_handling", ), ) + +# Check that when we are not configured to rescue on watchdog timeout that +# a watchdog timeout event simply boots the firmware normally. +opentitan_test( + name = "rescue_watchdog_disabled_test", + srcs = [ + "watchdog_test.c", + ], + exec_env = { + "//hw/top_earlgrey:fpga_hyper310_rom_ext": None, + "//hw/top_earlgrey:fpga_cw340_rom_ext": None, + }, + fpga = fpga_params( + changes_otp = True, + exit_failure = "(FAIL|BFV:|mode: RESQ).*", + rom_ext = "//sw/device/silicon_creator/rom_ext:rom_ext_dice_x509_slot_a", + test_cmd = """ + --exec="transport init" + --exec="fpga clear-bitstream" + --exec="fpga load-bitstream {bitstream}" + --exec="bootstrap --clear-uart=true {firmware}" + --exec="console --non-interactive --exit-success='{exit_success}' --exit-failure='{exit_failure}'" + no-op + """, + ), + deps = [ + "//sw/device/lib/base:status", + "//sw/device/lib/testing/test_framework:ottf_main", + "//sw/device/silicon_creator/lib/drivers:retention_sram", + "//sw/device/silicon_creator/lib/drivers:rstmgr", + "//sw/device/silicon_creator/lib/drivers:watchdog", + ], +) + +# Check that when we are configured to rescue on watchdog timeout that +# a watchdog timeout event triggers rescue mode. +opentitan_test( + name = "rescue_watchdog_enabled_test", + srcs = [ + "watchdog_test.c", + ], + exec_env = { + "//hw/top_earlgrey:fpga_hyper310_rom_ext": None, + "//hw/top_earlgrey:fpga_cw340_rom_ext": None, + }, + fpga = fpga_params( + changes_otp = True, + exit_success = "mode: RESQ", + rom_ext = "//sw/device/silicon_creator/rom_ext:rom_ext_xmodem_enter_on_watchdog", + test_cmd = """ + --exec="transport init" + --exec="fpga clear-bitstream" + --exec="fpga load-bitstream {bitstream}" + --exec="bootstrap --clear-uart=true {firmware}" + --exec="console --non-interactive --exit-success='{exit_success}' --exit-failure='{exit_failure}'" + no-op + """, + ), + deps = [ + "//sw/device/lib/base:status", + "//sw/device/lib/testing/test_framework:ottf_main", + "//sw/device/silicon_creator/lib/drivers:retention_sram", + "//sw/device/silicon_creator/lib/drivers:rstmgr", + "//sw/device/silicon_creator/lib/drivers:watchdog", + ], +) diff --git a/sw/device/silicon_creator/rom_ext/e2e/rescue/watchdog_test.c b/sw/device/silicon_creator/rom_ext/e2e/rescue/watchdog_test.c new file mode 100644 index 0000000000000..1c4f04bf3374c --- /dev/null +++ b/sw/device/silicon_creator/rom_ext/e2e/rescue/watchdog_test.c @@ -0,0 +1,63 @@ +// Copyright lowRISC contributors (OpenTitan project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +#include "sw/device/silicon_creator/lib/drivers/watchdog.h" + +#include +#include + +#include "sw/device/lib/arch/device.h" +#include "sw/device/lib/base/math.h" +#include "sw/device/lib/runtime/log.h" +#include "sw/device/lib/runtime/print.h" +#include "sw/device/lib/testing/test_framework/ottf_main.h" +#include "sw/device/silicon_creator/lib/drivers/retention_sram.h" +#include "sw/device/silicon_creator/lib/drivers/rstmgr.h" +#include "sw/device/silicon_creator/lib/error.h" + +static uint32_t compute_ticks_per_ms(uint64_t hz) { + const uint64_t kTicksPerMs = udiv64_slow(hz, 1000, NULL); + CHECK(kTicksPerMs <= UINT32_MAX, "kTicksPerMs exceeds UINT32_MAX"); + return (uint32_t)kTicksPerMs; +} + +// Setup the watchdog to bite. +static status_t watchdog_bite_setup(void) { + // Set watchdog bite threshold to 5ms. + uint32_t bite_threshold = 5 * compute_ticks_per_ms(kClockFreqAonHz); + uint32_t bark_threshold = 9 * bite_threshold / 8; + LOG_INFO("bite threshold = %d", bite_threshold); + LOG_INFO("bark threshold = %d", bark_threshold); + watchdog_configure((watchdog_config_t){ + .bite_threshold = bite_threshold, + .bark_threshold = bark_threshold, + .enable = kHardenedBoolTrue, + }); + + // Sleep for 6ms. + busy_spin_micros(6 * 1000); + + watchdog_disable(); + return UNKNOWN(); +} + +OTTF_DEFINE_TEST_CONFIG(); + +bool test_main(void) { + status_t result = OK_STATUS(); + const retention_sram_t *rr = retention_sram_get(); + uint32_t reason = rr->creator.reset_reasons; + + if (bitfield_bit32_read(reason, kRstmgrReasonPowerOn)) { + LOG_INFO("Configure watchdog to bite."); + result = watchdog_bite_setup(); + } else if (bitfield_bit32_read(reason, kRstmgrReasonWatchdog)) { + LOG_INFO("Got watchdog reset."); + result = OK_STATUS(); + } else { + LOG_ERROR("Unknown reset reason"); + result = UNKNOWN(); + } + return status_ok(result); +} diff --git a/sw/device/silicon_creator/rom_ext/rom_ext.c b/sw/device/silicon_creator/rom_ext/rom_ext.c index 57593a72e5a97..0d7dc59d2ffad 100644 --- a/sw/device/silicon_creator/rom_ext/rom_ext.c +++ b/sw/device/silicon_creator/rom_ext/rom_ext.c @@ -588,9 +588,10 @@ static rom_error_t rom_ext_start(boot_data_t *boot_data, boot_log_t *boot_log) { HARDENED_RETURN_IF_ERROR(ownership_seal_clear()); // We don't want to enter rescue mode if this is a low-power wakeup. - hardened_bool_t want_rescue = waking_from_low_power != kHardenedBoolTrue - ? rescue_detect_entry(owner_config.rescue) - : kHardenedBoolFalse; + hardened_bool_t want_rescue = + waking_from_low_power != kHardenedBoolTrue + ? rescue_detect_entry(owner_config.rescue, reset_reasons) + : kHardenedBoolFalse; hardened_bool_t boot_attempted = kHardenedBoolFalse; if (want_rescue == kHardenedBoolFalse) { From b45b4c06763a1dd6ec8a13c195d610947f272ba3 Mon Sep 17 00:00:00 2001 From: Chris Frantz Date: Mon, 6 Oct 2025 10:47:11 -0700 Subject: [PATCH 3/4] [opentitanlib] Update the rescue configuration struct Update the rescue configuration struct to understand the `enter_on_watchdog` field. Signed-off-by: Chris Frantz --- sw/host/opentitanlib/src/ownership/owner.rs | 1 + sw/host/opentitanlib/src/ownership/rescue.rs | 28 ++++++++++++++------ 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/sw/host/opentitanlib/src/ownership/owner.rs b/sw/host/opentitanlib/src/ownership/owner.rs index 200b99ed976c1..783e0dd31a538 100644 --- a/sw/host/opentitanlib/src/ownership/owner.rs +++ b/sw/host/opentitanlib/src/ownership/owner.rs @@ -586,6 +586,7 @@ r#"00000000: 4f 57 4e 52 00 08 00 00 00 00 00 00 4c 4e 45 58 OWNR........LNEX trigger_index: 0, gpio_pull_en: false, gpio_value: false, + enter_on_watchdog: false, enter_on_failure: false, timeout: 0, start: 32, diff --git a/sw/host/opentitanlib/src/ownership/rescue.rs b/sw/host/opentitanlib/src/ownership/rescue.rs index 2f7af01809936..4f579fe0d2274 100644 --- a/sw/host/opentitanlib/src/ownership/rescue.rs +++ b/sw/host/opentitanlib/src/ownership/rescue.rs @@ -76,6 +76,9 @@ pub struct OwnerRescueConfig { /// The GPIO trigger value (only if trigger is GPIO). #[serde(default)] pub gpio_value: bool, + /// Enter rescue mode if the reboot reason is watchdog timeout. + #[serde(default)] + pub enter_on_watchdog: bool, /// Enter rescue mode if boot fails. pub enter_on_failure: bool, /// The inactivity timeout in seconds (zero means disabled). @@ -95,6 +98,7 @@ impl Default for OwnerRescueConfig { protocol: RescueProtocol::default(), gpio_pull_en: false, gpio_value: false, + enter_on_watchdog: false, enter_on_failure: false, timeout: 0, trigger: RescueTrigger::default(), @@ -108,8 +112,9 @@ impl Default for OwnerRescueConfig { impl OwnerRescueConfig { const BASE_SIZE: usize = 16; - const GPIO_PULL_BIT: u8 = 0x02; - const GPIO_VALUE_BIT: u8 = 0x01; + const MISC_GPIO_WATCHDOG_TIMEOUT_EN_BIT: u8 = 0x80; + const MISC_GPIO_PULL_BIT: u8 = 0x02; + const MISC_GPIO_VALUE_BIT: u8 = 0x01; const ENTER_ON_FAIL_BIT: u8 = 0x80; const TIMEOUT_MASK: u8 = 0x7f; const TRIGGER_SHIFT: u8 = 6; @@ -133,8 +138,9 @@ impl OwnerRescueConfig { Ok(Self { header, protocol, - gpio_pull_en: gpio & Self::GPIO_PULL_BIT != 0, - gpio_value: gpio & Self::GPIO_VALUE_BIT != 0, + gpio_pull_en: gpio & Self::MISC_GPIO_PULL_BIT != 0, + gpio_value: gpio & Self::MISC_GPIO_VALUE_BIT != 0, + enter_on_watchdog: gpio & Self::MISC_GPIO_WATCHDOG_TIMEOUT_EN_BIT != 0, enter_on_failure: timeout & Self::ENTER_ON_FAIL_BIT != 0, timeout: timeout & Self::TIMEOUT_MASK, trigger: RescueTrigger(trigger >> Self::TRIGGER_SHIFT), @@ -153,12 +159,16 @@ impl OwnerRescueConfig { header.write(dest)?; dest.write_u8(u8::from(self.protocol))?; dest.write_u8( - if self.gpio_pull_en { - Self::GPIO_PULL_BIT + if self.enter_on_watchdog { + Self::MISC_GPIO_WATCHDOG_TIMEOUT_EN_BIT + } else { + 0 + } | if self.gpio_pull_en { + Self::MISC_GPIO_PULL_BIT } else { 0 } | if self.gpio_value { - Self::GPIO_VALUE_BIT + Self::MISC_GPIO_VALUE_BIT } else { 0 }, @@ -219,7 +229,7 @@ mod test { use crate::util::hexdump::{hexdump_parse, hexdump_string}; const OWNER_RESCUE_CONFIG_BIN: &str = "\ -00000000: 52 45 53 51 4c 00 00 00 58 00 00 40 20 00 64 00 RESQL...X..@ .d.\n\ +00000000: 52 45 53 51 4c 00 00 00 58 80 00 40 20 00 64 00 RESQL...X..@ .d.\n\ 00000010: 45 4d 50 54 4d 53 45 43 4e 45 58 54 55 4e 4c 4b EMPTMSECNEXTUNLK\n\ 00000020: 41 43 54 56 51 53 45 52 42 53 45 52 47 4f 4c 42 ACTVQSERBSERGOLB\n\ 00000030: 51 45 52 42 50 53 52 42 52 4e 57 4f 30 47 50 4f QERBPSRBRNWO0GPO\n\ @@ -231,6 +241,7 @@ mod test { trigger_index: 0, gpio_pull_en: false, gpio_value: false, + enter_on_watchdog: true, enter_on_failure: false, timeout: 0, start: 32, @@ -260,6 +271,7 @@ mod test { header: TlvHeader::default(), protocol: RescueProtocol::Xmodem, trigger: RescueTrigger::UartBreak, + enter_on_watchdog: true, start: 32, size: 100, command_allow: vec![ From cc737485e11c7295a34f506a2a5e4138613036cb Mon Sep 17 00:00:00 2001 From: Chris Frantz Date: Tue, 7 Oct 2025 10:42:18 -0700 Subject: [PATCH 4/4] [ownership] Update documentation Document the rescue configuration options. Signed-off-by: Chris Frantz --- .../silicon_creator/rom_ext/doc/ownership.md | 32 ++++++++++++++++--- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/sw/device/silicon_creator/rom_ext/doc/ownership.md b/sw/device/silicon_creator/rom_ext/doc/ownership.md index 9af65e4518a2b..90e226baaf9f1 100644 --- a/sw/device/silicon_creator/rom_ext/doc/ownership.md +++ b/sw/device/silicon_creator/rom_ext/doc/ownership.md @@ -732,6 +732,14 @@ See the definition in [datatypes.h](../../lib/ownership/datatypes.h). ### Rescue Configuration The rescue configuration describes the owner's desired configuration of the ROM\_EXT rescue protocol. +- The owner may configure desired rescue protocol: Xmodem, USB-DFU or SPI-DFU. +- The owner may configure desired rescue trigger: UART break, Strapping combination or GPIO pin. + - When the trigger is UART break, at least 350us of the break condition must be observed on the UART RX line to trigger the rescue protocol. + - When the trigger is a strapping combination, the desired strap pattern must be configured (e.g. a value 0-61). + - When the trigger is a GPIO pin, the desired IO pin as well as the sense of the pin and whether or not to enable the internal pull-up/down resistor must be configured. +- The owner may configure rescue to be triggered by failure to boot an owner payload. +- The owner may configure rescue to be triggered by a watchdog timeout as the reset reason. +- The owner may configure rescue to automatically exit after a specific timeout of no activity. - The owner may configure the region of flash to be erased and reprogrammed during firmware rescue. - The owner may configure the allowed interactions with the rescue protocol. - Allowed rescue modes permit whether the rescue client can upload firmware or interact with the boot log and boot services. @@ -753,21 +761,31 @@ typedef struct owner_rescue_config { */ uint8_t protocol; /** - * The gpio configuration (if relevant, depending on `detect`). + * The miscellaneous and gpio configuration (if relevant, depending on `detect`). * - * 7 2 1 0 + * 7 6 2 1 0 * +---------------+--------+-------+ - * | Reserved | PullEn | Value | + * | WDT | Resv'd | PullEn | Value | * +---------------+--------+-------+ + * + * WDT: Enter rescue if the reset reason is watchdog timeout. + * PullEn: When GPIO is the trigger, enable the internal pullup in the + * opposite direction of Value. + * Value: When GPIO is the trigger, the GPIO value which signifies entry + * into rescue mode. */ uint8_t gpio; /** - * The timeout configuration (not implemented yet). + * The timeout configuration. * * 7 6 0 * +-----+--------------------------+ * | EoF | Timeout | * +-----+--------------------------+ + * + * EoF: Enter rescue on failure to boot. + * Timeout: After `timeout` seconds of no activity, exit rescue mode and + * reboot. */ uint8_t timeout; /** @@ -777,6 +795,12 @@ typedef struct owner_rescue_config { * +--------+-----------------------+ * | Detect | Index | * +--------+-----------------------+ + * + * Detect and Index: + * 0 - None; index is meaningless. + * 1 - UART Break; index is meaningless. + * 2 - Strapping pins; index is the strapping value. + * 3 - GPIO; index is the pin to sample. */ uint8_t detect; /** The start offset of the rescue region in flash (in pages). */