From 8acb3ebf135389a809d4389ac448b08db119af94 Mon Sep 17 00:00:00 2001 From: David Garske Date: Fri, 26 Dec 2025 15:30:45 -0800 Subject: [PATCH 1/4] Fixes for PolarFire SoC eMMC/SD to stabilize and add read DMA support. Refactor the RISC-V boot/vector code for use on both 32-bit and 64-bit architectures. --- arch.mk | 12 +- config/examples/polarfire_mpfs250.config | 4 +- docs/Targets.md | 18 +- hal/mpfs250.c | 387 +++++++++++++++--- hal/mpfs250.h | 150 ++++--- hal/riscv.h | 164 ++++++++ include/hal.h | 6 + src/boot_riscv.c | 205 ++++++++-- src/boot_riscv64.c | 101 ----- ...oot_riscv64_start.S => boot_riscv_start.S} | 117 +++++- src/update_disk.c | 13 +- src/vector_riscv.S | 258 ++++++++---- src/vector_riscv64.S | 179 -------- src/x86/common.c | 35 +- 14 files changed, 1100 insertions(+), 549 deletions(-) create mode 100644 hal/riscv.h delete mode 100644 src/boot_riscv64.c rename src/{boot_riscv64_start.S => boot_riscv_start.S} (58%) delete mode 100644 src/vector_riscv64.S diff --git a/arch.mk b/arch.mk index a3dbd857c6..d4467bf886 100644 --- a/arch.mk +++ b/arch.mk @@ -542,7 +542,7 @@ ifeq ($(ARCH),RENESAS_RX) endif -## RISCV +## RISCV (32-bit) ifeq ($(ARCH),RISCV) CROSS_COMPILE?=riscv32-unknown-elf- ARCH_FLAGS=-march=rv32imac -mabi=ilp32 -mcmodel=medany @@ -555,11 +555,12 @@ ifeq ($(ARCH),RISCV) CFLAGS +=-ffunction-sections -fdata-sections LDFLAGS+=-Wl,--gc-sections - OBJS+=src/boot_riscv.o src/vector_riscv.o + # Unified RISC-V boot code (32/64-bit via __riscv_xlen) + OBJS+=src/boot_riscv_start.o src/boot_riscv.o src/vector_riscv.o ARCH_FLASH_OFFSET=0x20010000 endif -## RISCV64 +## RISCV64 (64-bit) ifeq ($(ARCH),RISCV64) CROSS_COMPILE?=riscv64-unknown-elf- CFLAGS+=-DMMU -DWOLFBOOT_DUALBOOT @@ -568,7 +569,7 @@ ifeq ($(ARCH),RISCV64) OBJS += src/gpt.o OBJS += src/disk.o ARCH_FLAGS=-march=rv64imafd -mabi=lp64d -mcmodel=medany - CFLAGS+=-fno-builtin-printf -DUSE_M_TIME -g -nostartfiles -DARCH_RISCV64 + CFLAGS+=-fno-builtin-printf -DUSE_M_TIME -g -nostartfiles -DARCH_RISCV -DARCH_RISCV64 CFLAGS+=$(ARCH_FLAGS) LDFLAGS+=$(ARCH_FLAGS) @@ -576,7 +577,8 @@ ifeq ($(ARCH),RISCV64) CFLAGS +=-ffunction-sections -fdata-sections LDFLAGS+=-Wl,--gc-sections - OBJS+=src/boot_riscv64_start.o src/boot_riscv64.o src/vector_riscv64.o + # Unified RISC-V boot code (32/64-bit via __riscv_xlen) + OBJS+=src/boot_riscv_start.o src/boot_riscv.o src/vector_riscv.o CFLAGS+=-DWOLFBOOT_FDT OBJS+=src/fdt.o diff --git a/config/examples/polarfire_mpfs250.config b/config/examples/polarfire_mpfs250.config index 7a709403a6..142c075ce0 100644 --- a/config/examples/polarfire_mpfs250.config +++ b/config/examples/polarfire_mpfs250.config @@ -48,8 +48,8 @@ WOLFBOOT_LOAD_ADDRESS?=0x8E000000 WOLFBOOT_NO_PARTITIONS=1 CFLAGS_EXTRA+=-DBOOT_PART_A=1 CFLAGS_EXTRA+=-DBOOT_PART_B=2 -# Speed up disk partition read (1MB chunks) -CFLAGS_EXTRA+=-DDISK_BLOCK_SIZE=0x100000 +# Speed up disk partition read (512KB chunks) +CFLAGS_EXTRA+=-DDISK_BLOCK_SIZE=0x80000 # DTS (Device Tree) WOLFBOOT_LOAD_DTS_ADDRESS?=0x8A000000 diff --git a/docs/Targets.md b/docs/Targets.md index 87dbd47215..8c42cc41a3 100644 --- a/docs/Targets.md +++ b/docs/Targets.md @@ -1034,7 +1034,7 @@ set architecture riscv:rv64 ### PolarFire Example Boot Output ``` -wolfBoot Version: 2.7.0 (Dec 22 2025 14:14:37) +wolfBoot Version: 2.7.0 (Dec 29 2025 11:34:01) Reading MBR... Found GPT PTE at sector 1 Found valid boot signature in MBR @@ -1054,19 +1054,18 @@ Checking secondary OS image in 0,2... Versions, A:1 B:1 Load address 0x8E000000 Attempting boot from P:A -Boot partition: 0x801FFDA0 (sz 19767000, ver 0x1, type 0x601) -Loading image from disk...done. -Boot partition: 0x8E000000 (sz 19767000, ver 0x1, type 0x601) -Checking image integrity...done. -Verifying image signature...done. +Boot partition: 0x801FFD80 (sz 19767004, ver 0x1, type 0x601) +Loading image from disk...done. (846 ms) +Boot partition: 0x8E000000 (sz 19767004, ver 0x1, type 0x601) +Checking image integrity...done. (1507 ms) +Verifying image signature...done. (68 ms) Firmware Valid. -Flattened uImage Tree: Version 17, Size 19767000 +Flattened uImage Tree: Version 17, Size 19767004 Loading Image kernel-1: 0x8E0002C8 -> 0x80200000 (19745280 bytes) Image kernel-1: 0x80200000 (19745280 bytes) Loading Image fdt-1: 0x8F2D4DCC -> 0x8A000000 (19897 bytes) Image fdt-1: 0x8A000000 (19897 bytes) Loading DTS: 0x8A000000 -> 0x8A000000 (19897 bytes) -Loading elf at 0x80200000 Invalid elf, falling back to raw binary Booting at 80200000 [ 0.000000] Linux version 6.12.22-linux4microchip+fpga-2025.07-g032a7095303a (oe-user@oe-host) (riscv64-oe-linux-gcc (GCC) 13.3.0, GNU ld (GNU Binutils) 2.42.0.20240723) #1 SMP Tue Jul 22 10:04:20 UTC 2025 @@ -1078,14 +1077,13 @@ Booting at 80200000 [ 0.000000] SBI RFENCE extension detected [ 0.000000] SBI SRST extension detected [ 0.000000] earlycon: ns16550a0 at MMIO32 0x0000000020100000 (options '115200n8') +[ 0.000000] printk: legacy bootconsole [ns16550a0] enabled ... ``` ### PolarFire TODO * Add eMMC/SD features: - - Improve mmc_delay and timeout handling - - DMA read support - Write support - eMMC support (not just SD) * Add support for reading serial number and modifying ethernet MAC in device tree diff --git a/hal/mpfs250.c b/hal/mpfs250.c index ef80fee784..5955f71fc6 100644 --- a/hal/mpfs250.c +++ b/hal/mpfs250.c @@ -134,15 +134,196 @@ void* hal_get_dts_address(void) } #endif - static uint32_t g_sector_count; static uint32_t g_sector_size; static uint32_t g_bus_width = 1; static uint32_t g_rca = 0; /* SD Card Relative Address */ -#ifndef DEFAULT_DELAY -#define DEFAULT_DELAY 0xFFFF +/* MMC Interrupt state - volatile for interrupt handler access */ +static volatile uint32_t g_mmc_irq_status = 0; +static volatile int g_mmc_irq_pending = 0; + +/* ============================================================================ + * PLIC - Platform-Level Interrupt Controller Functions + * ============================================================================ */ + +/* Get the current hart ID from the tp register (set during boot) */ +static inline uint32_t plic_get_hart_id(void) +{ + uint32_t hart_id; + asm volatile("mv %0, tp" : "=r"(hart_id)); + return hart_id; +} + +/* Get the PLIC context for the current hart in S-mode */ +static inline uint32_t plic_get_context(void) +{ + return PLIC_HART_TO_SMODE_CTX(plic_get_hart_id()); +} + +/* Set priority for an interrupt source */ +void plic_set_priority(uint32_t irq, uint32_t priority) +{ + if (irq > 0 && irq < PLIC_NUM_SOURCES && priority <= PLIC_PRIORITY_MAX) { + PLIC_PRIORITY(irq) = priority; + } +} + +/* Enable an interrupt for the current hart's context */ +void plic_enable_interrupt(uint32_t irq) +{ + uint32_t ctx = plic_get_context(); + if (irq > 0 && irq < PLIC_NUM_SOURCES) { + PLIC_ENABLE(ctx, irq) |= PLIC_ENABLE_BIT(irq); + } +} + +/* Disable an interrupt for the current hart's context */ +void plic_disable_interrupt(uint32_t irq) +{ + uint32_t ctx = plic_get_context(); + if (irq > 0 && irq < PLIC_NUM_SOURCES) { + PLIC_ENABLE(ctx, irq) &= ~PLIC_ENABLE_BIT(irq); + } +} + +/* Set the priority threshold for the current hart's context */ +void plic_set_threshold(uint32_t threshold) +{ + uint32_t ctx = plic_get_context(); + if (threshold <= PLIC_PRIORITY_MAX) { + PLIC_THRESHOLD(ctx) = threshold; + } +} + +/* Claim the highest priority pending interrupt (returns IRQ number, 0 if none) */ +uint32_t plic_claim(void) +{ + uint32_t ctx = plic_get_context(); + return PLIC_CLAIM(ctx); +} + +/* Signal completion of interrupt handling */ +void plic_complete(uint32_t irq) +{ + uint32_t ctx = plic_get_context(); + PLIC_COMPLETE(ctx) = irq; +} + +/* Initialize PLIC for MMC interrupt handling */ +void plic_init_mmc(void) +{ + /* Set priority for MMC main interrupt */ + plic_set_priority(PLIC_INT_MMC_MAIN, PLIC_PRIORITY_DEFAULT); + + /* Set threshold to 0 (allow all priorities > 0) */ + plic_set_threshold(0); + + /* Enable MMC interrupt for this hart */ + plic_enable_interrupt(PLIC_INT_MMC_MAIN); + +#ifdef DEBUG_MMC + wolfBoot_printf("plic_init_mmc: hart %d, context %d, irq %d enabled\n", + plic_get_hart_id(), plic_get_context(), PLIC_INT_MMC_MAIN); #endif +} + +/* ============================================================================ + * MMC Interrupt Handler + * ============================================================================ */ + +/* MMC interrupt handler - called from PLIC dispatch */ +void mmc_irq_handler(void) +{ + uint32_t status = EMMC_SD_SRS12; + + /* Check for DMA interrupt */ + if (status & EMMC_SD_SRS12_DMAINT) { + g_mmc_irq_status |= MMC_IRQ_FLAG_DMAINT; + EMMC_SD_SRS12 = EMMC_SD_SRS12_DMAINT; /* Clear interrupt */ + } + + /* Check for transfer complete */ + if (status & EMMC_SD_SRS12_TC) { + g_mmc_irq_status |= MMC_IRQ_FLAG_TC; + EMMC_SD_SRS12 = EMMC_SD_SRS12_TC; /* Clear interrupt */ + } + + /* Check for command complete */ + if (status & EMMC_SD_SRS12_CC) { + g_mmc_irq_status |= MMC_IRQ_FLAG_CC; + EMMC_SD_SRS12 = EMMC_SD_SRS12_CC; /* Clear interrupt */ + } + + /* Check for data timeout error */ + if (status & EMMC_SD_SRS12_EDT) { + g_mmc_irq_status |= MMC_IRQ_FLAG_ERROR; + EMMC_SD_SRS12 = EMMC_SD_SRS12_EDT; /* Clear interrupt */ + } + + /* Check for any other errors */ + if (status & EMMC_SD_SRS12_EINT) { + g_mmc_irq_status |= MMC_IRQ_FLAG_ERROR; + /* Clear all error status bits */ + EMMC_SD_SRS12 = (status & EMMC_SD_SRS12_ERR_STAT); + } + + /* Signal that interrupt was handled */ + g_mmc_irq_pending = 1; + +#ifdef DEBUG_MMC + wolfBoot_printf("mmc_irq_handler: status=0x%08X, flags=0x%02X\n", + status, g_mmc_irq_status); +#endif +} + +/* Enable MMC interrupts for SDMA transfer */ +static void mmc_enable_sdma_interrupts(void) +{ + /* Enable signal interrupts for: DMA, Transfer Complete, Command Complete, + * Data Timeout Error */ + uint32_t sig_enable = EMMC_SD_SRS14_DMAINT_IE | + EMMC_SD_SRS14_TC_IE | + EMMC_SD_SRS14_CC_IE | + EMMC_SD_SRS14_EDT_IE; + EMMC_SD_SRS14 |= sig_enable; + + /* Clear any pending interrupt state */ + g_mmc_irq_status = 0; + g_mmc_irq_pending = 0; +} + +/* Disable MMC signal interrupts (status enables remain for polling) */ +static void mmc_disable_sdma_interrupts(void) +{ + EMMC_SD_SRS14 &= ~(EMMC_SD_SRS14_DMAINT_IE | + EMMC_SD_SRS14_TC_IE | + EMMC_SD_SRS14_CC_IE | + EMMC_SD_SRS14_EDT_IE); +} + +/* Wait for MMC interrupt with timeout */ +static int mmc_wait_irq(uint32_t expected_flags, uint32_t timeout) +{ + while (timeout-- > 0) { + if (g_mmc_irq_pending) { + g_mmc_irq_pending = 0; + + /* Check for error */ + if (g_mmc_irq_status & MMC_IRQ_FLAG_ERROR) { + return -1; + } + + /* Check for expected flags */ + if (g_mmc_irq_status & expected_flags) { + return 0; + } + } + /* Brief delay while waiting */ + asm volatile("nop"); + } + return -1; /* Timeout */ +} static int mmc_set_timeout(uint32_t timeout_us) { @@ -198,13 +379,6 @@ static int mmc_set_timeout(uint32_t timeout_us) return 0; } -static void mmc_delay(uint32_t delay) -{ - while (delay--) { - asm volatile("nop"); - } -} - /* voltage values: * 0 = off * EMMC_SD_SRS10_BVS_1_8V @@ -241,7 +415,6 @@ static int mmc_set_power(uint32_t voltage) } /* should be - 0xf06 */ EMMC_SD_SRS10 = reg; - mmc_delay(DEFAULT_DELAY); /* delay after bus power is applied */ } return 0; } @@ -300,8 +473,6 @@ static uint32_t mmc_set_clock(uint32_t clock_khz) clock_khz, freq_khz); #endif - mmc_delay(DEFAULT_DELAY); /* delay after clock changed */ - return freq_khz; } @@ -349,27 +520,21 @@ static uint32_t mmc_get_response_type(uint8_t resp_type) return cmd_reg; } -#define DEVICE_BUSY 1 -int mmc_send_cmd(uint32_t cmd_index, uint32_t cmd_arg, uint8_t resp_type) +static int mmc_send_cmd_internal(uint32_t cmd_type, + uint32_t cmd_index, uint32_t cmd_arg, uint8_t resp_type) { int status = 0; uint32_t cmd_reg; - uint32_t cmd_type = EMMC_SD_SRS03_CMD_NORMAL; + uint32_t timeout = 0x000FFFFF; #ifdef DEBUG_MMC wolfBoot_printf("mmc_send_cmd: cmd_index: %d, cmd_arg: %08X, resp_type: %d\n", cmd_index, cmd_arg, resp_type); #endif - /* wait for command line to be idle - TODO: Add timeout */ + /* wait for command line to be idle */ while ((EMMC_SD_SRS09 & EMMC_SD_SRS09_CICMD) != 0); - /* clear all status interrupts (except current limit, card interrupt/removal/insert) */ - EMMC_SD_SRS12 = ~(EMMC_SD_SRS12_ECL | - EMMC_SD_SRS12_CINT | - EMMC_SD_SRS12_CR | - EMMC_SD_SRS12_CIN); - /* set command argument and command transfer registers */ EMMC_SD_SRS02 = cmd_arg; cmd_reg = @@ -379,19 +544,41 @@ int mmc_send_cmd(uint32_t cmd_index, uint32_t cmd_arg, uint8_t resp_type) EMMC_SD_SRS03 = cmd_reg; - /* wait for command complete or error - TODO: Add timeout */ - while ((EMMC_SD_SRS12 & (EMMC_SD_SRS12_CC | EMMC_SD_SRS12_EINT)) == 0); + /* wait for command complete or error */ + while ((EMMC_SD_SRS12 & (EMMC_SD_SRS12_CC | EMMC_SD_SRS12_TC | + EMMC_SD_SRS12_EINT)) == 0 && --timeout > 0); - /* check for device busy */ - if (resp_type == EMMC_SD_RESP_R1 || resp_type == EMMC_SD_RESP_R1B) { - uint32_t resp = EMMC_SD_SRS04; - #define CARD_STATUS_READY_FOR_DATA (1U << 8) - if ((resp & CARD_STATUS_READY_FOR_DATA) == 0) { - status = DEVICE_BUSY; /* card is busy */ + if (timeout == 0 || (EMMC_SD_SRS12 & EMMC_SD_SRS12_EINT)) { + wolfBoot_printf("mmc_send_cmd:%s error SRS12: 0x%08X\n", + (timeout == 0) ? " timeout" : "", EMMC_SD_SRS12); + status = -1; /* error */ + } + + EMMC_SD_SRS12 = EMMC_SD_SRS12_CC; /* clear command complete */ + while ((EMMC_SD_SRS09 & EMMC_SD_SRS09_CICMD) != 0); + + return status; +} + +#define DEVICE_BUSY 1 +int mmc_send_cmd(uint32_t cmd_index, uint32_t cmd_arg, uint8_t resp_type) +{ + /* send command */ + int status = mmc_send_cmd_internal(EMMC_SD_SRS03_CMD_NORMAL, cmd_index, + cmd_arg, resp_type); + if (status == 0) { + /* check for device busy */ + if (resp_type == EMMC_SD_RESP_R1 || resp_type == EMMC_SD_RESP_R1B) { + uint32_t resp = EMMC_SD_SRS04; + #define CARD_STATUS_READY_FOR_DATA (1U << 8) + if ((resp & CARD_STATUS_READY_FOR_DATA) == 0) { + status = DEVICE_BUSY; /* card is busy */ + } } } - /* clear all status interrupts (except current limit, card interrupt/removal/insert) */ + /* clear all status interrupts + * (except current limit, card interrupt/removal/insert) */ EMMC_SD_SRS12 = ~(EMMC_SD_SRS12_ECL | EMMC_SD_SRS12_CINT | EMMC_SD_SRS12_CR | @@ -425,8 +612,6 @@ int mmc_power_init_seq(uint32_t voltage) status = mmc_send_cmd(MMC_CMD0_GO_IDLE, 0, EMMC_SD_RESP_NONE); } if (status == 0) { - mmc_delay(DEFAULT_DELAY); - /* send the operating conditions command */ status = mmc_send_cmd(SD_CMD8_SEND_IF_COND, IF_COND_27V_33V, EMMC_SD_RESP_R7); @@ -458,18 +643,24 @@ int mmc_read(uint32_t cmd_index, uint32_t block_addr, uint32_t* dst, uint32_t block_count; uint32_t reg, cmd_reg; + /* get block count (round up) */ + block_count = (sz + (EMMC_SD_BLOCK_SIZE - 1)) / EMMC_SD_BLOCK_SIZE; + +#ifdef DEBUG_MMC + wolfBoot_printf("mmc_read: cmd_index: %d, block_addr: %08X, dst %p, sz: %d (%d blocks)\n", + cmd_index, block_addr, dst, sz, block_count); + wolfBoot_printf("EMMC_SD IN: SRS12: 0x%08X, SRS09: 0x%08X\n", EMMC_SD_SRS12, EMMC_SD_SRS09); +#endif + /* wait for idle */ status = mmc_wait_busy(0); /* reset data and command lines */ EMMC_SD_SRS11 |= EMMC_SD_SRS11_RESET_DAT_CMD; - mmc_delay(0xFF); /* wait for command and data line busy to clear */ while ((EMMC_SD_SRS09 & (EMMC_SD_SRS09_CICMD | EMMC_SD_SRS09_CIDAT)) != 0); - /* get block count (round up) */ - block_count = (sz + (EMMC_SD_BLOCK_SIZE - 1)) / EMMC_SD_BLOCK_SIZE; /* set transfer block count */ EMMC_SD_SRS01 = (block_count << EMMC_SD_SRS01_BCCT_SHIFT) | sz; @@ -488,56 +679,113 @@ int mmc_read(uint32_t cmd_index, uint32_t block_addr, uint32_t* dst, } else if (cmd_index == MMC_CMD18_READ_MULTIPLE) { cmd_reg |= EMMC_SD_SRS03_MSBS; /* enable multi-block select */ - EMMC_SD_SRS01 = (block_count << EMMC_SD_SRS01_BCCT_SHIFT) | - EMMC_SD_BLOCK_SIZE; - } -#ifdef DEBUG_MMC - wolfBoot_printf("mmc_read: cmd_index: %d, block_addr: %08X, dst %p, sz: %d (%d blocks)\n", - cmd_index, block_addr, dst, sz, block_count); -#endif + if (sz >= (512 * 1024)) { /* use DMA */ + cmd_reg |= EMMC_SD_SRS03_DMAE; /* enable DMA */ + + EMMC_SD_SRS01 = (block_count << EMMC_SD_SRS01_BCCT_SHIFT) | + EMMC_SD_SRS01_DMA_BUFF_512KB | EMMC_SD_BLOCK_SIZE; + + /* SDMA mode (for 32-bit transfers) */ + EMMC_SD_SRS10 |= EMMC_SD_SRS10_DMA_SDMA; + EMMC_SD_SRS15 |= EMMC_SD_SRS15_HV4E; + EMMC_SD_SRS16 &= ~EMMC_SD_SRS16_A64S; + /* set SDMA destination address */ + EMMC_SD_SRS22 = (uint32_t)(uintptr_t)dst; + EMMC_SD_SRS23 = (uint32_t)(((uint64_t)(uintptr_t)dst) >> 32); + + /* Enable SDMA interrupts */ + mmc_enable_sdma_interrupts(); + } + } EMMC_SD_SRS02 = block_addr; /* cmd argument */ EMMC_SD_SRS03 = cmd_reg; /* execute command */ - while (sz > 0) { - /* wait for buffer read ready */ - while (((reg = EMMC_SD_SRS12) & - (EMMC_SD_SRS12_BRR | EMMC_SD_SRS12_EINT)) == 0); - - /* read in buffer - read 4 bytes at a time */ - if (reg & EMMC_SD_SRS12_BRR) { - uint32_t i, read_sz = sz; - if (read_sz > EMMC_SD_BLOCK_SIZE) { - read_sz = EMMC_SD_BLOCK_SIZE; + + if (cmd_reg & EMMC_SD_SRS03_DMAE) { + while (1) { /* DMA mode with interrupt support */ + /* Wait for DMA interrupt, transfer complete, or error */ + status = mmc_wait_irq(MMC_IRQ_FLAG_DMAINT | MMC_IRQ_FLAG_TC, + 0x00FFFFFF); + if (status != 0) { + /* Timeout or error */ + wolfBoot_printf("mmc_read: SDMA interrupt timeout/error\n"); + status = -1; /* error */ + break; + } + + /* Check for transfer complete */ + if (g_mmc_irq_status & MMC_IRQ_FLAG_TC) { + g_mmc_irq_status &= ~MMC_IRQ_FLAG_TC; + break; /* Transfer complete */ } - for (i=0; i> 32); } - sz -= read_sz; } - } - if (cmd_index == MMC_CMD18_READ_MULTIPLE) { - /* send CMD12 to stop transfer - ignore response */ - (void)mmc_send_cmd(MMC_CMD12_STOP_TRANS, (g_rca << SD_RCA_SHIFT), - EMMC_SD_RESP_R1); + /* Disable SDMA interrupts after transfer */ + mmc_disable_sdma_interrupts(); + } + else { + while (sz > 0) { /* blocking mode */ + /* wait for buffer read ready (or error) */ + while (((reg = EMMC_SD_SRS12) & + (EMMC_SD_SRS12_BRR | EMMC_SD_SRS12_EINT)) == 0); + + /* read in buffer - read 4 bytes at a time */ + if (reg & EMMC_SD_SRS12_BRR) { + uint32_t i, read_sz = sz; + if (read_sz > EMMC_SD_BLOCK_SIZE) { + read_sz = EMMC_SD_BLOCK_SIZE; + } + for (i=0; i #include "image.h" #include "loader.h" +#include "hal/riscv.h" + +#ifdef TARGET_mpfs250 +#include "hal/mpfs250.h" +#endif extern void trap_entry(void); extern void trap_exit(void); +/* Linker symbols - use native pointer-sized types */ +#if __riscv_xlen == 64 +extern uint64_t _start_vector; +extern uint64_t _stored_data; +extern uint64_t _start_data; +extern uint64_t _end_data; +extern uint64_t _start_bss; +extern uint64_t _end_bss; +extern uint64_t _end_stack; +extern uint64_t _start_heap; +extern uint64_t _global_pointer; +extern void (* const trap_vector_table[])(void); +#else extern uint32_t _start_vector; extern uint32_t _stored_data; extern uint32_t _start_data; @@ -37,63 +57,157 @@ extern uint32_t _end_stack; extern uint32_t _start_heap; extern uint32_t _global_pointer; extern void (* const IV[])(void); +#endif extern void main(void); -void RAMFUNCTION reloc_iv(const uint32_t *address) + +/* reloc_trap_vector is implemented in boot_riscv_start.S */ +extern void reloc_trap_vector(const uint32_t *address); + +#ifdef TARGET_mpfs250 +/* PLIC functions from mpfs250.c */ +extern uint32_t plic_claim(void); +extern void plic_complete(uint32_t irq); +extern void mmc_irq_handler(void); +#endif + +/* ============================================================================ + * Trap Handling + * ============================================================================ */ + +#if __riscv_xlen == 64 +static uint64_t last_cause = 0; +static uint64_t last_epc = 0; +static uint64_t last_tval = 0; +#else +static uint32_t last_cause = 0; +static uint32_t last_epc = 0; +static uint32_t last_tval = 0; +#endif + +#ifdef TARGET_mpfs250 +/* Handle external interrupts via PLIC */ +static void handle_external_interrupt(void) { - asm volatile("csrw mtvec, %0":: "r"(address + 1)); + uint32_t irq; + + /* Claim the interrupt from PLIC */ + while ((irq = plic_claim()) != 0) { + /* Dispatch to appropriate handler based on IRQ number */ + switch (irq) { + case PLIC_INT_MMC_MAIN: + mmc_irq_handler(); + break; + default: + /* Unknown interrupt - just complete it */ + break; + } + + /* Signal completion to PLIC */ + plic_complete(irq); + } } +#endif -void __attribute__((naked,section(".init"))) _reset(void) { - register uint32_t *src, *dst; - asm volatile("la gp, _global_pointer"); - asm volatile("la sp, _end_stack"); - - /* Set up vectored interrupt, with IV starting at offset 0x100 */ - asm volatile("csrw mtvec, %0":: "r"((uint8_t *)(&_start_vector) + 1)); - - src = (uint32_t *) &_stored_data; - dst = (uint32_t *) &_start_data; - /* Copy the .data section from flash to RAM. */ - while (dst < (uint32_t *)&_end_data) { - *dst = *src; - dst++; - src++; +unsigned long WEAKFUNCTION handle_trap(unsigned long cause, unsigned long epc, + unsigned long tval) +{ + last_cause = cause; + last_epc = epc; + last_tval = tval; + +#ifdef TARGET_mpfs250 + /* Check if this is an interrupt (MSB set) */ + if (cause & MCAUSE_INT) { + unsigned long exception_code = cause & MCAUSE_CAUSE; + + /* Check for external interrupt (S-mode external = 9, M-mode external = 11) */ + if (exception_code == IRQ_S_EXT || exception_code == IRQ_M_EXT) { + handle_external_interrupt(); + } + /* Other interrupts (timer, software) can be handled here if needed */ } + /* Synchronous exceptions are not handled - just record them */ +#endif - /* Initialize the BSS section to 0 */ - dst = &_start_bss; - while (dst < (uint32_t *)&_end_bss) { - *dst = 0U; - dst++; - } + return epc; +} - /* Run wolfboot */ - main(); +/* ============================================================================ + * Timer Functions + * ============================================================================ */ - /* Should never return */ - wolfBoot_panic(); +uint64_t hal_get_timer(void) +{ +#if __riscv_xlen == 64 + /* For RV64, CSR time contains full 64-bit value */ + return csr_read(time); +#else + /* For RV32, read both timeh and time with wrap-around protection */ + uint32_t hi, lo; + + do { + hi = csr_read(timeh); + lo = csr_read(time); + } while (hi != csr_read(timeh)); + + return ((uint64_t)hi << 32) | lo; +#endif } -void do_boot(const uint32_t *app_offset) +/* Get timer value in microseconds + * Formula: time_us = (ticks * 1000) / (rate / 1000) + * = (ticks * 1000000) / rate + */ +uint64_t hal_get_timer_us(void) { -#if 1 - /* workaround for long jump */ - asm volatile("la a2, reloc_iv;" \ - "jalr a2" ::: "a2"); + uint64_t ticks = hal_get_timer(); + uint32_t rate = RISCV_SMODE_TIMER_FREQ; + + /* Avoid overflow: (ticks * 1000) / (rate / 1000) */ + return (ticks * 1000) / (rate / 1000); +} + +/* ============================================================================ + * Boot Functions + * ============================================================================ */ + +#ifdef MMU +int WEAKFUNCTION hal_dts_fixup(void* dts_addr) +{ + (void)dts_addr; + return 0; +} +#endif + +#ifdef MMU +void do_boot(const uint32_t *app_offset, const uint32_t* dts_offset) #else - reloc_iv(app_offset); +void do_boot(const uint32_t *app_offset) #endif +{ +#ifdef MMU + hal_dts_fixup((uint32_t*)dts_offset); +#endif + + /* Relocate trap vector table to application */ + reloc_trap_vector(app_offset); + + /* Jump to application entry point */ asm volatile("jr %0":: "r"((uint8_t *)(app_offset))); } void isr_empty(void) { - + /* Empty interrupt handler */ } -#ifdef RAM_CODE +/* ============================================================================ + * Reboot Functions + * ============================================================================ */ +#if __riscv_xlen == 32 && defined(RAM_CODE) +/* RV32 HiFive1 watchdog-based reboot */ #define AON_WDOGCFG *(volatile uint32_t *)(0x10000000UL) #define AON_WDOGKEY *(volatile uint32_t *)(0x1000001CUL) #define AON_WDOGFEED *(volatile uint32_t *)(0x10000018UL) @@ -105,14 +219,14 @@ void isr_empty(void) #define AON_WDOGCFG_ZEROCMP 0x00000200 #define AON_WDOGCFG_ENALWAYS 0x00001000 - void RAMFUNCTION arch_reboot(void) { AON_WDOGKEY = AON_WDOGKEY_VALUE; AON_WDOGCMP = 0; - //wdogconfig: : wdogrsten | enablealways | reset to 0 | max scale + /* wdogconfig: wdogrsten | enablealways | reset to 0 | max scale */ AON_WDOGKEY = AON_WDOGKEY_VALUE; - AON_WDOGCFG |= (AON_WDOGCFG_RSTEN | AON_WDOGCFG_ENALWAYS | AON_WDOGCFG_ZEROCMP | AON_WDOGCFG_SCALE) ; + AON_WDOGCFG |= (AON_WDOGCFG_RSTEN | AON_WDOGCFG_ENALWAYS | + AON_WDOGCFG_ZEROCMP | AON_WDOGCFG_SCALE); AON_WDOGKEY = AON_WDOGKEY_VALUE; AON_WDOGFEED = 1; @@ -121,4 +235,17 @@ void RAMFUNCTION arch_reboot(void) wolfBoot_panic(); } -#endif /* RAM_CODE */ +#else /* RV64 or non-RAM_CODE */ + +void WEAKFUNCTION arch_reboot(void) +{ +#ifdef TARGET_mpfs250 + SYSREG_MSS_RESET_CR = 0xDEAD; +#endif + + while(1) + ; + wolfBoot_panic(); +} + +#endif /* __riscv_xlen == 32 && RAM_CODE */ diff --git a/src/boot_riscv64.c b/src/boot_riscv64.c deleted file mode 100644 index b71733002f..0000000000 --- a/src/boot_riscv64.c +++ /dev/null @@ -1,101 +0,0 @@ -/* boot_riscv64.c - * - * Copyright (C) 2025 wolfSSL Inc. - * - * This file is part of wolfBoot. - * - * wolfBoot is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * wolfBoot is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA - */ - -/* RISC-V 64-bit boot code */ - -#include - -#include "image.h" -#include "loader.h" - -#ifdef TARGET_mpfs250 -#include "hal/mpfs250.h" -#endif - -extern void trap_entry(void); -extern void trap_exit(void); - -extern uint64_t _start_vector; -extern uint64_t _stored_data; -extern uint64_t _start_data; -extern uint64_t _end_data; -extern uint64_t _start_bss; -extern uint64_t _end_bss; -extern uint64_t _end_stack; -extern uint64_t _start_heap; -extern uint64_t _global_pointer; -extern void (* const trap_vector_table[])(void); - -/* reloc_trap_vector is implemented in boot_riscv64_start.S */ -extern void reloc_trap_vector(const uint32_t *address); - -static uint64_t last_cause = 0; -static uint64_t last_epc = 0; -static uint64_t last_tval = 0; - -unsigned long WEAKFUNCTION handle_trap(unsigned long cause, unsigned long epc, unsigned long tval) -{ - last_cause = cause; - last_epc = epc; - last_tval = tval; - return epc; -} - -#ifdef MMU -int WEAKFUNCTION hal_dts_fixup(void* dts_addr) -{ - (void)dts_addr; - return 0; -} -#endif - -#ifdef MMU -void do_boot(const uint32_t *app_offset, const uint32_t* dts_offset) -#else -void do_boot(const uint32_t *app_offset) -#endif -{ -#ifdef MMU - hal_dts_fixup((uint32_t*)dts_offset); -#endif - - /* Relocate trap vector table to application */ - reloc_trap_vector(app_offset); - - /* Jump to application entry point */ - asm volatile("jr %0":: "r"((uint8_t *)(app_offset))); -} - -void isr_empty(void) -{ - /* Empty interrupt handler */ -} - -void WEAKFUNCTION arch_reboot(void) -{ -#ifdef TARGET_mpfs250 - SYSREG_MSS_RESET_CR = 0xDEAD; -#endif - - while(1) - ; - wolfBoot_panic(); -} diff --git a/src/boot_riscv64_start.S b/src/boot_riscv_start.S similarity index 58% rename from src/boot_riscv64_start.S rename to src/boot_riscv_start.S index 82b7e1c446..4ed11d5efc 100644 --- a/src/boot_riscv64_start.S +++ b/src/boot_riscv_start.S @@ -1,5 +1,5 @@ /** - * RISC-V 64-bit bootup + * RISC-V bootup (32-bit and 64-bit unified) * Copyright (C) 2025 wolfSSL Inc. * * This file is part of wolfBoot. @@ -19,22 +19,38 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA */ +#include "hal/riscv.h" + #ifdef TARGET_mpfs250 #include "hal/mpfs250.h" #endif -/* - * ============================================================ - * RISC-V 64-bit Boot Entry Point - * ============================================================ - * Entry conditions (passed by prior boot stage / SBI): - * a0 = hart ID (hardware thread identifier) - * a1 = pointer to device tree blob (DTB) in memory - * ============================================================ - */ +#ifdef WOLFBOOT_RISCV_SMODE +#define MODE_PREFIX(__suffix) s##__suffix +#else +#define MODE_PREFIX(__suffix) m##__suffix +#endif + + +/* ============================================================================ + * RISC-V Boot Entry Point + * ============================================================================ + * + * For RV64 (typically running under SBI): + * Entry conditions (passed by prior boot stage / SBI): + * a0 = hart ID (hardware thread identifier) + * a1 = pointer to device tree blob (DTB) in memory + * + * For RV32 (typically bare metal): + * Starts fresh, reads hart ID from CSR + * + * ============================================================================ */ .section .init .globl _reset _reset: +#if __riscv_xlen == 64 + /* ---------- RV64 Boot Sequence ---------- */ + #ifdef WOLFBOOT_RISCV_MMODE /* * Machine Mode: Read hart ID from CSR since we're the first code @@ -77,19 +93,35 @@ _reset: csrw MODE_PREFIX(ie), zero /* - * Selectively enable Software Interrupts (IPIs) only. - * IPIs are required for multi-hart boot coordination - secondary harts - * may need to be woken via software interrupt after initialization. - * - M-mode: Set MSIE (Machine Software Interrupt Enable) bit - * - S-mode: Set SSIE (Supervisor Software Interrupt Enable) bit + * Enable interrupt sources: + * - Software Interrupts (IPIs) for multi-hart boot coordination + * - External Interrupts for PLIC-routed peripheral interrupts (e.g., MMC) + * + * M-mode: MSIE (Software) + MEIE (External) + * S-mode: SSIE (Software) + SEIE (External) */ #ifdef WOLFBOOT_RISCV_SMODE - li t0, SIE_SSIE + li t0, (SIE_SSIE | SIE_SEIE) #else - li t0, MIE_MSIE + li t0, (MIE_MSIE | MIE_MEIE) #endif csrs MODE_PREFIX(ie), t0 + /* + * Enable global interrupts by setting the SIE/MIE bit in sstatus/mstatus. + * Without this, the CPU will never take interrupts regardless of the + * per-source enables in sie/mie. + * + * M-mode: mstatus.MIE (bit 3) + * S-mode: sstatus.SIE (bit 1) + */ +#ifdef WOLFBOOT_RISCV_SMODE + li t0, SSTATUS_SIE +#else + li t0, MSTATUS_MIE +#endif + csrs MODE_PREFIX(status), t0 + /* * Initialize stack pointer: * WOLFBOOT_STACK_TOP = 0x80000000 (M-mode) or 0x80200000 (S-mode) @@ -122,7 +154,49 @@ _reset: mv a0, tp j main -/* +#else /* __riscv_xlen == 32 */ + /* ---------- RV32 Boot Sequence ---------- */ + + /* Initialize global pointer for position-independent access to globals */ + la gp, _global_pointer + + /* Initialize stack pointer to top of stack */ + la sp, _end_stack + + /* Set up vectored interrupt, with IV starting at offset 0x100 */ + la t0, _start_vector + addi t0, t0, 1 + csrw mtvec, t0 + + /* Copy the .data section from flash to RAM */ + la t0, _stored_data + la t1, _start_data + la t2, _end_data +1: + bge t1, t2, 2f + LOAD t3, 0(t0) + STORE t3, 0(t1) + addi t0, t0, REGBYTES + addi t1, t1, REGBYTES + j 1b +2: + + /* Initialize the BSS section to 0 */ + la t0, _start_bss + la t1, _end_bss +3: + bge t0, t1, 4f + STORE zero, 0(t0) + addi t0, t0, REGBYTES + j 3b +4: + + /* Run wolfboot - main() should never return */ + j main + +#endif /* __riscv_xlen */ + +/* ============================================================================ * reloc_trap_vector - Relocate trap vector table * * Parameters: @@ -130,9 +204,14 @@ _reset: * * Sets the trap-vector base-address register to (address + 4), * accounting for the header offset in the application image. - */ + * ============================================================================ */ .globl reloc_trap_vector reloc_trap_vector: addi a0, a0, 4 /* address + 1 (uint32_t* = +4 bytes) */ +#if __riscv_xlen == 64 csrw MODE_PREFIX(tvec), a0 +#else + csrw mtvec, a0 +#endif ret + diff --git a/src/update_disk.c b/src/update_disk.c index fa20f2fe7b..056cc1f1ce 100644 --- a/src/update_disk.c +++ b/src/update_disk.c @@ -116,6 +116,7 @@ void RAMFUNCTION wolfBoot_start(void) uint32_t dts_size = 0; #endif char part_name[4] = {'P', ':', 'X', '\0'}; + uint64_t start_us, elapsed_ms; ret = disk_init(BOOT_DISK); if (ret != 0) { @@ -208,6 +209,7 @@ void RAMFUNCTION wolfBoot_start(void) /* Read the image into RAM */ wolfBoot_printf("Loading image from disk..."); + start_us = hal_get_timer_us(); load_off = 0; do { ret = disk_part_read(BOOT_DISK, cur_part, load_off, @@ -223,7 +225,8 @@ void RAMFUNCTION wolfBoot_start(void) selected ^= 1; continue; } - wolfBoot_printf("done.\r\n"); + elapsed_ms = (hal_get_timer_us() - start_us) / 1000; + wolfBoot_printf("done. (%lu ms)\r\n", (unsigned long)elapsed_ms); memset(&os_image, 0, sizeof(os_image)); ret = wolfBoot_open_image_address(&os_image, (void*)load_address); @@ -234,21 +237,25 @@ void RAMFUNCTION wolfBoot_start(void) } wolfBoot_printf("Checking image integrity..."); + start_us = hal_get_timer_us(); if (wolfBoot_verify_integrity(&os_image) != 0) { wolfBoot_printf("Error validating integrity for %s\r\n", part_name); selected ^= 1; continue; } - wolfBoot_printf("done.\r\n"); + elapsed_ms = (hal_get_timer_us() - start_us) / 1000; + wolfBoot_printf("done. (%lu ms)\r\n", (unsigned long)elapsed_ms); wolfBoot_printf("Verifying image signature..."); + start_us = hal_get_timer_us(); if (wolfBoot_verify_authenticity(&os_image) != 0) { wolfBoot_printf("Error validating authenticity for %s\r\n", part_name); selected ^= 1; continue; } else { - wolfBoot_printf("done.\r\n"); + elapsed_ms = (hal_get_timer_us() - start_us) / 1000; + wolfBoot_printf("done. (%lu ms)\r\n", (unsigned long)elapsed_ms); failures = 0; break; /* Success case */ } diff --git a/src/vector_riscv.S b/src/vector_riscv.S index b2f5b09b5f..a79f89a900 100644 --- a/src/vector_riscv.S +++ b/src/vector_riscv.S @@ -1,5 +1,5 @@ /** - * RISC-V bootup + * RISC-V vector table (32-bit and 64-bit unified) * Copyright (C) 2025 wolfSSL Inc. * * This file is part of wolfBoot. @@ -19,122 +19,238 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA */ +#include "hal/riscv.h" + +#ifdef TARGET_mpfs250 +#include "hal/mpfs250.h" +#endif + +/* ============================================================================ + * Trap Entry/Exit Macros + * ============================================================================ */ + +#if __riscv_xlen == 64 + +/* RV64: Save all caller-saved registers and call handle_trap */ .macro trap_entry - addi sp, sp, -64 - sw x1, 0(sp) - sw x5, 4(sp) - sw x6, 8(sp) - sw x7, 12(sp) - sw x10, 16(sp) - sw x11, 20(sp) - sw x12, 24(sp) - sw x13, 28(sp) - sw x14, 32(sp) - sw x15, 36(sp) - sw x16, 40(sp) - sw x17, 44(sp) - sw x28, 48(sp) - sw x29, 52(sp) - sw x30, 56(sp) - sw x31, 60(sp) + addi sp, sp, -32 * REGBYTES + STORE x1, 1 * REGBYTES(sp) + STORE x2, 2 * REGBYTES(sp) + STORE x3, 3 * REGBYTES(sp) + STORE x4, 4 * REGBYTES(sp) + STORE x5, 5 * REGBYTES(sp) + STORE x6, 6 * REGBYTES(sp) + STORE x7, 7 * REGBYTES(sp) + STORE x8, 8 * REGBYTES(sp) + STORE x9, 9 * REGBYTES(sp) + STORE x10, 10 * REGBYTES(sp) + STORE x11, 11 * REGBYTES(sp) + STORE x12, 12 * REGBYTES(sp) + STORE x13, 13 * REGBYTES(sp) + STORE x14, 14 * REGBYTES(sp) + STORE x15, 15 * REGBYTES(sp) + STORE x16, 16 * REGBYTES(sp) + STORE x17, 17 * REGBYTES(sp) + STORE x18, 18 * REGBYTES(sp) + STORE x19, 19 * REGBYTES(sp) + STORE x20, 20 * REGBYTES(sp) + STORE x21, 21 * REGBYTES(sp) + STORE x22, 22 * REGBYTES(sp) + STORE x23, 23 * REGBYTES(sp) + STORE x24, 24 * REGBYTES(sp) + STORE x25, 25 * REGBYTES(sp) + STORE x26, 26 * REGBYTES(sp) + STORE x27, 27 * REGBYTES(sp) + STORE x28, 28 * REGBYTES(sp) + STORE x29, 29 * REGBYTES(sp) + STORE x30, 30 * REGBYTES(sp) + STORE x31, 31 * REGBYTES(sp) +#ifdef WOLFBOOT_RISCV_SMODE + csrr a0, scause + csrr a1, sepc + csrr a2, stval +#else + csrr a0, mcause + csrr a1, mepc + csrr a2, mtval +#endif + mv a3, sp + jal handle_trap +#ifdef WOLFBOOT_RISCV_SMODE + csrw sepc, a0 +#else + csrw mepc, a0 +#endif +.endm + +.macro trap_exit + LOAD x1, 1 * REGBYTES(sp) + LOAD x3, 3 * REGBYTES(sp) + LOAD x4, 4 * REGBYTES(sp) + LOAD x5, 5 * REGBYTES(sp) + LOAD x6, 6 * REGBYTES(sp) + LOAD x7, 7 * REGBYTES(sp) + LOAD x8, 8 * REGBYTES(sp) + LOAD x9, 9 * REGBYTES(sp) + LOAD x10, 10 * REGBYTES(sp) + LOAD x11, 11 * REGBYTES(sp) + LOAD x12, 12 * REGBYTES(sp) + LOAD x13, 13 * REGBYTES(sp) + LOAD x14, 14 * REGBYTES(sp) + LOAD x15, 15 * REGBYTES(sp) + LOAD x16, 16 * REGBYTES(sp) + LOAD x17, 17 * REGBYTES(sp) + LOAD x18, 18 * REGBYTES(sp) + LOAD x19, 19 * REGBYTES(sp) + LOAD x20, 20 * REGBYTES(sp) + LOAD x21, 21 * REGBYTES(sp) + LOAD x22, 22 * REGBYTES(sp) + LOAD x23, 23 * REGBYTES(sp) + LOAD x24, 24 * REGBYTES(sp) + LOAD x25, 25 * REGBYTES(sp) + LOAD x26, 26 * REGBYTES(sp) + LOAD x27, 27 * REGBYTES(sp) + LOAD x28, 28 * REGBYTES(sp) + LOAD x29, 29 * REGBYTES(sp) + LOAD x30, 30 * REGBYTES(sp) + LOAD x31, 31 * REGBYTES(sp) + LOAD x2, 2 * REGBYTES(sp) + addi sp, sp, 32 * REGBYTES +#ifdef WOLFBOOT_RISCV_SMODE + sret +#else + mret +#endif .endm +#else /* __riscv_xlen == 32 */ + +/* RV32: Save caller-saved registers (minimal set) */ +.macro trap_entry + addi sp, sp, -64 + STORE x1, 0(sp) + STORE x5, 4(sp) + STORE x6, 8(sp) + STORE x7, 12(sp) + STORE x10, 16(sp) + STORE x11, 20(sp) + STORE x12, 24(sp) + STORE x13, 28(sp) + STORE x14, 32(sp) + STORE x15, 36(sp) + STORE x16, 40(sp) + STORE x17, 44(sp) + STORE x28, 48(sp) + STORE x29, 52(sp) + STORE x30, 56(sp) + STORE x31, 60(sp) +.endm .macro trap_exit - lw x1, 0(sp) - lw x5, 4(sp) - lw x6, 8(sp) - lw x7, 12(sp) - lw x10, 16(sp) - lw x11, 20(sp) - lw x12, 24(sp) - lw x13, 28(sp) - lw x14, 32(sp) - lw x15, 36(sp) - lw x16, 40(sp) - lw x17, 44(sp) - lw x28, 48(sp) - lw x29, 52(sp) - lw x30, 56(sp) - lw x31, 60(sp) - addi sp, sp, 64 - mret + LOAD x1, 0(sp) + LOAD x5, 4(sp) + LOAD x6, 8(sp) + LOAD x7, 12(sp) + LOAD x10, 16(sp) + LOAD x11, 20(sp) + LOAD x12, 24(sp) + LOAD x13, 28(sp) + LOAD x14, 32(sp) + LOAD x15, 36(sp) + LOAD x16, 40(sp) + LOAD x17, 44(sp) + LOAD x28, 48(sp) + LOAD x29, 52(sp) + LOAD x30, 56(sp) + LOAD x31, 60(sp) + addi sp, sp, 64 + mret .endm +#endif /* __riscv_xlen */ + +/* ============================================================================ + * Vector Table + * ============================================================================ */ + .section .isr_vector .align 8 +#if __riscv_xlen == 64 +.global trap_vector_table +trap_vector_table: +#else .global IV - IV: +#endif j _synctrap - .align 2 + .align VECTOR_ALIGN j trap_empty - .align 2 + .align VECTOR_ALIGN j trap_empty - .align 2 + .align VECTOR_ALIGN j trap_empty - .align 2 + .align VECTOR_ALIGN j trap_empty - .align 2 + .align VECTOR_ALIGN j trap_empty - .align 2 + .align VECTOR_ALIGN j trap_empty - .align 2 + .align VECTOR_ALIGN j trap_empty - .align 2 + .align VECTOR_ALIGN j trap_empty - .align 2 + .align VECTOR_ALIGN j trap_empty - .align 2 + .align VECTOR_ALIGN j trap_empty - .align 2 + .align VECTOR_ALIGN j trap_empty - .align 2 + .align VECTOR_ALIGN j trap_empty - .align 2 + .align VECTOR_ALIGN j trap_empty - .align 2 + .align VECTOR_ALIGN j trap_empty - .align 2 + .align VECTOR_ALIGN j trap_empty - .align 2 + .align VECTOR_ALIGN j trap_empty - .align 2 + .align VECTOR_ALIGN j trap_empty - .align 2 + .align VECTOR_ALIGN j trap_empty - .align 2 + .align VECTOR_ALIGN j trap_empty - .align 2 + .align VECTOR_ALIGN j trap_empty - .align 2 + .align VECTOR_ALIGN j trap_empty - .align 2 + .align VECTOR_ALIGN j trap_empty - .align 2 + .align VECTOR_ALIGN j trap_empty - .align 2 + .align VECTOR_ALIGN j trap_empty - .align 2 + .align VECTOR_ALIGN j trap_empty - .align 2 + .align VECTOR_ALIGN j trap_empty - .align 2 + .align VECTOR_ALIGN j trap_empty - .align 2 + .align VECTOR_ALIGN j trap_empty - .align 2 + .align VECTOR_ALIGN j trap_empty - .align 2 + .align VECTOR_ALIGN j trap_empty - .align 2 + .align VECTOR_ALIGN j trap_empty - .align 2 + .align VECTOR_ALIGN _synctrap: - trap_entry - trap_exit + trap_entry + trap_exit trap_empty: nop diff --git a/src/vector_riscv64.S b/src/vector_riscv64.S deleted file mode 100644 index a960f841e6..0000000000 --- a/src/vector_riscv64.S +++ /dev/null @@ -1,179 +0,0 @@ -/** - * RISC-V 64-bit vector table - * Copyright (C) 2025 wolfSSL Inc. - * - * This file is part of wolfBoot. - * - * wolfBoot is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * wolfBoot is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA - */ - -#include "hal/mpfs250.h" - -/* RISC-V 64-bit trap/exception handling macros */ -.macro trap_entry - addi sp, sp, -32 * REGBYTES - sd x1, 1 * REGBYTES(sp) - sd x2, 2 * REGBYTES(sp) - sd x3, 3 * REGBYTES(sp) - sd x4, 4 * REGBYTES(sp) - sd x5, 5 * REGBYTES(sp) - sd x6, 6 * REGBYTES(sp) - sd x7, 7 * REGBYTES(sp) - sd x8, 8 * REGBYTES(sp) - sd x9, 9 * REGBYTES(sp) - sd x10, 10 * REGBYTES(sp) - sd x11, 11 * REGBYTES(sp) - sd x12, 12 * REGBYTES(sp) - sd x13, 13 * REGBYTES(sp) - sd x14, 14 * REGBYTES(sp) - sd x15, 15 * REGBYTES(sp) - sd x16, 16 * REGBYTES(sp) - sd x17, 17 * REGBYTES(sp) - sd x18, 18 * REGBYTES(sp) - sd x19, 19 * REGBYTES(sp) - sd x20, 20 * REGBYTES(sp) - sd x21, 21 * REGBYTES(sp) - sd x22, 22 * REGBYTES(sp) - sd x23, 23 * REGBYTES(sp) - sd x24, 24 * REGBYTES(sp) - sd x25, 25 * REGBYTES(sp) - sd x26, 26 * REGBYTES(sp) - sd x27, 27 * REGBYTES(sp) - sd x28, 28 * REGBYTES(sp) - sd x29, 29 * REGBYTES(sp) - sd x30, 30 * REGBYTES(sp) - sd x31, 31 * REGBYTES(sp) - csrr a0, MODE_PREFIX(cause) - csrr a1, MODE_PREFIX(epc) - csrr a2, MODE_PREFIX(tval) - mv a3, sp - jal handle_trap - csrw MODE_PREFIX(epc), a0 -.endm - -.macro trap_exit - ld x1, 1 * REGBYTES(sp) - ld x3, 3 * REGBYTES(sp) - ld x4, 4 * REGBYTES(sp) - ld x5, 5 * REGBYTES(sp) - ld x6, 6 * REGBYTES(sp) - ld x7, 7 * REGBYTES(sp) - ld x8, 8 * REGBYTES(sp) - ld x9, 9 * REGBYTES(sp) - ld x10, 10 * REGBYTES(sp) - ld x11, 11 * REGBYTES(sp) - ld x12, 12 * REGBYTES(sp) - ld x13, 13 * REGBYTES(sp) - ld x14, 14 * REGBYTES(sp) - ld x15, 15 * REGBYTES(sp) - ld x16, 16 * REGBYTES(sp) - ld x17, 17 * REGBYTES(sp) - ld x18, 18 * REGBYTES(sp) - ld x19, 19 * REGBYTES(sp) - ld x20, 20 * REGBYTES(sp) - ld x21, 21 * REGBYTES(sp) - ld x22, 22 * REGBYTES(sp) - ld x23, 23 * REGBYTES(sp) - ld x24, 24 * REGBYTES(sp) - ld x25, 25 * REGBYTES(sp) - ld x26, 26 * REGBYTES(sp) - ld x27, 27 * REGBYTES(sp) - ld x28, 28 * REGBYTES(sp) - ld x29, 29 * REGBYTES(sp) - ld x30, 30 * REGBYTES(sp) - ld x31, 31 * REGBYTES(sp) - ld x2, 2 * REGBYTES(sp) - addi sp, sp, 32 * REGBYTES - mret -.endm - -.section .isr_vector -.align 8 - -.global trap_vector_table -trap_vector_table: - j _synctrap - .align 3 - j trap_empty - .align 3 - j trap_empty - .align 3 - j trap_empty - .align 3 - j trap_empty - .align 3 - j trap_empty - .align 3 - j trap_empty - .align 3 - j trap_empty - .align 3 - j trap_empty - .align 3 - j trap_empty - .align 3 - j trap_empty - .align 3 - j trap_empty - .align 3 - j trap_empty - .align 3 - j trap_empty - .align 3 - j trap_empty - .align 3 - j trap_empty - .align 3 - j trap_empty - .align 3 - j trap_empty - .align 3 - j trap_empty - .align 3 - j trap_empty - .align 3 - j trap_empty - .align 3 - j trap_empty - .align 3 - j trap_empty - .align 3 - j trap_empty - .align 3 - j trap_empty - .align 3 - j trap_empty - .align 3 - j trap_empty - .align 3 - j trap_empty - .align 3 - j trap_empty - .align 3 - j trap_empty - .align 3 - j trap_empty - .align 3 - j trap_empty - .align 3 - j trap_empty - .align 3 - -_synctrap: - trap_entry - trap_exit - -trap_empty: - nop diff --git a/src/x86/common.c b/src/x86/common.c index 4f0b8ac880..051d8c896b 100644 --- a/src/x86/common.c +++ b/src/x86/common.c @@ -263,6 +263,37 @@ void delay(int msec) io_write8(0x80, 0x41); } +/* x86 TSC (Time Stamp Counter) frequency in MHz + * Default 2 GHz, can be overridden in target configuration */ +#ifndef X86_TSC_FREQ_MHZ +#define X86_TSC_FREQ_MHZ 2000 +#endif + +/** + * @brief Read the x86 Time Stamp Counter (TSC). + * + * @return The current TSC value as a 64-bit integer. + */ +static inline uint64_t rdtsc(void) +{ + uint32_t lo, hi; + __asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi)); + return ((uint64_t)hi << 32) | lo; +} + +/** + * @brief Get the current timer value in microseconds. + * + * Uses the x86 TSC for timing measurements. The TSC frequency + * is configured via X86_TSC_FREQ_MHZ (default 2000 MHz). + * + * @return The current time in microseconds. + */ +uint64_t hal_get_timer_us(void) +{ + return rdtsc() / X86_TSC_FREQ_MHZ; +} + /** * @brief Enter an infinite loop, causing a panic state. * @@ -441,9 +472,9 @@ int x86_run_fsp_32bit(void* api, void* arg) /* save status */ "mov %%ebx, %[status]\n" :[status]"=m"(status) - :[SEG_COMP]"i"(GDT_CS_32BIT_COMPAT), + :[SEG_COMP]"i"(GDT_CS_32BIT_COMPAT), [SEG_LONG]"i"(GDT_CS_64BIT), - [PG]"i"(CR0_PG_BIT), + [PG]"i"(CR0_PG_BIT), [LME]"i"(IA32_EFER_LME), [PAE]"i"(CR4_PAE_BIT), [api]"r"(api), From f017826d3bbec6a05e0db90448a2377a2abbb6f9 Mon Sep 17 00:00:00 2001 From: David Garske Date: Mon, 29 Dec 2025 11:44:03 -0800 Subject: [PATCH 2/4] Fix for Yocto Linux boot issue with smpboot and hartid. --- src/boot_riscv.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 76 insertions(+), 2 deletions(-) diff --git a/src/boot_riscv.c b/src/boot_riscv.c index 9d022cf266..44f4400bae 100644 --- a/src/boot_riscv.c +++ b/src/boot_riscv.c @@ -25,6 +25,9 @@ #include "image.h" #include "loader.h" +#ifdef DEBUG_BOOT +#include "printf.h" +#endif #include "hal/riscv.h" #ifdef TARGET_mpfs250 @@ -180,21 +183,92 @@ int WEAKFUNCTION hal_dts_fixup(void* dts_addr) } #endif +#if __riscv_xlen == 64 +/* Get the hartid saved by boot_riscv_start.S in the tp register */ +static inline unsigned long get_boot_hartid(void) +{ + unsigned long hartid; + asm volatile("mv %0, tp" : "=r"(hartid)); + return hartid; +} +#endif + #ifdef MMU void do_boot(const uint32_t *app_offset, const uint32_t* dts_offset) #else void do_boot(const uint32_t *app_offset) #endif { +#if __riscv_xlen == 64 + unsigned long hartid; +#endif +#ifdef MMU + unsigned long dts_addr; +#endif + #ifdef MMU hal_dts_fixup((uint32_t*)dts_offset); + dts_addr = (unsigned long)dts_offset; +#endif + +#if __riscv_xlen == 64 + /* Get the hartid that was saved by boot_riscv_start.S in tp register. + * This is the hartid passed to wolfBoot by the prior boot stage (e.g., HSS). + * For MPFS, this should be 1-4 (U54 cores), never 0 (E51 monitor core). */ + hartid = get_boot_hartid(); +#endif + +#ifdef DEBUG_BOOT + wolfBoot_printf("do_boot: entry=0x%lx", (unsigned long)app_offset); +#if __riscv_xlen == 64 + wolfBoot_printf(", hartid=%lu", hartid); +#endif +#ifdef MMU + wolfBoot_printf(", dts=0x%lx", dts_addr); +#endif + wolfBoot_printf("\n"); #endif /* Relocate trap vector table to application */ reloc_trap_vector(app_offset); - /* Jump to application entry point */ - asm volatile("jr %0":: "r"((uint8_t *)(app_offset))); + /* + * RISC-V Linux kernel boot requirements (Documentation/arch/riscv/boot.rst): + * a0 = hartid of the current core + * a1 = physical address of the device tree blob (DTB) + * satp = 0 (MMU disabled) + * + * For SMP systems using ordered booting (preferred), only the boot hart + * enters the kernel. Secondary harts are started via SBI HSM extension. + */ + +#if __riscv_xlen == 64 +#ifdef MMU + asm volatile( + #ifdef WOLFBOOT_RISCV_SMODE + "csrw satp, zero\n" + "sfence.vma\n" + #endif + "mv a0, %0\n" + "mv a1, %1\n" + "jr %2\n" + : : "r"(hartid), "r"(dts_addr), "r"(app_offset) : "a0", "a1" + ); +#else + asm volatile( + "mv a0, %0\n" + "mv a1, zero\n" + "jr %1\n" + : : "r"(hartid), "r"(app_offset) : "a0", "a1" + ); +#endif +#else /* RV32 */ + /* RV32: typically bare-metal without Linux, simpler boot */ + asm volatile("jr %0" : : "r"(app_offset)); +#endif + + /* Should never reach here */ + __builtin_unreachable(); } void isr_empty(void) From 61aa031c9034c88acd2b3520435c4b75ae363adc Mon Sep 17 00:00:00 2001 From: David Garske Date: Mon, 29 Dec 2025 14:28:53 -0800 Subject: [PATCH 3/4] Add kernel boot args (for rootfs). Added optional SD tuning support. Yocto Linux is fully working now! --- docs/Targets.md | 23 +++- hal/mpfs.dtb | Bin 19897 -> 0 bytes hal/mpfs250.c | 294 ++++++++++++++++++++++++++++++++++++++++++++--- hal/mpfs250.h | 1 + src/boot_riscv.c | 2 +- 5 files changed, 305 insertions(+), 15 deletions(-) delete mode 100644 hal/mpfs.dtb diff --git a/docs/Targets.md b/docs/Targets.md index 8c42cc41a3..1358796408 100644 --- a/docs/Targets.md +++ b/docs/Targets.md @@ -883,6 +883,7 @@ n n 4 + t 1 4 @@ -920,6 +921,9 @@ Device Start End Sectors Size Type 2) Build, Sign and copy images ```sh +# Copy wolfBoot to "BIOS" partition +sudo dd if=wolfboot.bin of=/dev/sdc1 bs=512 && sudo cmp wolfboot.bin /dev/sdc1 + # make test-app make test-app/image.elf @@ -930,8 +934,22 @@ sudo dd if=test-app/image_v1_signed.bin of=/dev/sdc2 bs=512 && sudo cmp test-app 4) Insert SDCARD into PolarFire and let HSS start wolfBoot. You may need to use `boot sdcard` or configure/build HSS to disable MMC / enable SDCARD. +### PolarFire Building Hart Software Services (HSS) + +The Hart Software Services (HSS) is the zero-stage bootloader for the PolarFire SoC. It runs on the E51 monitor core and is responsible for system initialization, hardware configuration, and booting the U54 application cores. The HSS provides essential services including watchdog management, inter-processor communication (IPC), and loading payloads from various boot sources (eMMC, SD card, or SPI flash). + +```sh +git clone https://github.com/polarfire-soc/hart-software-services.git +cd hart-software-services +make clean +make BOARD=mpfs-video-kit +make BOARD=mpfs-video-kit program +``` + ### PolarFire Building Yocto-SDK Linux +The Yocto Project provides a customizable embedded Linux distribution for PolarFire SoC. Microchip maintains the `meta-mchp` layer with board support packages (BSP), drivers, and example applications for their devices. The build system uses OpenEmbedded and produces bootable images that can be flashed to eMMC or SD card. + See: * https://github.com/linux4microchip/meta-mchp/blob/scarthgap/meta-mchp-common/README.md * https://github.com/linux4microchip/meta-mchp/blob/scarthgap/meta-mchp-polarfire-soc/README.md @@ -958,6 +976,9 @@ Build images are output to: `./tmp-glibc/deploy/images/mpfs-video-kit/` #### Custom FIT image, signing and coping to SDCard ```sh +# Copy wolfBoot to "BIOS" partition +sudo dd if=wolfboot.bin of=/dev/sdc1 bs=512 && sudo cmp wolfboot.bin /dev/sdc1 + # Extract GZIP compressed linux kernel to wolfboot root gzip -cdvk ../yocto-dev-polarfire/build/tmp-glibc/work/mpfs_video_kit-oe-linux/linux-mchp/6.12.22+git/build/linux.bin > kernel.bin @@ -1003,7 +1024,7 @@ sudo dd if=fitImage_v1_signed.bin of=/dev/sdc2 bs=512 status=progress && sudo cm sudo dd if=fitImage_v1_signed.bin of=/dev/sdc3 bs=512 status=progress && sudo cmp fitImage_v1_signed.bin /dev/sdc3 # Copy root file system -sudo dd if=../yocto-dev-polarfire/build/tmp-glibc/deploy/images/mpfs-video-kit/mchp-base-image-sdk-mpfs-video-kit.rootfs.ext4 of=/dev/sdb4 bs=512 status=progress +sudo dd if=../yocto-dev-polarfire/build/tmp-glibc/deploy/images/mpfs-video-kit/mchp-base-image-sdk-mpfs-video-kit.rootfs.ext4 of=/dev/sdc4 bs=4M status=progress ``` ### PolarFire Soc Debugging diff --git a/hal/mpfs.dtb b/hal/mpfs.dtb deleted file mode 100644 index dc4e8bd5c86f0622e466a198310621c4e19e1432..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19897 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 gp`P!WZ4y!?0&f~&XkSZ&Y8BO= 0) { + /* Set bootargs property */ + fdt_fixup_str(fdt, off, "chosen", "bootargs", LINUX_BOOTARGS); + } + + /* TODO: Consider additional FDT fixups: * ethernet0: local-mac-address {0x00, 0x04, 0xA3, SERIAL2, SERIAL1, SERIAL0} */ - (void)dts_addr; + return 0; } void hal_prepare_boot(void) { + /* reset the eMMC/SD card? */ + } @@ -143,22 +181,48 @@ static uint32_t g_rca = 0; /* SD Card Relative Address */ static volatile uint32_t g_mmc_irq_status = 0; static volatile int g_mmc_irq_pending = 0; -/* ============================================================================ - * PLIC - Platform-Level Interrupt Controller Functions - * ============================================================================ */ +/* ========================================================================== + * PHY Register Access Functions + * ========================================================================== */ -/* Get the current hart ID from the tp register (set during boot) */ -static inline uint32_t plic_get_hart_id(void) +/* Write to SD/eMMC PHY register via HRS04 */ +static void mmc_phy_write(uint8_t phy_addr, uint8_t delay_val) { - uint32_t hart_id; - asm volatile("mv %0, tp" : "=r"(hart_id)); - return hart_id; + uint32_t phycfg; + +#ifdef DEBUG_MMC + wolfBoot_printf("mmc_phy_write: phyaddr: 0x%08x, delay_value: %d\n", + phy_addr, delay_val); +#endif + + /* Wait for ACK to clear */ + while ((EMMC_SD_HRS04 & EMMC_SD_HRS04_UIS_ACK) == 0); + + /* Set address and delay value */ + phycfg = ((uint32_t)phy_addr & EMMC_SD_HRS04_UIS_ADDR_MASK) | + ((uint32_t)delay_val << EMMC_SD_HRS04_UIS_WDATA_SHIFT); + EMMC_SD_HRS04 = phycfg; + + /* Send write request */ + EMMC_SD_HRS04 = phycfg | EMMC_SD_HRS04_UIS_WR; + /* Wait for ACK */ + while ((EMMC_SD_HRS04 & EMMC_SD_HRS04_UIS_ACK) == 0); + + /* Clear write request */ + EMMC_SD_HRS04 = phycfg; + EMMC_SD_HRS04 = 0; } +/* ============================================================================ + * PLIC - Platform-Level Interrupt Controller Functions + * ============================================================================ */ + /* Get the PLIC context for the current hart in S-mode */ +extern unsigned long get_boot_hartid(void); static inline uint32_t plic_get_context(void) { - return PLIC_HART_TO_SMODE_CTX(plic_get_hart_id()); + uint32_t hart_id = get_boot_hartid(); + return PLIC_HART_TO_SMODE_CTX(hart_id); } /* Set priority for an interrupt source */ @@ -224,7 +288,7 @@ void plic_init_mmc(void) #ifdef DEBUG_MMC wolfBoot_printf("plic_init_mmc: hart %d, context %d, irq %d enabled\n", - plic_get_hart_id(), plic_get_context(), PLIC_INT_MMC_MAIN); + get_boot_hartid(), plic_get_context(), PLIC_INT_MMC_MAIN); #endif } @@ -895,6 +959,201 @@ int mmc_set_function(uint32_t function_number, uint32_t group_number) return status; } +#ifdef ENABLE_MMC_SD_TUNING +/* ========================================================================== + * SD Tuning Functions (CMD19-based for SDR50/SDR104) + * ========================================================================== */ + +#define EMMC_SD_TUNING_BLOCK_SIZE 64 /* SD tuning block size (bytes) */ +#define EMMC_SD_TUNING_MAX_LOOPS 40 /* Max tuning iterations per spec */ + +/* Send CMD19 tuning block and read 64 bytes. + * Based on HSS read_tune_block() for SD_CMD_19_SEND_TUNING_BLK */ +static int mmc_send_tuning_block(uint32_t *data) +{ + uint32_t cmd_reg, srs12; + int i; + + /* Wait for idle */ + while (EMMC_SD_SRS09 & (EMMC_SD_SRS09_CICMD | EMMC_SD_SRS09_CIDAT)); + + /* Clear all status interrupts */ + EMMC_SD_SRS12 = (EMMC_SD_SRS12_NORM_STAT | EMMC_SD_SRS12_ERR_STAT); + + /* Block length = 64, block count = 1 */ + EMMC_SD_SRS01 = (1 << EMMC_SD_SRS01_BCCT_SHIFT) | EMMC_SD_TUNING_BLOCK_SIZE; + + /* CMD19: Data present, read direction, R1 response */ + cmd_reg = (SD_CMD19_SEND_TUNING << EMMC_SD_SRS03_CIDX_SHIFT) | + EMMC_SD_SRS03_DPS | /* Data Present */ + EMMC_SD_SRS03_DTDS | /* Data Transfer Direction: Read */ + EMMC_SD_SRS03_BCE | /* Block Count Enable */ + EMMC_SD_SRS03_RID | /* Response Interrupt Disable */ + EMMC_SD_SRS03_RECE | /* Response Error Check Enable */ + EMMC_SD_SRS03_RESP_48 | + EMMC_SD_SRS03_CRCCE | + EMMC_SD_SRS03_CICE; + + /* Command argument = 0 for CMD19 */ + EMMC_SD_SRS02 = 0; + EMMC_SD_SRS03 = cmd_reg; + + /* Wait for buffer read ready or error */ + do { + srs12 = EMMC_SD_SRS12; + } while ((srs12 & (EMMC_SD_SRS12_BRR | EMMC_SD_SRS12_EINT)) == 0); + + /* Read data if buffer ready */ + if (srs12 & EMMC_SD_SRS12_BRR) { + for (i = 0; i < (EMMC_SD_TUNING_BLOCK_SIZE / 4); i++) { + data[i] = EMMC_SD_SRS08; + } + } + + /* Check for errors */ + srs12 = EMMC_SD_SRS12; + EMMC_SD_SRS12 = (EMMC_SD_SRS12_NORM_STAT | EMMC_SD_SRS12_ERR_STAT); + + if (srs12 & EMMC_SD_SRS12_ERR_STAT) { + return -1; + } + return 0; +} + +/* Execute SD tuning procedure using CMD19 and Execute Tuning bit. + * Based on HSS sd_tuning() implementation */ +static int mmc_sd_tuning(void) +{ + uint32_t reg; + uint32_t tuning_data[EMMC_SD_TUNING_BLOCK_SIZE / 4]; + int count; + int status = 0; + +#ifdef DEBUG_MMC + wolfBoot_printf("mmc_sd_tuning: starting\n"); +#endif + + reg = EMMC_SD_SRS15; + + /* Reset tuning: clear Sampling Clock Select */ + reg &= ~EMMC_SD_SRS15_SCS; + /* Start tuning: set Execute Tuning */ + reg |= EMMC_SD_SRS15_EXTNG; + EMMC_SD_SRS15 = reg; + + /* Tuning loop - send CMD19 up to 40 times */ + for (count = EMMC_SD_TUNING_MAX_LOOPS; count > 0; count--) { + status = mmc_send_tuning_block(tuning_data); + if (status != 0) { + /* Reset data/cmd lines on failure */ + EMMC_SD_SRS11 |= EMMC_SD_SRS11_RESET_DAT_CMD; + while (EMMC_SD_SRS11 & EMMC_SD_SRS11_RESET_DAT_CMD); + break; + } + + /* Check if Execute Tuning has cleared (hardware completed) */ + reg = EMMC_SD_SRS15; + if ((reg & EMMC_SD_SRS15_EXTNG) == 0) { + break; + } + } + + /* Check result: Sampling Clock Select should be set on success */ + reg = EMMC_SD_SRS15; + if ((reg & EMMC_SD_SRS15_SCS) == 0) { + #ifdef DEBUG_MMC + wolfBoot_printf("mmc_sd_tuning: FAILED (SCS not set)\n"); + #endif + /* Clear Execute Tuning if still set */ + if (reg & EMMC_SD_SRS15_EXTNG) { + EMMC_SD_SRS15 = reg & ~EMMC_SD_SRS15_EXTNG; + } + return -1; + } + +#ifdef DEBUG_MMC + wolfBoot_printf("mmc_sd_tuning: SUCCESS after %d iterations\n", + EMMC_SD_TUNING_MAX_LOOPS - count + 1); +#endif + return 0; +} + +/* PHY training - find optimal delay value by testing reads + * Based on HSS phy_training_mmc() implementation */ +static int mmc_tune(uint8_t phy_addr, uint32_t clk_khz) +{ + int status; + uint8_t delay, max_delay; + uint8_t pos = 0, length = 0, curr_length = 0; + uint32_t tmp_block[EMMC_SD_BLOCK_SIZE / sizeof(uint32_t)]; + + /* Calculate max delay based on clock rate (from HSS) */ + if (clk_khz <= 12500) { + max_delay = 20; + } else { + max_delay = (uint8_t)((200000 / clk_khz) * 2); + } + if (max_delay > 40) { + max_delay = 40; + } + +#ifdef DEBUG_MMC + wolfBoot_printf("mmc_tune: phy_addr=0x%02x, clk=%d kHz, max_delay=%d\n", + phy_addr, clk_khz, max_delay); +#endif + + /* Test each delay value to find longest valid range */ + for (delay = 0; delay < max_delay; delay++) { + mmc_phy_write(phy_addr, delay); + + /* Try a single block read to test this delay setting */ + status = mmc_read(MMC_CMD17_READ_SINGLE, 0, tmp_block, + EMMC_SD_BLOCK_SIZE); + if (status == 0) { + curr_length++; + if (curr_length > length) { + pos = delay - length; + length++; + } + } else { + /* Reset data/cmd lines on failure */ + EMMC_SD_SRS11 |= EMMC_SD_SRS11_RESET_DAT_CMD; + while (EMMC_SD_SRS11 & EMMC_SD_SRS11_RESET_DAT_CMD); + curr_length = 0; + } + } + + /* Set optimal delay (middle of longest valid range) */ + if (length > 0) { + uint8_t new_delay = pos + (length / 2); + mmc_phy_write(phy_addr, new_delay); + #ifdef DEBUG_MMC + wolfBoot_printf("mmc_tune: PHY delay=%d (range: pos=%d, len=%d)\n", + new_delay, pos, length); + #endif + + /* For SDR50/SDR104, also run SD tuning (CMD19) if required. + * Check SRS17 bit 13 (TSDR50) - Tuning for SDR50 required */ + if (EMMC_SD_SRS17 & EMMC_SD_SRS17_TSDR50) { + status = mmc_sd_tuning(); + if (status != 0) { + #ifdef DEBUG_MMC + wolfBoot_printf("mmc_tune: SD tuning failed\n"); + #endif + return status; + } + } + + return 0; + } + +#ifdef DEBUG_MMC + wolfBoot_printf("mmc_tune: FAILED - no valid PHY delay found\n"); +#endif + return -1; +} +#endif /* ENABLE_MMC_SD_TUNING */ + int mmc_init(void) { int status = 0; @@ -1145,7 +1404,16 @@ int mmc_init(void) if (status == 0) { mmc_set_clock(EMMC_SD_CLK_50MHZ); - /* TODO: Phy training at SDR25 (50MHz) */ +#ifdef ENABLE_MMC_SD_TUNING + /* PHY training for SDR25 at 50MHz */ + status = mmc_tune(EMMC_SD_PHY_ADDR_UHSI_SDR25, EMMC_SD_CLK_50MHZ); + if (status != 0) { + #ifdef DEBUG_MMC + wolfBoot_printf("mmc_init: tuning failed, continuing\n"); + #endif + status = 0; /* Don't fail init on tuning failure */ + } +#endif EMMC_SD_SRS13 = irq_restore; /* re-enable interrupt */ } diff --git a/hal/mpfs250.h b/hal/mpfs250.h index a51dc13027..d2055698d9 100644 --- a/hal/mpfs250.h +++ b/hal/mpfs250.h @@ -804,6 +804,7 @@ #define SD_CMD16 16 /* R1 Rsp */ #define MMC_CMD17_READ_SINGLE 17 /* Read single block */ #define MMC_CMD18_READ_MULTIPLE 18 /* Read multiple blocks */ +#define SD_CMD19_SEND_TUNING 19 /* SD: Send 64-byte tuning block */ #define MMC_CMD24_WRITE_SINGLE 24 /* Write single block */ #define MMC_CMD25_WRITE_MULTIPLE 25 /* Write multiple blocks */ diff --git a/src/boot_riscv.c b/src/boot_riscv.c index 44f4400bae..2a7fc4d305 100644 --- a/src/boot_riscv.c +++ b/src/boot_riscv.c @@ -185,7 +185,7 @@ int WEAKFUNCTION hal_dts_fixup(void* dts_addr) #if __riscv_xlen == 64 /* Get the hartid saved by boot_riscv_start.S in the tp register */ -static inline unsigned long get_boot_hartid(void) +unsigned long get_boot_hartid(void) { unsigned long hartid; asm volatile("mv %0, tp" : "=r"(hartid)); From b8fbc3511f7c76ab7328a8ded1e82610b9e447a4 Mon Sep 17 00:00:00 2001 From: David Garske Date: Mon, 29 Dec 2025 15:59:12 -0800 Subject: [PATCH 4/4] Add update_disk encryption support. --- config/examples/polarfire_mpfs250.config | 7 +- docs/Targets.md | 93 +++++- hal/mpfs250.c | 347 ++++++++++++++++++++++- src/update_disk.c | 105 +++++++ 4 files changed, 537 insertions(+), 15 deletions(-) diff --git a/config/examples/polarfire_mpfs250.config b/config/examples/polarfire_mpfs250.config index 142c075ce0..36e3411fea 100644 --- a/config/examples/polarfire_mpfs250.config +++ b/config/examples/polarfire_mpfs250.config @@ -25,9 +25,6 @@ WOLFTPM?=0 ELF?=1 #DEBUG_ELF?=1 -# Optionally allow downgrade to older valid version in update partition -ALLOW_DOWNGRADE?=0 - # Use RISC-V assembly version of ECDSA and SHA NO_ASM?=0 NO_ARM_ASM?=0 @@ -54,6 +51,10 @@ CFLAGS_EXTRA+=-DDISK_BLOCK_SIZE=0x80000 # DTS (Device Tree) WOLFBOOT_LOAD_DTS_ADDRESS?=0x8A000000 +# Optional Encryption +#ENCRYPT=1 +#ENCRYPT_WITH_AES256=1 + # Optional EMMC_SD debugging logs #CFLAGS_EXTRA+=-DDEBUG_MMC # Optional disk debugging logs diff --git a/docs/Targets.md b/docs/Targets.md index 1358796408..e3c5a70cb1 100644 --- a/docs/Targets.md +++ b/docs/Targets.md @@ -1027,6 +1027,48 @@ sudo dd if=fitImage_v1_signed.bin of=/dev/sdc3 bs=512 status=progress && sudo cm sudo dd if=../yocto-dev-polarfire/build/tmp-glibc/deploy/images/mpfs-video-kit/mchp-base-image-sdk-mpfs-video-kit.rootfs.ext4 of=/dev/sdc4 bs=4M status=progress ``` +### PolarFire SoC Encryption + +PolarFire SoC uses MMU mode with disk-based updates. The encryption key is stored in RAM rather than flash. + +Enable encryption in your configuration with `ENCRYPT=1` and one of: `ENCRYPT_WITH_AES256=1`, `ENCRYPT_WITH_AES128=1`, or `ENCRYPT_WITH_CHACHA=1`. + +| Algorithm | Key Size | Nonce/IV Size | +|-----------|----------|---------------| +| ChaCha20 | 32 bytes | 12 bytes | +| AES-128 | 16 bytes | 16 bytes | +| AES-256 | 32 bytes | 16 bytes | + +The `libwolfboot` API provides the following functions for managing the encryption key: + +```c +int wolfBoot_set_encrypt_key(const uint8_t *key, const uint8_t *nonce); +int wolfBoot_get_encrypt_key(uint8_t *key, uint8_t *nonce); +int wolfBoot_erase_encrypt_key(void); /* called automatically by wolfBoot_success() */ +``` + +To sign and encrypt an image, create a key file with the concatenated key and nonce, then use the sign tool: + +```sh +# Create key file (32-byte key + 16-byte IV for AES-256) +echo -n "0123456789abcdef0123456789abcdef0123456789abcdef" > enc_key.der + +# Sign and encrypt +./tools/keytools/sign --ecc384 --sha384 --aes256 --encrypt enc_key.der \ + fitImage wolfboot_signing_private_key.der 1 +``` + +In your application, set the encryption key before triggering an update: + +```c +wolfBoot_set_encrypt_key(enc_key, enc_iv); +wolfBoot_update_trigger(); +``` + +During boot, wolfBoot decrypts the image headers from disk to select the best candidate, loads and decrypts the full image to RAM, then verifies integrity and authenticity before booting. On successful boot, `wolfBoot_success()` clears the key from RAM. + +See the [Encrypted Partitions](encrypted_partitions.md) documentation for additional details. + ### PolarFire Soc Debugging Start GDB server: @@ -1102,10 +1144,59 @@ Booting at 80200000 ... ``` +### PolarFire Benchmarks + +RISC-V 64-bit U54 (RV64GC1) 625 MHz + +``` +------------------------------------------------------------------------------ + wolfSSL version 5.8.4 +------------------------------------------------------------------------------ +Math: Multi-Precision: Wolf(SP) word-size=64 bits=3072 sp_int.c + Assembly Speedups: RISCVASM ALIGN +wolfCrypt Benchmark (block bytes 1048576, min 1.0 sec each) +RNG 5 MiB took 1.232 seconds, 4.058 MiB/s +AES-128-CBC-enc 10 MiB took 1.182 seconds, 8.457 MiB/s +AES-128-CBC-dec 10 MiB took 1.166 seconds, 8.573 MiB/s +AES-192-CBC-enc 10 MiB took 1.378 seconds, 7.257 MiB/s +AES-192-CBC-dec 10 MiB took 1.362 seconds, 7.344 MiB/s +AES-256-CBC-enc 10 MiB took 1.569 seconds, 6.373 MiB/s +AES-256-CBC-dec 10 MiB took 1.556 seconds, 6.426 MiB/s +AES-128-GCM-enc 10 MiB took 1.956 seconds, 5.113 MiB/s +AES-128-GCM-dec 10 MiB took 1.955 seconds, 5.115 MiB/s +AES-192-GCM-enc 5 MiB took 1.075 seconds, 4.650 MiB/s +AES-192-GCM-dec 5 MiB took 1.074 seconds, 4.654 MiB/s +AES-256-GCM-enc 5 MiB took 1.172 seconds, 4.268 MiB/s +AES-256-GCM-dec 5 MiB took 1.170 seconds, 4.275 MiB/s +GMAC Table 4-bit 15 MiB took 1.133 seconds, 13.245 MiB/s +CHACHA 20 MiB took 1.107 seconds, 18.064 MiB/s +CHA-POLY 15 MiB took 1.060 seconds, 14.152 MiB/s +POLY1305 75 MiB took 1.044 seconds, 71.812 MiB/s +SHA 20 MiB took 1.139 seconds, 17.561 MiB/s +SHA-256 10 MiB took 1.069 seconds, 9.350 MiB/s +SHA-384 15 MiB took 1.072 seconds, 13.994 MiB/s +SHA-512 15 MiB took 1.072 seconds, 13.990 MiB/s +SHA-512/224 15 MiB took 1.068 seconds, 14.041 MiB/s +SHA-512/256 15 MiB took 1.066 seconds, 14.070 MiB/s +HMAC-SHA 20 MiB took 1.140 seconds, 17.542 MiB/s +HMAC-SHA256 10 MiB took 1.068 seconds, 9.366 MiB/s +HMAC-SHA384 15 MiB took 1.066 seconds, 14.076 MiB/s +HMAC-SHA512 15 MiB took 1.066 seconds, 14.077 MiB/s +PBKDF2 1 KiB took 1.024 seconds, 1.129 KiB/s +RSA 2048 public 800 ops took 1.142 sec, avg 1.427 ms, 700.575 ops/sec +RSA 2048 private 100 ops took 8.450 sec, avg 84.504 ms, 11.834 ops/sec +DH 2048 key gen 60 ops took 1.010 sec, avg 16.841 ms, 59.379 ops/sec +DH 2048 agree 100 ops took 3.421 sec, avg 34.211 ms, 29.231 ops/sec +ECC [ SECP256R1] 256 key gen 100 ops took 1.304 sec, avg 13.039 ms, 76.691 ops/sec +ECDHE [ SECP256R1] 256 agree 100 ops took 1.299 sec, avg 12.992 ms, 76.970 ops/sec +ECDSA [ SECP256R1] 256 sign 100 ops took 1.338 sec, avg 13.383 ms, 74.723 ops/sec +ECDSA [ SECP256R1] 256 verify 200 ops took 1.846 sec, avg 9.231 ms, 108.333 ops/sec +Benchmark complete +``` + ### PolarFire TODO * Add eMMC/SD features: - - Write support - eMMC support (not just SD) * Add support for reading serial number and modifying ethernet MAC in device tree * Add support for QSPI NOR flash diff --git a/hal/mpfs250.c b/hal/mpfs250.c index d0588f5370..65e7176c11 100644 --- a/hal/mpfs250.c +++ b/hal/mpfs250.c @@ -46,17 +46,24 @@ #include "gpt.h" #include "fdt.h" +#ifdef DISK_TEST +static int disk_test(int drv); +#endif + void hal_init(void) { wolfBoot_printf("wolfBoot Version: %s (%s %s)\n", LIBWOLFBOOT_VERSION_STRING,__DATE__, __TIME__); - } /* Linux kernel command line arguments */ #ifndef LINUX_BOOTARGS +#ifndef LINUX_BOOTARGS_ROOT +#define LINUX_BOOTARGS_ROOT "/dev/mmcblk0p4" +#endif + #define LINUX_BOOTARGS \ - "earlycon root=/dev/mmcblk0p4 rootwait uio_pdrv_genirq.of_id=generic-uio" + "earlycon root="LINUX_BOOTARGS_ROOT" rootwait uio_pdrv_genirq.of_id=generic-uio" #endif int hal_dts_fixup(void* dts_addr) @@ -713,11 +720,16 @@ int mmc_read(uint32_t cmd_index, uint32_t block_addr, uint32_t* dst, #ifdef DEBUG_MMC wolfBoot_printf("mmc_read: cmd_index: %d, block_addr: %08X, dst %p, sz: %d (%d blocks)\n", cmd_index, block_addr, dst, sz, block_count); - wolfBoot_printf("EMMC_SD IN: SRS12: 0x%08X, SRS09: 0x%08X\n", EMMC_SD_SRS12, EMMC_SD_SRS09); #endif /* wait for idle */ status = mmc_wait_busy(0); + if (status != 0) { + #ifdef DEBUG_MMC + wolfBoot_printf("mmc_read: wait busy error\n"); + #endif + return status; + } /* reset data and command lines */ EMMC_SD_SRS11 |= EMMC_SD_SRS11_RESET_DAT_CMD; @@ -839,7 +851,6 @@ int mmc_read(uint32_t cmd_index, uint32_t block_addr, uint32_t* dst, } #ifdef DEBUG_MMC - wolfBoot_printf("EMMC_SD OUT: SRS12: 0x%08X, SRS09: 0x%08X\n", EMMC_SD_SRS12, EMMC_SD_SRS09); wolfBoot_printf("mmc_read: status: %d\n", status); #endif @@ -853,6 +864,176 @@ int mmc_read(uint32_t cmd_index, uint32_t block_addr, uint32_t* dst, return status; } +/* MMC_CMD24_WRITE_SINGLE, MMC_CMD25_WRITE_MULTIPLE */ +int mmc_write(uint32_t cmd_index, uint32_t block_addr, const uint32_t* src, + uint32_t sz) +{ + int status; + uint32_t block_count; + uint32_t reg, cmd_reg; + + /* get block count (round up) */ + block_count = (sz + (EMMC_SD_BLOCK_SIZE - 1)) / EMMC_SD_BLOCK_SIZE; + +#ifdef DEBUG_MMC + wolfBoot_printf("mmc_write: cmd_index: %d, block_addr: %08X, src %p, sz: %d (%d blocks)\n", + cmd_index, block_addr, src, sz, block_count); +#endif + + /* wait for idle */ + status = mmc_wait_busy(0); + if (status != 0) { + #ifdef DEBUG_MMC + wolfBoot_printf("mmc_write: wait busy error\n"); + #endif + return status; + } + + /* reset data and command lines */ + EMMC_SD_SRS11 |= EMMC_SD_SRS11_RESET_DAT_CMD; + + /* wait for command and data line busy to clear */ + while ((EMMC_SD_SRS09 & (EMMC_SD_SRS09_CICMD | EMMC_SD_SRS09_CIDAT)) != 0); + + /* set transfer block count */ + EMMC_SD_SRS01 = (block_count << EMMC_SD_SRS01_BCCT_SHIFT) | sz; + + /* Build command register for write: + * - DTDS=0 for write direction (DTDS=1 is read) + * - DPS=1 data present + * - BCE=1 block count enable + * - RECE=1 response error check enable + * - RID=1 response interrupt disable + */ + cmd_reg = ((cmd_index << EMMC_SD_SRS03_CIDX_SHIFT) | + EMMC_SD_SRS03_DPS | /* Data present, no DTDS = write direction */ + EMMC_SD_SRS03_BCE | EMMC_SD_SRS03_RECE | EMMC_SD_SRS03_RID | + EMMC_SD_SRS03_RESP_48 | EMMC_SD_SRS03_CRCCE | EMMC_SD_SRS03_CICE); + + if (cmd_index == MMC_CMD25_WRITE_MULTIPLE) { + cmd_reg |= EMMC_SD_SRS03_MSBS; /* enable multi-block select */ + + if (sz >= (512 * 1024)) { /* use DMA for large transfers */ + cmd_reg |= EMMC_SD_SRS03_DMAE; /* enable DMA */ + + EMMC_SD_SRS01 = (block_count << EMMC_SD_SRS01_BCCT_SHIFT) | + EMMC_SD_SRS01_DMA_BUFF_512KB | EMMC_SD_BLOCK_SIZE; + + /* SDMA mode (for 32-bit transfers) */ + EMMC_SD_SRS10 |= EMMC_SD_SRS10_DMA_SDMA; + EMMC_SD_SRS15 |= EMMC_SD_SRS15_HV4E; + EMMC_SD_SRS16 &= ~EMMC_SD_SRS16_A64S; + /* set SDMA source address */ + EMMC_SD_SRS22 = (uint32_t)(uintptr_t)src; + EMMC_SD_SRS23 = (uint32_t)(((uint64_t)(uintptr_t)src) >> 32); + + /* Enable SDMA interrupts */ + mmc_enable_sdma_interrupts(); + } + } + + /* wait for cmd/data line not busy */ + while ((EMMC_SD_SRS09 & + (EMMC_SD_SRS09_CICMD | EMMC_SD_SRS09_CIDAT)) != 0); + + EMMC_SD_SRS02 = block_addr; /* cmd argument */ + EMMC_SD_SRS03 = cmd_reg; /* execute command */ + + if (cmd_reg & EMMC_SD_SRS03_DMAE) { + while (1) { /* DMA mode with interrupt support */ + /* Wait for DMA interrupt, transfer complete, or error */ + status = mmc_wait_irq(MMC_IRQ_FLAG_DMAINT | MMC_IRQ_FLAG_TC, + 0x00FFFFFF); + if (status != 0) { + /* Timeout or error */ + wolfBoot_printf("mmc_write: SDMA interrupt timeout/error\n"); + status = -1; /* error */ + break; + } + + /* Check for transfer complete */ + if (g_mmc_irq_status & MMC_IRQ_FLAG_TC) { + g_mmc_irq_status &= ~MMC_IRQ_FLAG_TC; + break; /* Transfer complete */ + } + + /* Check for DMA boundary interrupt - need to update address */ + if (g_mmc_irq_status & MMC_IRQ_FLAG_DMAINT) { + g_mmc_irq_status &= ~MMC_IRQ_FLAG_DMAINT; + /* Read updated DMA address - engine will have incremented */ + src = (const uint32_t*)(uintptr_t)((((uint64_t)EMMC_SD_SRS23) << 32) | + EMMC_SD_SRS22); + /* Set new DMA address for next boundary */ + EMMC_SD_SRS22 = (uint32_t)(uintptr_t)src; + EMMC_SD_SRS23 = (uint32_t)(((uint64_t)(uintptr_t)src) >> 32); + } + } + + /* Disable SDMA interrupts after transfer */ + mmc_disable_sdma_interrupts(); + } + else { + while (sz > 0) { /* blocking mode */ + /* wait for buffer write ready (or error) */ + while (((reg = EMMC_SD_SRS12) & + (EMMC_SD_SRS12_BWR | EMMC_SD_SRS12_EINT)) == 0); + + /* write buffer - write 4 bytes at a time */ + if (reg & EMMC_SD_SRS12_BWR) { + uint32_t i, write_sz = sz; + if (write_sz > EMMC_SD_BLOCK_SIZE) { + write_sz = EMMC_SD_BLOCK_SIZE; + } + for (i=0; i 0) { + block_addr = (start / EMMC_SD_BLOCK_SIZE); + write_sz = count; + if (write_sz > EMMC_SD_BLOCK_SIZE) { + write_sz = EMMC_SD_BLOCK_SIZE; + } + if (write_sz < EMMC_SD_BLOCK_SIZE || /* partial block */ + start_offset != 0 || /* start not block aligned */ + ((uintptr_t)buf % 4) != 0) /* buf not 4-byte aligned */ + { + /* read-modify-write for partial block */ + status = mmc_read(MMC_CMD17_READ_SINGLE, block_addr, + tmp_block, EMMC_SD_BLOCK_SIZE); + if (status == 0) { + uint8_t* tmp_buf = (uint8_t*)tmp_block; + memcpy(tmp_buf + start_offset, buf, write_sz); + status = mmc_write(MMC_CMD24_WRITE_SINGLE, block_addr, + tmp_block, EMMC_SD_BLOCK_SIZE); + start_offset = 0; + } + } + else { + /* direct full block(s) write */ + uint32_t blocks = (count / EMMC_SD_BLOCK_SIZE); + write_sz = (blocks * EMMC_SD_BLOCK_SIZE); + status = mmc_write(blocks > 1 ? + MMC_CMD25_WRITE_MULTIPLE : + MMC_CMD24_WRITE_SINGLE, + block_addr, (const uint32_t*)buf, write_sz); + } + if (status != 0) { + break; + } + + start += write_sz; + buf += write_sz; + count -= write_sz; + } + return status; } int disk_init(int drv) @@ -1491,6 +1716,9 @@ int disk_init(int drv) wolfBoot_printf("Failed to initialize MMC\n"); } (void)drv; +#ifdef DISK_TEST + disk_test(drv); +#endif return r; } @@ -1499,6 +1727,103 @@ void disk_close(int drv) (void)drv; } +#ifdef DISK_TEST +/* Test block address in update partition */ +#ifndef DISK_TEST_BLOCK_ADDR +#define DISK_TEST_BLOCK_ADDR 149504 +#endif + +/* disk_test: Test read/write functionality at update partition + * Tests sizes: 128, 512, 1024, 512KB (524288), 1MB (1048576) bytes + * Uses DDR at WOLFBOOT_LOAD_ADDRESS for test buffer + * Returns 0 on success, negative on failure */ +static int disk_test(int drv) +{ + int status = 0; + int test_num = 0; + uint32_t i; + static const uint32_t test_sizes[] = { + 128, /* partial block */ + 512, /* single block */ + 1024, /* two blocks */ + 512 * 1024, /* 512KB - DMA threshold */ + 1024 * 1024 /* 1MB */ + }; + /* Use DDR memory at WOLFBOOT_LOAD_ADDRESS for test buffer */ + uint32_t* tmp_buf32 = (uint32_t*)WOLFBOOT_LOAD_ADDRESS; + uint8_t* tmp_buf = (uint8_t*)WOLFBOOT_LOAD_ADDRESS; + + wolfBoot_printf("disk_test: Starting tests at block %d (buf @ %p)\n", + DISK_TEST_BLOCK_ADDR, tmp_buf); + + for (test_num = 0; test_num < (int)(sizeof(test_sizes)/sizeof(test_sizes[0])); test_num++) { + uint32_t test_sz = test_sizes[test_num]; + uint64_t test_addr = (uint64_t)DISK_TEST_BLOCK_ADDR * EMMC_SD_BLOCK_SIZE; + uint32_t blocks_needed = (test_sz + EMMC_SD_BLOCK_SIZE - 1) / EMMC_SD_BLOCK_SIZE; + + wolfBoot_printf(" Test %d: size=%u bytes (%u blocks)... ", + test_num + 1, test_sz, blocks_needed); + + /* Fill with test pattern */ + for (i = 0; i < test_sz / sizeof(uint32_t); i++) { + tmp_buf32[i] = (test_num << 24) | i; + } + /* Handle remaining bytes for non-word-aligned sizes */ + for (i = (test_sz / sizeof(uint32_t)) * sizeof(uint32_t); i < test_sz; i++) { + tmp_buf[i] = (uint8_t)((test_num << 4) | (i & 0x0F)); + } + + /* Write */ + status = disk_write(drv, test_addr, test_sz, tmp_buf); + if (status != 0) { + wolfBoot_printf("FAIL (write error %d)\n", status); + continue; + } + + /* Clear buffer */ + memset(tmp_buf, 0, test_sz); + + /* Read back */ + status = disk_read(drv, test_addr, test_sz, tmp_buf); + if (status != 0) { + wolfBoot_printf("FAIL (read error %d)\n", status); + continue; + } + + /* Verify pattern */ + for (i = 0; i < test_sz / sizeof(uint32_t); i++) { + uint32_t expected = (test_num << 24) | i; + if (tmp_buf32[i] != expected) { + wolfBoot_printf("FAIL (verify @ word %u: got 0x%08X, expected 0x%08X)\n", + i, tmp_buf32[i], expected); + status = -1; + break; + } + } + /* Verify remaining bytes for non-word-aligned sizes */ + if (status == 0) { + for (i = (test_sz / sizeof(uint32_t)) * sizeof(uint32_t); i < test_sz; i++) { + uint8_t expected = (uint8_t)((test_num << 4) | (i & 0x0F)); + if (tmp_buf[i] != expected) { + wolfBoot_printf("FAIL (verify @ byte %u: got 0x%02X, expected 0x%02X)\n", + i, tmp_buf[i], expected); + status = -1; + break; + } + } + } + + if (status == 0) { + wolfBoot_printf("PASS\n"); + } + } + + wolfBoot_printf("disk_test: Complete\n"); + return status; +} +#endif /* DISK_TEST */ + + #ifdef DEBUG_UART #ifndef DEBUG_UART_BASE diff --git a/src/update_disk.c b/src/update_disk.c index 056cc1f1ce..dbc832355b 100644 --- a/src/update_disk.c +++ b/src/update_disk.c @@ -47,6 +47,13 @@ #include "elf.h" #endif +/* Disk encryption support for AES-256, AES-128, or ChaCha20 */ +#if defined(ENCRYPT_WITH_AES256) || defined(ENCRYPT_WITH_AES128) || \ + defined(ENCRYPT_WITH_CHACHA) +#define DISK_ENCRYPT +#include "encrypt.h" +#endif + #include #include @@ -83,6 +90,66 @@ #define DISK_BLOCK_SIZE 512 #endif +#ifdef DISK_ENCRYPT +/** + * @brief Decrypt an image header in RAM. + * + * This function decrypts the image header using the configured encryption + * algorithm (AES-256/AES-128 CTR mode or ChaCha20). + * + * @param src Pointer to the encrypted header. + * @param dst Pointer to the destination buffer for decrypted header. + * + * @return 0 if successful, -1 on failure. + */ +static int decrypt_header(const uint8_t *src, uint8_t *dst) +{ + uint32_t i; + uint32_t magic; + + for (i = 0; i < IMAGE_HEADER_SIZE; i += ENCRYPT_BLOCK_SIZE) { + wolfBoot_crypto_set_iv(NULL, i / ENCRYPT_BLOCK_SIZE); + crypto_decrypt(dst + i, src + i, ENCRYPT_BLOCK_SIZE); + } + magic = *((uint32_t*)dst); + if (magic != WOLFBOOT_MAGIC) + return -1; + return 0; +} + +/** + * @brief Decrypt an image in RAM. + * + * This function decrypts the full image (header + firmware) using the + * configured encryption algorithm. The decryption is done in-place. + * + * @param data Pointer to the encrypted image data. + * @param size Size of the image (header + firmware). + * + * @return 0 if successful, -1 on failure. + */ +static int decrypt_image(uint8_t *data, uint32_t size) +{ + uint32_t iv_counter = 0; + uint32_t offset = 0; + uint8_t dec_block[ENCRYPT_BLOCK_SIZE]; + + while (offset < size) { + uint32_t chunk = size - offset; + if (chunk > ENCRYPT_BLOCK_SIZE) + chunk = ENCRYPT_BLOCK_SIZE; + + wolfBoot_crypto_set_iv(NULL, iv_counter); + crypto_decrypt(dec_block, data + offset, chunk); + memcpy(data + offset, dec_block, chunk); + + offset += ENCRYPT_BLOCK_SIZE; + iv_counter++; + } + return 0; +} +#endif /* DISK_ENCRYPT */ + extern int wolfBoot_get_dts_size(void *dts_addr); #if defined(WOLFBOOT_NO_LOAD_ADDRESS) || !defined(WOLFBOOT_LOAD_ADDRESS) @@ -100,6 +167,9 @@ extern uint8_t _end_wb[]; void RAMFUNCTION wolfBoot_start(void) { uint8_t p_hdr[IMAGE_HEADER_SIZE] XALIGNED_STACK(16); +#ifdef DISK_ENCRYPT + uint8_t dec_hdr[IMAGE_HEADER_SIZE] XALIGNED_STACK(16); +#endif #ifdef WOLFBOOT_FSP struct stage2_parameter *stage2_params; #endif @@ -118,6 +188,14 @@ void RAMFUNCTION wolfBoot_start(void) char part_name[4] = {'P', ':', 'X', '\0'}; uint64_t start_us, elapsed_ms; +#ifdef DISK_ENCRYPT + /* Initialize encryption */ + if (wolfBoot_initialize_encryption() != 0) { + wolfBoot_printf("Error initializing encryption\r\n"); + wolfBoot_panic(); + } +#endif + ret = disk_init(BOOT_DISK); if (ret != 0) { wolfBoot_panic(); @@ -132,14 +210,26 @@ void RAMFUNCTION wolfBoot_start(void) BOOT_PART_A); if (disk_part_read(BOOT_DISK, BOOT_PART_A, 0, IMAGE_HEADER_SIZE, p_hdr) == IMAGE_HEADER_SIZE) { +#ifdef DISK_ENCRYPT + if (decrypt_header(p_hdr, dec_hdr) == 0) { + pA_ver = wolfBoot_get_blob_version(dec_hdr); + } +#else pA_ver = wolfBoot_get_blob_version((uint8_t*)p_hdr); +#endif } wolfBoot_printf("Checking secondary OS image in %d,%d...\r\n", BOOT_DISK, BOOT_PART_B); if (disk_part_read(BOOT_DISK, BOOT_PART_B, 0, IMAGE_HEADER_SIZE, p_hdr) == IMAGE_HEADER_SIZE) { +#ifdef DISK_ENCRYPT + if (decrypt_header(p_hdr, dec_hdr) == 0) { + pB_ver = wolfBoot_get_blob_version(dec_hdr); + } +#else pB_ver = wolfBoot_get_blob_version((uint8_t*)p_hdr); +#endif } if ((pB_ver == 0) && (pA_ver == 0)) { @@ -228,6 +318,21 @@ void RAMFUNCTION wolfBoot_start(void) elapsed_ms = (hal_get_timer_us() - start_us) / 1000; wolfBoot_printf("done. (%lu ms)\r\n", (unsigned long)elapsed_ms); +#ifdef DISK_ENCRYPT + /* Decrypt the image in RAM */ + wolfBoot_printf("Decrypting image..."); + start_us = hal_get_timer_us(); + ret = decrypt_image((uint8_t*)load_address, + os_image.fw_size + IMAGE_HEADER_SIZE); + if (ret != 0) { + wolfBoot_printf("Error decrypting image\r\n"); + selected ^= 1; + continue; + } + elapsed_ms = (hal_get_timer_us() - start_us) / 1000; + wolfBoot_printf("done. (%lu ms)\r\n", (unsigned long)elapsed_ms); +#endif + memset(&os_image, 0, sizeof(os_image)); ret = wolfBoot_open_image_address(&os_image, (void*)load_address); if (ret < 0) {