lowRISC Contributors | 802543a | 2019-08-31 12:12:56 +0100 | [diff] [blame] | 1 | // Copyright lowRISC contributors. |
| 2 | // Licensed under the Apache License, Version 2.0, see LICENSE for details. |
| 3 | // SPDX-License-Identifier: Apache-2.0 |
| 4 | |
| 5 | #include "bootstrap.h" |
| 6 | |
| 7 | #include "common.h" |
| 8 | #include "flash_ctrl.h" |
| 9 | #include "gpio.h" |
| 10 | #include "spi_device.h" |
| 11 | #include "uart.h" // TODO: Wrap uart in DEBUG macros. |
| 12 | |
| 13 | /* Checks if flash is blank to determine if bootstrap is needed. */ |
| 14 | /* TODO: Update this to check bootstrap pin instead in Verilator. */ |
| 15 | static int bootstrap_requested(void) { |
| 16 | // The following flash empty-sniff-check is done this way due to the lack of |
| 17 | // clear eflash reset in SIM environments. |
| 18 | #if defined(SIMULATION) |
| 19 | return !!(REG32(FLASH_MEM_BASE_ADDR) == 0 || |
| 20 | REG32(FLASH_MEM_BASE_ADDR) == 0xFFFFFFFF); |
| 21 | #else |
| 22 | return !!(gpio_read() & GPIO_BOOTSTRAP_BIT_MASK); |
| 23 | #endif |
| 24 | } |
| 25 | |
| 26 | /* Erase all flash, and verify blank. */ |
| 27 | static int erase_flash(void) { |
| 28 | if (flash_bank_erase(FlashBank0)) { |
| 29 | return E_BS_ERASE; |
| 30 | } |
| 31 | if (flash_bank_erase(FlashBank1)) { |
| 32 | return E_BS_ERASE; |
| 33 | } |
| 34 | if (!flash_check_empty()) { |
| 35 | return E_BS_NOTEMPTY; |
| 36 | } |
| 37 | return 0; |
| 38 | } |
| 39 | |
| 40 | /* Processes frames received via spid interface and writes them to flash. */ |
| 41 | static int bootstrap_flash(void) { |
| 42 | static frame_t f; |
| 43 | static uint8_t ack[32] = {0}; |
| 44 | uint32_t expected_frame_no = 0; |
| 45 | for (;;) { |
| 46 | if (spid_bytes_available() >= sizeof(f)) { |
| 47 | spid_read_nb(&f, sizeof(f)); |
| 48 | uart_send_str("Processing frame no: "); |
| 49 | uart_send_uint(f.hdr.frame_num, 32); |
| 50 | uart_send_str(" exp no: "); |
| 51 | uart_send_uint(expected_frame_no, 32); |
| 52 | uart_send_str("\r\n"); |
| 53 | |
| 54 | // TODO: Add hash check. |
| 55 | if (FRAME_NO(f.hdr.frame_num) == expected_frame_no) { |
| 56 | // TODO: Add ack computation. |
| 57 | spid_send(ack, sizeof(ack)); |
| 58 | |
| 59 | if (expected_frame_no == 0) { |
| 60 | // TODO: Add signed header checks. |
| 61 | flash_default_region_access(/*rd_en=*/1, /*prog_en=*/1, |
| 62 | /*erase_en=*/1); |
| 63 | int rv = erase_flash(); |
| 64 | if (rv) { |
| 65 | return rv; |
| 66 | } |
| 67 | } |
| 68 | if (flash_write(f.hdr.flash_offset, f.data, ARRAYSIZE(f.data))) { |
| 69 | return E_BS_WRITE; |
| 70 | } |
| 71 | |
| 72 | ++expected_frame_no; |
| 73 | if (f.hdr.frame_num & FRAME_EOF_MARKER) { |
| 74 | break; |
| 75 | } |
| 76 | } else { |
| 77 | // Send previous ack if unable to verify current frame. |
| 78 | spid_send(ack, sizeof(ack)); |
| 79 | } |
| 80 | } |
| 81 | } |
| 82 | uart_send_str("bootstrap: DONE!\r\n"); |
| 83 | return 0; |
| 84 | } |
| 85 | |
| 86 | int bootstrap(void) { |
| 87 | if (!bootstrap_requested()) { |
| 88 | return 0; |
| 89 | } |
| 90 | // SPI device is only initialized in bootstrap mode. |
| 91 | spid_init(); |
| 92 | flash_init_block(); |
| 93 | |
| 94 | int rv = bootstrap_flash(); |
| 95 | |
| 96 | // Always make sure to revert flash_ctrl access to default settings. |
| 97 | // bootstrap_flash enables access to flash to perform update. |
| 98 | flash_default_region_access(/*rd_en=*/0, /*prog_en=*/0, /*erase_en=*/0); |
| 99 | return rv; |
| 100 | } |