Start of public OpenTitan development history

Code contributors:
Alex Bradbury <asb@lowrisc.org>
Cindy Chen <chencindy@google.com>
Eunchan Kim <eunchan@google.com>
Gaurang Chitroda <gaurangg@google.com>
Mark Hayter <mark.hayter@gmail.com>
Michael Schaffner <msf@google.com>
Miguel Osorio <miguelosorio@google.com>
Nils Graf <nilsg@google.com>
Philipp Wagner <phw@lowrisc.org>
Pirmin Vogel <vogelpi@lowrisc.org>
Ram Babu Penugonda <rampenugonda@google.com>
Scott Johnson <scottdj@google.com>
Shail Kushwah <kushwahs@google.com>
Srikrishna Iyer <sriyer@google.com>
Steve Nelson <Steve.Nelson@wdc.com>
Tao Liu <taliu@google.com>
Timothy Chen <timothytim@google.com>
Tobias Wölfel <tobias.woelfel@mailbox.org>
Weicai Yang <weicai@google.com>
diff --git a/sw/boot_rom/bootstrap.c b/sw/boot_rom/bootstrap.c
new file mode 100644
index 0000000..ec0485c
--- /dev/null
+++ b/sw/boot_rom/bootstrap.c
@@ -0,0 +1,100 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+#include "bootstrap.h"
+
+#include "common.h"
+#include "flash_ctrl.h"
+#include "gpio.h"
+#include "spi_device.h"
+#include "uart.h"  // TODO: Wrap uart in DEBUG macros.
+
+/* 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) {
+// The following flash empty-sniff-check is done this way due to the lack of
+// clear eflash reset in SIM environments.
+#if defined(SIMULATION)
+  return !!(REG32(FLASH_MEM_BASE_ADDR) == 0 ||
+            REG32(FLASH_MEM_BASE_ADDR) == 0xFFFFFFFF);
+#else
+  return !!(gpio_read() & GPIO_BOOTSTRAP_BIT_MASK);
+#endif
+}
+
+/* Erase all flash, and verify blank. */
+static int erase_flash(void) {
+  if (flash_bank_erase(FlashBank0)) {
+    return E_BS_ERASE;
+  }
+  if (flash_bank_erase(FlashBank1)) {
+    return E_BS_ERASE;
+  }
+  if (!flash_check_empty()) {
+    return E_BS_NOTEMPTY;
+  }
+  return 0;
+}
+
+/* Processes frames received via spid interface and writes them to 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));
+      uart_send_str("Processing frame no: ");
+      uart_send_uint(f.hdr.frame_num, 32);
+      uart_send_str(" exp no: ");
+      uart_send_uint(expected_frame_no, 32);
+      uart_send_str("\r\n");
+
+      // TODO: Add hash check.
+      if (FRAME_NO(f.hdr.frame_num) == expected_frame_no) {
+        // TODO: Add ack computation.
+        spid_send(ack, sizeof(ack));
+
+        if (expected_frame_no == 0) {
+          // TODO: Add signed header checks.
+          flash_default_region_access(/*rd_en=*/1, /*prog_en=*/1,
+                                      /*erase_en=*/1);
+          int rv = erase_flash();
+          if (rv) {
+            return rv;
+          }
+        }
+        if (flash_write(f.hdr.flash_offset, f.data, ARRAYSIZE(f.data))) {
+          return E_BS_WRITE;
+        }
+
+        ++expected_frame_no;
+        if (f.hdr.frame_num & FRAME_EOF_MARKER) {
+          break;
+        }
+      } else {
+        // Send previous ack if unable to verify current frame.
+        spid_send(ack, sizeof(ack));
+      }
+    }
+  }
+  uart_send_str("bootstrap: DONE!\r\n");
+  return 0;
+}
+
+int bootstrap(void) {
+  if (!bootstrap_requested()) {
+    return 0;
+  }
+  // SPI device is only initialized in bootstrap mode.
+  spid_init();
+  flash_init_block();
+
+  int rv = bootstrap_flash();
+
+  // 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;
+}