blob: ec0485c77bd0e33101982bad58b2c6716a7a1585 [file] [log] [blame]
// 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;
}