[sw/boot_rom] Add frame retry logic
boot_rom sends an ack to spiflash with the hash of the entire previous
frame. spiflash retries the previous fram if unable to verify the ack
against previous frame hash.
diff --git a/sw/boot_rom/bootstrap.c b/sw/boot_rom/bootstrap.c
index fa41e0f..d884ba3 100644
--- a/sw/boot_rom/bootstrap.c
+++ b/sw/boot_rom/bootstrap.c
@@ -6,8 +6,8 @@
#include "common.h"
#include "flash_ctrl.h"
-#include "hw_sha256.h"
#include "gpio.h"
+#include "hw_sha256.h"
#include "spi_device.h"
#include "uart.h" // TODO: Wrap uart in DEBUG macros.
@@ -65,14 +65,15 @@
uart_send_uint(expected_frame_no, 32);
uart_send_str("\r\n");
- if (check_frame_hash(&f)) {
- uart_send_str("Error: detected hash mismatch on frame: ");
- uart_send_uint(f.hdr.frame_num, 32);
- uart_send_str("\r\n");
- return E_BS_BAD_HASH_FRAME;
- }
-
if (FRAME_NO(f.hdr.frame_num) == expected_frame_no) {
+ if (check_frame_hash(&f)) {
+ uart_send_str("Error: detected hash mismatch on frame: ");
+ uart_send_uint(f.hdr.frame_num, 32);
+ uart_send_str("\r\n");
+ spid_send(ack, sizeof(ack));
+ continue;
+ }
+
hw_SHA256_hash(&f, sizeof(f), ack);
spid_send(ack, sizeof(ack));
diff --git a/sw/boot_rom/bootstrap_msgs.h b/sw/boot_rom/bootstrap_msgs.h
index 2ad9331..7ce2e5e 100644
--- a/sw/boot_rom/bootstrap_msgs.h
+++ b/sw/boot_rom/bootstrap_msgs.h
@@ -31,7 +31,6 @@
} frame_t;
/* Bootstrap error codes */
-#define E_BS_BAD_HASH_FRAME 9
#define E_BS_ERASE 10
#define E_BS_NOTEMPTY 11
#define E_BS_WRITE 12
diff --git a/sw/boot_rom/srcs.mk b/sw/boot_rom/srcs.mk
index 456df0c..894f22f 100644
--- a/sw/boot_rom/srcs.mk
+++ b/sw/boot_rom/srcs.mk
@@ -3,7 +3,8 @@
# SPDX-License-Identifier: Apache-2.0
SW_NAME ?= boot_rom
-SW_SRCS += $(SW_DIR)/bootstrap.c $(SW_DIR)/boot_rom.c
+SW_SRCS += $(SW_DIR)/bootstrap.c $(SW_DIR)/boot_rom.c $(LIB_DIR)/hw_sha256.c
+INCS += -I$(SW_ROOT_DIR)/vendor
# overrides
CRT_SRCS := $(SW_DIR)/crt0.S
diff --git a/sw/host/spiflash/updater.cc b/sw/host/spiflash/updater.cc
index 2025ca9..9f5cc2d 100644
--- a/sw/host/spiflash/updater.cc
+++ b/sw/host/spiflash/updater.cc
@@ -4,9 +4,10 @@
#include "updater.h"
-#include <algorithm>
#include <assert.h>
+#include <algorithm>
+
namespace opentitan {
namespace spiflash {
namespace {
@@ -43,6 +44,15 @@
SHA256_Final(f->hdr.hash, &sha256);
}
+// Check hash portion of |ack| against |ack_expected|.
+bool CheckAckHash(const std::string &ack, const std::string &ack_expected) {
+ uint8_t result = 0;
+ for (int i = 0; i < 32; ++i) {
+ result |= ack[i] ^ ack_expected[i];
+ }
+ return (result == 0);
+}
+
} // namespace
bool Updater::Run() {
@@ -55,16 +65,43 @@
std::cout << "Image divided into " << frames.size() << " frames."
<< std::endl;
- for (const Frame &f : frames) {
+ std::string ack_expected;
+ ack_expected.resize(sizeof(Frame), '\0');
+ std::string ack;
+ ack.resize(sizeof(Frame));
+ for (uint32_t current_frame = 0; current_frame < frames.size();) {
+ const Frame &f = frames[current_frame];
+
std::cout << "frame: 0x" << std::setfill('0') << std::setw(8) << std::hex
<< f.hdr.frame_num << " to offset: 0x" << std::setfill('0')
<< std::setw(8) << std::hex << f.hdr.offset << std::endl;
- uint8_t rx[sizeof(Frame)];
- if (!spi_->TransmitFrame(reinterpret_cast<const uint8_t *>(&f), rx,
+
+ if (!spi_->TransmitFrame(reinterpret_cast<const uint8_t *>(&f),
+ reinterpret_cast<uint8_t *>(&ack[0]),
sizeof(Frame))) {
std::cerr << "Failed to transmit frame no: 0x" << std::setfill('0')
<< std::setw(8) << std::hex << f.hdr.frame_num << std::endl;
}
+
+ // When we send the next frame, we'll get the previous frame's hash as
+ // the ack, so with each increment of |current_frame| we also need to
+ // update the |ack_expected| value.
+ uint32_t ack_expected_index = 0;
+ if (current_frame == 0 || CheckAckHash(ack, ack_expected)) {
+ ack_expected_index = current_frame;
+ current_frame++;
+ } else {
+ // TODO: Improve protocol by encoding NEXT frame number, current error,
+ // ack marker and CRC.
+ // The current implementation will send the previous frame if the current
+ // ack doesn't match the expected response.
+ if (current_frame > 1) {
+ current_frame--;
+ }
+ ack_expected_index = (current_frame == 0) ? 0 : current_frame - 1;
+ }
+ SHA256(reinterpret_cast<const uint8_t *>(&frames[ack_expected_index]),
+ sizeof(f), reinterpret_cast<uint8_t *>(&ack_expected[0]));
}
return true;
}
@@ -87,7 +124,7 @@
Frame &last_frame = frames->back();
last_frame.hdr.frame_num = 0x80000000 | last_frame.hdr.frame_num;
- for (Frame& f : *frames) {
+ for (Frame &f : *frames) {
HashFrame(&f);
}
return true;