[sw] Clean up boot_rom SPI bootstrap code.
This change mostly just adds comments and removes initialisms from
bootstrap.c, to make it consistent with the rest of our code.
Signed-off-by: Miguel Young de la Sota <mcyoung@google.com>
diff --git a/sw/device/boot_rom/bootstrap.c b/sw/device/boot_rom/bootstrap.c
index 557408d..2566669 100644
--- a/sw/device/boot_rom/bootstrap.c
+++ b/sw/device/boot_rom/bootstrap.c
@@ -4,102 +4,123 @@
#include "sw/device/boot_rom/bootstrap.h"
+#include "sw/device/boot_rom/spiflash_frame.h"
#include "sw/device/lib/arch/device.h"
#include "sw/device/lib/base/log.h"
-#include "sw/device/lib/common.h"
+#include "sw/device/lib/base/memory.h"
+#include "sw/device/lib/base/mmio.h"
#include "sw/device/lib/dif/dif_gpio.h"
#include "sw/device/lib/flash_ctrl.h"
#include "sw/device/lib/hw_sha256.h"
+#include "sw/device/lib/runtime/hart.h"
#include "sw/device/lib/spi_device.h"
-#include "sw/device/lib/uart.h" // TODO: Wrap uart in DEBUG macros.
#include "hw/top_earlgrey/sw/autogen/top_earlgrey.h"
#define GPIO_BOOTSTRAP_BIT_MASK 0x00020000u
-/* Checks if flash is blank to determine if bootstrap is needed. */
-/* TODO: Update this to check bootstrap pin instead in Verilator. */
-static int bootstrap_requested(void) {
+/**
+ * Check if flash is blank to determine if bootstrap is needed.
+ *
+ * TODO: Update this to check bootstrap pin instead in Verilator.
+ */
+static bool bootstrap_requested(void) {
// The following flash empty-sniff-check is done this way due to the lack of
// clear eflash reset in SIM environments.
if (kDeviceType == kDeviceSimVerilator) {
- return !!(REG32(FLASH_MEM_BASE_ADDR) == 0 ||
- REG32(FLASH_MEM_BASE_ADDR) == 0xFFFFFFFF);
+ mmio_region_t flash_region = mmio_region_from_addr(FLASH_MEM_BASE_ADDR);
+ uint32_t value = mmio_region_read32(flash_region, 0x0);
+ return value == 0 || value == UINT32_MAX;
}
- // Initialize GPIO device
+
+ // Initialize GPIO device.
dif_gpio_t gpio;
dif_gpio_config_t gpio_config = {
.base_addr = mmio_region_from_addr(TOP_EARLGREY_GPIO_BASE_ADDR)};
dif_gpio_init(&gpio_config, &gpio);
- // Read pin
+
uint32_t gpio_in;
dif_gpio_all_read(&gpio, &gpio_in);
- return !!(gpio_in & GPIO_BOOTSTRAP_BIT_MASK);
+ return (gpio_in & GPIO_BOOTSTRAP_BIT_MASK) != 0;
}
-/* Erase all flash, and verify blank. */
+/**
+ * Erase all flash, and verify blank.
+ */
static int erase_flash(void) {
- if (flash_bank_erase(FLASH_BANK_0)) {
+ if (flash_bank_erase(FLASH_BANK_0) != 0) {
return E_BS_ERASE;
}
- if (flash_bank_erase(FLASH_BANK_1)) {
+ if (flash_bank_erase(FLASH_BANK_1) != 0) {
return E_BS_ERASE;
}
- if (!flash_check_empty()) {
+ if (flash_check_empty() == 0) {
return E_BS_NOTEMPTY;
}
+
return 0;
}
-/* Calculates SHA256 hash of received data and compares it against recieved
- * hash. Returns 0 if both hashes are identical. */
-static int check_frame_hash(const frame_t *f) {
- static uint32_t hash[8];
- uint32_t result = 0;
- hw_SHA256_hash((uint8_t *)&f->hdr.frame_num, RAW_BUFFER_SIZE - 32,
- (uint8_t *)hash);
- for (int i = 0; i < 8; ++i) {
- result |= hash[i] ^ f->hdr.hash[i];
- }
- return result;
+/**
+ * Compares the SHA256 hash of the recieved data with the recieved hash.
+ *
+ * Returns true if the hashes match.
+ */
+static bool check_frame_hash(const spiflash_frame_t *frame) {
+ uint8_t hash[sizeof(frame->header.hash)];
+ uint8_t *data = ((uint8_t *)frame) + sizeof(hash);
+ hw_SHA256_hash(data, sizeof(spiflash_frame_t) - sizeof(hash), hash);
+
+ return memcmp(hash, frame->header.hash, sizeof(hash)) == 0;
}
-/* Processes frames received via spid interface and writes them to flash. */
+/**
+ * Load spiflash frames from the SPI interface.
+ *
+ * This function checks that the sequence numbers and hashes of the frames are
+ * correct before programming them into flash.
+ * */
static int bootstrap_flash(void) {
- static frame_t f;
- static uint8_t ack[32] = {0};
- uint32_t expected_frame_no = 0;
- for (;;) {
- if (spid_bytes_available() >= sizeof(f)) {
- spid_read_nb(&f, sizeof(f));
- LOG_INFO("Processing frame no: %d exp no: %d", f.hdr.frame_num,
- expected_frame_no);
+ uint8_t ack[SHA256_DIGEST_SIZE] = {0};
+ uint32_t expected_frame_num = 0;
+ while (true) {
+ if (spid_bytes_available() >= sizeof(spiflash_frame_t)) {
+ spiflash_frame_t frame;
+ spid_read_nb(&frame, sizeof(spiflash_frame_t));
- if (FRAME_NO(f.hdr.frame_num) == expected_frame_no) {
- if (check_frame_hash(&f)) {
- LOG_ERROR("Detected hash mismatch on frame: %d", f.hdr.frame_num);
+ uint32_t frame_num = SPIFLASH_FRAME_NUM(frame.header.frame_num);
+ LOG_INFO("Processing frame #%d, expecting #%d", frame_num,
+ expected_frame_num);
+
+ if (frame_num == expected_frame_num) {
+ if (!check_frame_hash(&frame)) {
+ LOG_ERROR("Detected hash mismatch on frame #%d", frame_num);
spid_send(ack, sizeof(ack));
continue;
}
- hw_SHA256_hash(&f, sizeof(f), ack);
+ hw_SHA256_hash(&frame, sizeof(spiflash_frame_t), ack);
spid_send(ack, sizeof(ack));
- if (expected_frame_no == 0) {
- flash_default_region_access(/*rd_en=*/1, /*prog_en=*/1,
- /*erase_en=*/1);
- int rv = erase_flash();
- if (rv) {
- return rv;
+ if (expected_frame_num == 0) {
+ flash_default_region_access(/*rd_en=*/true, /*prog_en=*/true,
+ /*erase_en=*/true);
+ int flash_error = erase_flash();
+ if (flash_error != 0) {
+ return flash_error;
}
+ LOG_INFO("Flash erase successful");
}
- if (flash_write(f.hdr.flash_offset, f.data, ARRAYSIZE(f.data))) {
+
+ if (flash_write(frame.header.flash_offset, frame.data,
+ SPIFLASH_FRAME_DATA_WORDS) != 0) {
return E_BS_WRITE;
}
- ++expected_frame_no;
- if (f.hdr.frame_num & FRAME_EOF_MARKER) {
- break;
+ ++expected_frame_num;
+ if (SPIFLASH_FRAME_IS_EOF(frame.header.frame_num)) {
+ LOG_INFO("Bootstrap: DONE!");
+ return 0;
}
} else {
// Send previous ack if unable to verify current frame.
@@ -107,8 +128,6 @@
}
}
}
- LOG_INFO("bootstrap: DONE!");
- return 0;
}
int bootstrap(void) {
@@ -121,13 +140,15 @@
flash_init_block();
LOG_INFO("HW initialisation completed, waiting for SPI input...");
- int rv = bootstrap_flash();
- if (rv) {
- rv |= erase_flash();
+ int error = bootstrap_flash();
+ if (error != 0) {
+ error |= erase_flash();
+ LOG_ERROR("Bootstrap error: 0x%x", error);
}
// Always make sure to revert flash_ctrl access to default settings.
// bootstrap_flash enables access to flash to perform update.
- flash_default_region_access(/*rd_en=*/0, /*prog_en=*/0, /*erase_en=*/0);
- return rv;
+ flash_default_region_access(/*rd_en=*/false, /*prog_en=*/false,
+ /*erase_en=*/false);
+ return error;
}
diff --git a/sw/device/boot_rom/bootstrap.h b/sw/device/boot_rom/bootstrap.h
index 580ae5e..9b22991 100644
--- a/sw/device/boot_rom/bootstrap.h
+++ b/sw/device/boot_rom/bootstrap.h
@@ -5,7 +5,18 @@
#ifndef OPENTITAN_SW_DEVICE_BOOT_ROM_BOOTSTRAP_H_
#define OPENTITAN_SW_DEVICE_BOOT_ROM_BOOTSTRAP_H_
-#include "sw/device/boot_rom/bootstrap_msgs.h"
+/**
+ * A bootstrap error representing a flash erase failure.
+ */
+#define E_BS_ERASE 10
+/**
+ * A bootstrap error representing unexpectedly empty flash.
+ */
+#define E_BS_NOTEMPTY 11
+/**
+ * A bootstrap error representing a flash write error.
+ */
+#define E_BS_WRITE 12
/**
* Bootstrap Flash with payload received on SPI device.
diff --git a/sw/device/boot_rom/bootstrap_msgs.h b/sw/device/boot_rom/bootstrap_msgs.h
deleted file mode 100644
index a1d1a7a..0000000
--- a/sw/device/boot_rom/bootstrap_msgs.h
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright lowRISC contributors.
-// Licensed under the Apache License, Version 2.0, see LICENSE for details.
-// SPDX-License-Identifier: Apache-2.0
-
-#ifndef OPENTITAN_SW_DEVICE_BOOT_ROM_BOOTSTRAP_MSGS_H_
-#define OPENTITAN_SW_DEVICE_BOOT_ROM_BOOTSTRAP_MSGS_H_
-#include <stdint.h>
-
-#define RAW_BUFFER_SIZE 1024
-#define FRAME_EOF_MARKER 0x80000000
-#define FRAME_NO(k) ((k)&0xffffff)
-
-typedef struct {
- /* SHA2 of the entire frame_t message starting at the `frame_num` offset. */
- uint32_t hash[8];
-
- /* Frame number starting at 0. The last frame should be ord with
- * FRAME_EOF_MARKER. */
- uint32_t frame_num;
-
- /* 0-based flash offset where the frame should be written to. */
- uint32_t flash_offset;
-} frame_hdr_t;
-
-typedef struct {
- /* Frame header. See frame_hdr_t for details. */
- frame_hdr_t hdr;
-
- /* Frame data uint32_t aligned. */
- uint32_t data[(RAW_BUFFER_SIZE - sizeof(frame_hdr_t)) / sizeof(uint32_t)];
-} frame_t;
-
-/* Bootstrap error codes */
-#define E_BS_ERASE 10
-#define E_BS_NOTEMPTY 11
-#define E_BS_WRITE 12
-
-#endif // OPENTITAN_SW_DEVICE_BOOT_ROM_BOOTSTRAP_MSGS_H_
diff --git a/sw/device/boot_rom/spiflash_frame.h b/sw/device/boot_rom/spiflash_frame.h
new file mode 100644
index 0000000..160122c
--- /dev/null
+++ b/sw/device/boot_rom/spiflash_frame.h
@@ -0,0 +1,78 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+#ifndef OPENTITAN_SW_DEVICE_BOOT_ROM_SPIFLASH_FRAME_H_
+#define OPENTITAN_SW_DEVICE_BOOT_ROM_SPIFLASH_FRAME_H_
+
+#include <stdalign.h>
+#include <stdint.h>
+
+#include "sw/device/lib/hw_sha256.h"
+
+/**
+ * The total size of a spiflash frame.
+ */
+#define SPIFLASH_RAW_BUFFER_SIZE 1024
+
+/**
+ * The EOF flag on a spiflash frame, indicating that a frame is the last one in
+ * the sequence.
+ */
+#define SPIFLASH_FRAME_EOF_MARKER 0x80000000
+
+/**
+ * Extracts the "number" part of a `frame_num`.
+ */
+#define SPIFLASH_FRAME_NUM(k) ((k)&0xffffff)
+
+/**
+ * Checks whether a `frame_num` represents an EOF.
+ */
+#define SPIFLASH_FRAME_IS_EOF(k) (((k)&SPIFLASH_FRAME_EOF_MARKER) != 0)
+
+/**
+ * The length, in words, of a frame's data buffer.
+ */
+#define SPIFLASH_FRAME_DATA_WORDS \
+ ((SPIFLASH_RAW_BUFFER_SIZE - sizeof(spiflash_frame_header_t)) / \
+ sizeof(uint32_t))
+
+/**
+ * A spiflash frame header.
+ */
+typedef struct spiflash_frame_header {
+ /**
+ * SHA256 of the entire frame_t message starting at the `frame_num` offset.
+ */
+ uint32_t hash[SHA256_DIGEST_SIZE / sizeof(uint32_t)];
+ /**
+ * Frame number starting at 0. The last frame should be OR'd with
+ * FRAME_EOF_MARKER.
+ */
+ uint32_t frame_num;
+ /**
+ * Offset in flash, indexed from 0, where the frame should be
+ * written.
+ */
+ uint32_t flash_offset;
+} spiflash_frame_header_t;
+
+/**
+ * A spiflash frame, as it would arrive on the wire.
+ */
+typedef struct spiflash_frame {
+ /**
+ * Frame header.
+ */
+ spiflash_frame_header_t header;
+ /**
+ * Frame data, word-aligned.
+ */
+ uint32_t data[SPIFLASH_FRAME_DATA_WORDS];
+} spiflash_frame_t;
+
+_Static_assert(sizeof(spiflash_frame_t) == SPIFLASH_RAW_BUFFER_SIZE,
+ "spiflash_frame_t is the wrong size!");
+
+#endif // OPENTITAN_SW_DEVICE_BOOT_ROM_SPIFLASH_FRAME_H_