Skip to content

Commit c0b52d8

Browse files
cfrantzpamaury
authored andcommitted
[rescue] Permit ROM_EXT updates via rescue
Discussion in #26785. 1. Examine the first rescue block and determine if the rescue stream contains a ROM_EXT. 2. If the rescue stream contains a ROM_EXT _and_ we're performing rescue to the non-active flash slot, then erase and reprogram the inactive ROM_EXT area. Otherwise, silently consume the ROM_EXT portion of the rescue stream and flash the application payload. 3. Test that each combination of rom_ext slot and rescue slot always results in the inactive rom_ext slot updating and the active slot not updating. Signed-off-by: Chris Frantz <[email protected]> (cherry picked from commit ab4b517)
1 parent c7b8b34 commit c0b52d8

File tree

7 files changed

+156
-5
lines changed

7 files changed

+156
-5
lines changed

apt-requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ srecord
4444
tree
4545
xmlstarlet
4646
xsltproc
47+
xxd
4748
xz-utils
4849
zip
4950
zlib1g-dev

sw/device/silicon_creator/lib/rescue/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ cc_library(
3030
"//sw/device/silicon_creator/lib:boot_log",
3131
"//sw/device/silicon_creator/lib:dbg_print",
3232
"//sw/device/silicon_creator/lib:error",
33+
"//sw/device/silicon_creator/lib:manifest",
3334
"//sw/device/silicon_creator/lib/boot_svc:boot_svc_msg",
3435
"//sw/device/silicon_creator/lib/drivers:flash_ctrl",
3536
"//sw/device/silicon_creator/lib/drivers:lifecycle",

sw/device/silicon_creator/lib/rescue/rescue.c

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "sw/device/silicon_creator/lib/drivers/retention_sram.h"
1717
#include "sw/device/silicon_creator/lib/drivers/rstmgr.h"
1818
#include "sw/device/silicon_creator/lib/drivers/uart.h"
19+
#include "sw/device/silicon_creator/lib/manifest.h"
1920
#include "sw/device/silicon_creator/lib/ownership/datatypes.h"
2021
#include "sw/device/silicon_creator/lib/ownership/owner_block.h"
2122

@@ -27,6 +28,20 @@ const uint32_t kFlashPageSize = FLASH_CTRL_PARAM_BYTES_PER_PAGE;
2728
const uint32_t kFlashBankSize =
2829
kFlashPageSize * FLASH_CTRL_PARAM_REG_PAGES_PER_BANK;
2930

31+
static inline bool is_rom_ext(const void *data) {
32+
const manifest_t *manifest = (const manifest_t *)data;
33+
return manifest->identifier == CHIP_ROM_EXT_IDENTIFIER;
34+
}
35+
36+
static inline bool is_rom_ext_update_allowed(rescue_state_t *state) {
37+
// A ROM_EXT update is allowed if the partition we're flashing is not the
38+
// ROM_EXT active partition.
39+
return (state->mode == kRescueModeFirmware &&
40+
state->boot_log->rom_ext_slot == kBootSlotB) ||
41+
(state->mode == kRescueModeFirmwareSlotB &&
42+
state->boot_log->rom_ext_slot == kBootSlotA);
43+
}
44+
3045
rom_error_t flash_firmware_block(rescue_state_t *state) {
3146
uint32_t bank_offset =
3247
state->mode == kRescueModeFirmwareSlotB ? kFlashBankSize : 0;
@@ -38,20 +53,39 @@ rom_error_t flash_firmware_block(rescue_state_t *state) {
3853
.write = kMultiBitBool4True,
3954
.erase = kMultiBitBool4True,
4055
});
41-
for (uint32_t addr = state->flash_start; addr < state->flash_limit;
56+
// Detect if we're allowed to flash the ROM_EXT _and_ if the data stream
57+
// starts with a ROM_EXT. If so, we start flashing at offset 0 in this
58+
// bank.
59+
state->flash_begin =
60+
(is_rom_ext_update_allowed(state) && is_rom_ext(state->data))
61+
? 0
62+
: state->flash_start;
63+
64+
// Erase the allowed range in the requested partition.
65+
for (uint32_t addr = state->flash_begin; addr < state->flash_limit;
4266
addr += kFlashPageSize) {
4367
HARDENED_RETURN_IF_ERROR(
4468
flash_ctrl_data_erase(bank_offset + addr, kFlashCtrlEraseTypePage));
4569
}
46-
state->flash_offset = state->flash_start;
70+
// Regardless of whether we're allowed to flash the ROM_EXT, set the flash
71+
// offset to zero if the data stream contains a ROM_EXT, otherwise, set to
72+
// flash_start. This will allow rescue to silently consume the ROM_EXT if
73+
// we're in the ROM_EXT active partition.
74+
state->flash_offset = is_rom_ext(state->data) ? 0 : state->flash_start;
4775
}
48-
if (state->flash_offset < state->flash_limit) {
76+
77+
if (state->flash_offset < state->flash_begin) {
78+
// Before allowed beginning; silently consume the data without flashing.
79+
state->flash_offset += sizeof(state->data);
80+
} else if (state->flash_offset >= state->flash_limit) {
81+
// Beyond the allowed limit; return an error.
82+
return kErrorRescueImageTooBig;
83+
} else {
84+
// In the allowed range; flash the data.
4985
HARDENED_RETURN_IF_ERROR(flash_ctrl_data_write(
5086
bank_offset + state->flash_offset,
5187
sizeof(state->data) / sizeof(uint32_t), state->data));
5288
state->flash_offset += sizeof(state->data);
53-
} else {
54-
return kErrorRescueImageTooBig;
5589
}
5690
return kErrorOk;
5791
}

sw/device/silicon_creator/lib/rescue/rescue.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,11 @@ typedef struct RescueState {
7878
uint16_t staged_len;
7979
// Current flash write offset.
8080
uint32_t flash_offset;
81+
// Current flash beginning offset. This is the partition-relative offset
82+
// where we're allowed to start writing to flash. Normally, this will be
83+
// the same as `flash_start`, but if we're allowed to write the ROM_EXT
84+
// and we've detected a ROM_EXT, this may be adjusted to zero.
85+
uint32_t flash_begin;
8186
// Range to erase and write for firmware rescue (inclusive).
8287
uint32_t flash_start;
8388
uint32_t flash_limit;

sw/device/silicon_creator/rom_ext/e2e/rescue/BUILD

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,25 @@ _POSITIONS = {
2121
"slot_a": {
2222
"linker_script": "//sw/device/lib/testing/test_framework:ottf_ld_silicon_owner_slot_a",
2323
"slot": "SlotA",
24+
"rom_ext_offset": "0",
2425
},
2526
"slot_b": {
2627
"linker_script": "//sw/device/lib/testing/test_framework:ottf_ld_silicon_owner_slot_b",
2728
"slot": "SlotB",
29+
"rom_ext_offset": "0x80000",
30+
},
31+
}
32+
33+
_RESCUE_ROMEXT_RESULTS = {
34+
True: {
35+
# When the ROM_EXT location and rescue upload slot are the same.
36+
"success": DEFAULT_TEST_SUCCESS_MSG,
37+
"failure": DEFAULT_TEST_FAILURE_MSG,
38+
},
39+
False: {
40+
# When the ROM_EXT location and rescue upload slot are opposite.
41+
"success": "{slot} rom_ext_id = OTRE\r\n.*{slot} rom_ext_version = 99.999\r\n",
42+
"failure": "(PASS|FAIL|BFV).*\r\n",
2843
},
2944
}
3045

@@ -57,14 +72,19 @@ _CONFIGS = {
5772
srcs = [
5873
"//sw/device/silicon_creator/rom_ext/e2e/verified_boot:boot_test",
5974
],
75+
defines = [
76+
"WITH_MANIFEST=1",
77+
],
6078
exec_env = [
6179
"//hw/top_earlgrey:fpga_cw310_rom_ext",
6280
],
6381
linker_script = position["linker_script"],
6482
deps = [
83+
"//hw/top_earlgrey/sw/autogen:top_earlgrey",
6584
"//sw/device/lib/base:status",
6685
"//sw/device/lib/testing/test_framework:ottf_main",
6786
"//sw/device/silicon_creator/lib:boot_log",
87+
"//sw/device/silicon_creator/lib:manifest",
6888
"//sw/device/silicon_creator/lib/drivers:retention_sram",
6989
],
7090
)
@@ -108,6 +128,65 @@ _CONFIGS = {
108128
for protocol, config in _CONFIGS.items()
109129
]
110130

131+
# This bad ROM_EXT image is an empty image that identifies as a ROM_EXT with
132+
# version number 99.999. Apart from the identifier word and version, it
133+
# is all zeros. The identifier word allows rescue to identify the first block
134+
# of the rescue payload as a potential ROM_EXT and possibly store it in
135+
# flash of the inactive partition.
136+
genrule(
137+
name = "bad_rom_ext",
138+
srcs = ["bad_rom_ext.txt"],
139+
outs = ["bad_rom_ext.bin"],
140+
cmd = "xxd -r $< > $@",
141+
)
142+
143+
# Test rescue driven ROM_EXT updates:
144+
# 1. Place a ROM_EXT in slot_a or slot_b.
145+
# 2. Use rescue to send a rom_ext+owner_firmware payload.
146+
# 3. If rescueing into the slot where the ROM_EXT is active, the rom_ext
147+
# portion of the payload should be silently consumed and not updated.
148+
# If rescueing into the opposite slot, the rom_ext portion of the
149+
# payload will be programmed into the inactive rom_ext slot.
150+
# 4. Upon booting, the test binary will print the identifier and version
151+
# fields of both ROM_EXT slots.
152+
[
153+
opentitan_test(
154+
name = "rescue_rom_ext_{}_update_{}".format(rxslot, name),
155+
exec_env = {
156+
"//hw/top_earlgrey:fpga_cw310_rom_ext": None,
157+
},
158+
fpga = fpga_params(
159+
assemble = "{rom_ext}@{rom_ext_offset}",
160+
binaries = {
161+
":boot_test_{}".format(name): "payload",
162+
":bad_rom_ext": "bad_rom_ext",
163+
},
164+
exit_failure = _RESCUE_ROMEXT_RESULTS[name == rxslot]["failure"],
165+
exit_success = _RESCUE_ROMEXT_RESULTS[name == rxslot]["success"].format(slot = name),
166+
image_name = "/tmp/rescue_rom_ext_{}.img".format(name),
167+
rom_ext = "//sw/device/silicon_creator/rom_ext:rom_ext_dice_x509_slot_virtual",
168+
rom_ext_offset = _POSITIONS[rxslot]["rom_ext_offset"],
169+
slot = position["slot"],
170+
test_cmd = """
171+
--exec="transport init"
172+
--exec="fpga load-bitstream {bitstream}"
173+
--exec="bootstrap --clear-uart=true {firmware}"
174+
# First make sure the ROM_EXT is faulting because there is no firmware
175+
--exec="console --non-interactive --exit-success='BFV:' --exit-failure='PASS|FAIL'"
176+
# Construct a firmware image with the bad ROM_EXT
177+
--exec="image assemble --size=131072 --mirror=false --output={image_name} {bad_rom_ext}@0 {payload}@0x10000"
178+
# Load firmware via rescue, including the bad ROM_EXT
179+
--exec="rescue firmware --raw --slot={slot} {image_name}"
180+
# Check for firmware execution
181+
--exec="console --non-interactive --exit-success='{exit_success}' --exit-failure='{exit_failure}'"
182+
no-op
183+
""",
184+
),
185+
)
186+
for name, position in _POSITIONS.items()
187+
for rxslot in _POSITIONS.keys()
188+
]
189+
111190
[
112191
opentitan_test(
113192
name = "next_slot_{}".format(protocol),
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
00000000: 0000 0000 0000 0000 0000 0000 0000 0000 ................
2+
*
3+
00000330: 0000 0000 4f54 5245 0000 0000 0000 0000 ....OTRE........
4+
00000340: 0000 0000 6300 0000 e703 0000 0000 0000 ................
5+
00000350: 0000 0000 0000 0000 0000 0000 0000 0000 ................
6+
*
7+
0000fff0: 0000 0000 0000 0000 0000 0000 0000 0000 ................

sw/device/silicon_creator/rom_ext/e2e/verified_boot/boot_test.c

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,29 @@ status_t keymgr_print(void) {
9393
status_t keymgr_print(void) { return OK_STATUS(); }
9494
#endif
9595

96+
#ifdef WITH_MANIFEST
97+
#include "sw/device/silicon_creator/lib/manifest.h"
98+
99+
#include "hw/top_earlgrey/sw/autogen/top_earlgrey.h"
100+
101+
status_t manifest_print(void) {
102+
const manifest_t *a =
103+
(const manifest_t *)TOP_EARLGREY_FLASH_CTRL_MEM_BASE_ADDR;
104+
const manifest_t *b =
105+
(const manifest_t *)(TOP_EARLGREY_FLASH_CTRL_MEM_BASE_ADDR +
106+
(TOP_EARLGREY_FLASH_CTRL_MEM_SIZE_BYTES / 2));
107+
LOG_INFO("slot_a rom_ext_id = %C", a->identifier);
108+
LOG_INFO("slot_a rom_ext_version = %u.%u", a->version_major,
109+
a->version_minor);
110+
LOG_INFO("slot_b rom_ext_id = %C", b->identifier);
111+
LOG_INFO("slot_b rom_ext_version = %u.%u", b->version_major,
112+
b->version_minor);
113+
return OK_STATUS();
114+
}
115+
#else
116+
status_t manifest_print(void) { return OK_STATUS(); }
117+
#endif
118+
96119
OTTF_DEFINE_TEST_CONFIG();
97120

98121
status_t boot_log_print(boot_log_t *boot_log) {
@@ -114,6 +137,7 @@ status_t boot_log_print(boot_log_t *boot_log) {
114137
LOG_INFO("boot_log rom_ext_min_sec_ver = %u", boot_log->rom_ext_min_sec_ver);
115138
LOG_INFO("boot_log bl0_min_sec_ver = %u", boot_log->bl0_min_sec_ver);
116139
LOG_INFO("boot_log primary_bl0_slot = %C", boot_log->primary_bl0_slot);
140+
TRY(manifest_print());
117141
TRY(ownership_print());
118142
TRY(keymgr_print());
119143
return OK_STATUS();

0 commit comments

Comments
 (0)