diff --git a/hal/versal.c b/hal/versal.c index 7c4f0fa1..7293138e 100644 --- a/hal/versal.c +++ b/hal/versal.c @@ -1208,14 +1208,12 @@ void hal_init(void) "========================================\n"; #endif -#ifdef DEBUG_UART uart_init(); #ifdef __WOLFBOOT wolfBoot_printf("%s", banner); -#endif wolfBoot_printf("Current EL: %d\n", current_el()); -#endif /* DEBUG_UART */ +#endif #ifdef EXT_FLASH qspi_init(); diff --git a/hal/versal.h b/hal/versal.h index a927dccf..75b10409 100644 --- a/hal/versal.h +++ b/hal/versal.h @@ -59,6 +59,14 @@ /* ARM Errata */ #define CONFIG_ARM_ERRATA_855873 1 +/* BL31-applied errata/CVEs (preserve when modifying CPUACTLR): + * - Erratum 859971 + * - Erratum 1319367 + * - CVE-2017-5715 (Spectre V2) + * - CVE-2018-3639 (SSB) + * - CVE-2022-23960 + */ + #endif /* USE_BUILTIN_STARTUP */ /* ============================================================================ @@ -519,7 +527,9 @@ #define GQSPI_DUMMY_READ 8 /* Dummy clocks for Fast/Quad Read */ #endif +#ifndef XALIGNED #define XALIGNED(x) __attribute__((aligned(x))) +#endif /* ============================================================================ diff --git a/src/boot_aarch64.c b/src/boot_aarch64.c index fce0081b..3fa21c9b 100644 --- a/src/boot_aarch64.c +++ b/src/boot_aarch64.c @@ -25,6 +25,11 @@ #include "loader.h" #include "wolfboot/wolfboot.h" +/* Include platform-specific header for EL configuration defines */ +#ifdef TARGET_versal +#include "hal/versal.h" +#endif + /* Linker exported variables */ extern unsigned int __bss_start__; extern unsigned int __bss_end__; @@ -47,12 +52,15 @@ extern void gicv2_init_secure(void); #define SKIP_GIC_INIT #endif +#ifndef TARGET_versal +/* current_el() is defined in hal/versal.h for Versal */ unsigned int current_el(void) { unsigned long el; asm volatile("mrs %0, CurrentEL" : "=r" (el) : : "cc"); return (unsigned int)((el >> 2) & 0x3U); } +#endif #if defined(BOOT_EL1) && defined(EL2_HYPERVISOR) && EL2_HYPERVISOR == 1 /** @@ -66,83 +74,7 @@ unsigned int current_el(void) * @param entry_point Address to jump to in EL1 * @param dts_addr Device tree address (passed in x0 to application) */ -static void RAMFUNCTION el2_to_el1_boot(uintptr_t entry_point, uintptr_t dts_addr) -{ - /* 1. Configure timer access for EL1 */ - asm volatile( - "mrs x0, cnthctl_el2\n\t" - "orr x0, x0, #3\n\t" /* EL1PCEN | EL1PCTEN - enable EL1 timer access */ - "msr cnthctl_el2, x0\n\t" - "msr cntvoff_el2, xzr" /* Clear virtual timer offset */ - ::: "x0" - ); - - /* 2. Configure virtual processor ID */ - asm volatile( - "mrs x0, midr_el1\n\t" - "msr vpidr_el2, x0\n\t" - "mrs x0, mpidr_el1\n\t" - "msr vmpidr_el2, x0" - ::: "x0" - ); - - /* 3. Disable coprocessor traps to EL2 */ - asm volatile( - "mov x0, #0x33ff\n\t" /* CPTR_EL2: RES1 bits, no traps */ - "msr cptr_el2, x0\n\t" - "msr hstr_el2, xzr\n\t" /* No traps to EL2 on system registers */ - "mov x0, #(3 << 20)\n\t" /* CPACR_EL1: Full FP/SIMD access */ - "msr cpacr_el1, x0" - ::: "x0" - ); - - /* 4. Initialize SCTLR_EL1 with safe defaults (RES1 bits, MMU/cache off) */ - asm volatile( - "ldr x0, =0x30d00800\n\t" /* RES1 bits: 29,28,23,22,20,11 */ - "msr sctlr_el1, x0" - ::: "x0" - ); - - /* 5. Migrate stack pointer and vector base to EL1 */ - asm volatile( - "mov x0, sp\n\t" - "msr sp_el1, x0\n\t" - "mrs x0, vbar_el2\n\t" - "msr vbar_el1, x0" - ::: "x0" - ); - - /* 6. Configure HCR_EL2 - EL1 is AArch64, no hypervisor calls */ - asm volatile( - "mov x0, #(1 << 31)\n\t" /* RW: EL1 is AArch64 */ - "orr x0, x0, #(1 << 29)\n\t" /* HCD: Disable HVC instruction */ - "msr hcr_el2, x0" - ::: "x0" - ); - - /* 7. Set up SPSR_EL2 for return to EL1h with all interrupts masked */ - asm volatile( - "mov x0, #0x3c4\n\t" /* DAIF masked (0xF<<6) + M[4:0]=0b00100 (EL1h) */ - "msr spsr_el2, x0" - ::: "x0" - ); - - /* 8. Set exception return address and DTB pointer, then ERET */ - asm volatile( - "msr elr_el2, %0\n\t" /* Entry point in ELR_EL2 */ - "mov x0, %1\n\t" /* DTB address in x0 (first arg) */ - "mov x1, xzr\n\t" /* Zero remaining argument registers */ - "mov x2, xzr\n\t" - "mov x3, xzr\n\t" - "eret" - : - : "r"(entry_point), "r"(dts_addr) - : "x0", "x1", "x2", "x3" - ); - - /* Should never reach here */ - __builtin_unreachable(); -} +extern void el2_to_el1_boot(uintptr_t entry_point, uintptr_t dts_addr); #endif /* BOOT_EL1 && EL2_HYPERVISOR */ void boot_entry_C(void) diff --git a/src/boot_aarch64_start.S b/src/boot_aarch64_start.S index eb0c2325..169e4e92 100644 --- a/src/boot_aarch64_start.S +++ b/src/boot_aarch64_start.S @@ -198,8 +198,11 @@ InitEL3: orr w1, w1, #(1 << 1) /* Set IRQ bit (IRQs routed to EL3) */ msr SCR_EL3, x1 - /* Configure cpu auxiliary control register EL1 */ - ldr x0,=0x80CA000 /* L1 Data prefetch control - 5, Enable device split throttle, 2 independent data prefetch streams */ + /* Configure CPUACTLR_EL1 - read-modify-write to preserve BL31 workarounds: + * 859971, 1319367, CVE-2017-5715, CVE-2018-3639, CVE-2022-23960 */ + mrs x0, S3_1_C15_C2_0 /* Read current CPUACTLR_EL1 */ + ldr x1,=0x80CA000 /* L1 Data prefetch control - 5, Enable device split throttle, 2 independent data prefetch streams */ + orr x0, x0, x1 /* Merge with existing value */ #if defined(CONFIG_ARM_ERRATA_855873) && CONFIG_ARM_ERRATA_855873 /* Set ENDCCASCI bit in CPUACTLR_EL1 register, to execute data * cache clean operations as data cache clean and invalidate @@ -1231,4 +1234,101 @@ gicv2_init_secure: 1: ret +#if defined(BOOT_EL1) && defined(EL2_HYPERVISOR) && EL2_HYPERVISOR == 1 +/* + * Transition from EL2 to EL1 and jump to application + * + * Parameters: + * x0: entry_point - Address to jump to in EL1 + * x1: dts_addr - Device tree address (passed in x0 to application) + * + * This function configures the necessary system registers for EL1 operation + * and performs an exception return (ERET) to drop from EL2 to EL1. + * + * Based on ARM Architecture Reference Manual and U-Boot implementation. + */ +.global el2_to_el1_boot +el2_to_el1_boot: + /* Save parameters - x0=entry_point, x1=dts_addr */ + mov x19, x0 /* Save entry_point in x19 */ + mov x20, x1 /* Save dts_addr in x20 */ + + /* 1. Configure timer access for EL1 */ + mrs x0, CNTHCTL_EL2 + orr x0, x0, #3 /* EL1PCEN | EL1PCTEN - enable EL1 timer access */ + msr CNTHCTL_EL2, x0 + msr CNTVOFF_EL2, xzr /* Clear virtual timer offset */ + + /* 2. Configure virtual processor ID */ + mrs x0, MIDR_EL1 + msr VPIDR_EL2, x0 + mrs x0, MPIDR_EL1 + msr VMPIDR_EL2, x0 + + /* 3. Disable coprocessor traps to EL2 */ + mov x0, #0x33ff /* CPTR_EL2: RES1 bits, no traps */ + msr CPTR_EL2, x0 + msr HSTR_EL2, xzr /* No traps to EL2 on system registers */ + mov x0, #(3 << 20) /* CPACR_EL1: Full FP/SIMD access */ + msr CPACR_EL1, x0 + + /* 4. Initialize SCTLR_EL1 with safe defaults (RES1 bits, MMU/cache off) */ + /* RES1 bits: 29,28,23,22,20,11 = 0x30d00800 */ + movz x0, #0x800 + movk x0, #0x30d0, lsl #16 + msr SCTLR_EL1, x0 + + /* 5. Migrate stack pointer and vector base to EL1 */ + /* SP_EL1 must be 16-byte aligned per ARM spec */ + mov x0, sp + bic x0, x0, #0xF /* Ensure 16-byte alignment */ + msr SP_EL1, x0 + mrs x0, VBAR_EL2 + msr VBAR_EL1, x0 + dsb sy /* Ensure SP_EL1 and VBAR_EL1 writes complete */ + isb /* Ensure writes take effect */ + + /* 6. Configure HCR_EL2 - EL1 is AArch64, no hypervisor calls */ + /* Check if PAuth (Pointer Authentication) is supported */ + mrs x0, ID_AA64ISAR1_EL1 /* Read ISA feature register */ + mov x1, #(0xF << 28) /* GPI mask */ + orr x1, x1, #(0xF << 24) /* GPA mask */ + orr x1, x1, #(0xF << 8) /* API mask */ + orr x1, x1, #(0xF << 4) /* APA mask */ + tst x0, x1 /* Test if PAuth supported (Z=1 if not supported) */ + mov x0, #(1 << 31) /* RW: EL1 is AArch64 */ + orr x0, x0, #(1 << 29) /* HCD: Disable HVC instruction */ + mov x1, x0 /* Copy base value */ + orr x1, x1, #(1 << 41) /* API: Trap PAuth instructions */ + orr x1, x1, #(1 << 40) /* APK: Trap PAuth key access */ + csel x0, x0, x1, eq /* If PAuth not supported (eq), use x0 (base), else x1 (with traps) */ + msr HCR_EL2, x0 + dsb sy /* Ensure HCR_EL2 write completes */ + isb /* Ensure HCR_EL2 takes effect */ + + /* 7. Set up SPSR_EL2 for return to EL1h with all interrupts masked */ + /* M[3:0] = 0101 = EL1h (EL1 with SP_EL1) - NOT 0100 which is EL1t! */ + /* M[4] = 0 = AArch64 mode (bit 4 must be 0 for AArch64, 1 for AArch32) */ + /* DAIF = 0xF = all interrupts masked */ + /* Value: 0x3C5 = (0xF << 6) | 0x5 */ + movz x0, #0x3C5 /* DAIF=0xF (bits 9:6), M[3:0]=0x5 (EL1h) */ + msr SPSR_EL2, x0 + dsb sy /* Ensure SPSR_EL2 write completes */ + isb /* Ensure SPSR_EL2 takes effect */ + + /* 8. Set exception return address and DTB pointer, then ERET */ + /* Critical: All register writes must complete before eret */ + msr ELR_EL2, x19 /* Entry point in ELR_EL2 */ + mov x0, x20 /* DTB address in x0 (first arg) */ + mov x1, xzr /* Zero remaining argument registers */ + mov x2, xzr + mov x3, xzr + dsb sy /* Ensure all writes complete */ + isb /* Ensure all effects are visible */ + eret /* Exception return to EL1 */ + + /* Should never reach here */ + b . +#endif /* BOOT_EL1 && EL2_HYPERVISOR */ + .end diff --git a/test-app/app_versal.c b/test-app/app_versal.c index 935dfa26..c7bee8e1 100644 --- a/test-app/app_versal.c +++ b/test-app/app_versal.c @@ -32,7 +32,6 @@ void main(void) { uint32_t boot_version, update_version; - /* Initialize HAL (UART, etc.) */ hal_init(); /* Get versions from both partitions */ @@ -44,9 +43,11 @@ void main(void) wolfBoot_printf(" wolfBoot Test Application - AMD Versal\n"); wolfBoot_printf("===========================================\n\n"); + wolfBoot_printf("Current EL: %d\n", current_el()); + /* Print firmware versions */ - wolfBoot_printf("Boot Partition Version: %d (0x%08x)\n", boot_version, boot_version); - wolfBoot_printf("Update Partition Version: %d (0x%08x)\n", update_version, update_version); + wolfBoot_printf("BOOT: Version: %d (0x%08x)\n", boot_version, boot_version); + wolfBoot_printf("UPDATE: Version: %d (0x%08x)\n", update_version, update_version); wolfBoot_printf("Application running successfully!\n"); wolfBoot_printf("\nEntering idle loop...\n"); diff --git a/tools/scripts/versal_test.sh b/tools/scripts/versal_test.sh index 4d63b4fb..ba24cfe6 100755 --- a/tools/scripts/versal_test.sh +++ b/tools/scripts/versal_test.sh @@ -331,7 +331,10 @@ esac # Build wolfBoot log_info "Building wolfBoot..." cp config/examples/versal_vmk180.config .config -make clean && make + +make clean +make || { log_error "Failed to build wolfBoot"; exit 1; } +[ ! -f "wolfboot.elf" ] && { log_error "wolfboot.elf not found after build"; exit 1; } # Build test app if requested if [ "$FLASH_TEST_APP" = "true" ]; then @@ -396,6 +399,7 @@ fi # Generate BOOT.BIN log_info "Generating BOOT.BIN..." +[ ! -f "wolfboot.elf" ] && { log_error "wolfboot.elf not found - cannot generate BOOT.BIN"; exit 1; } # Set PREBUILT_DIR (relative to wolfBoot root) export PREBUILT_DIR="${WOLFBOOT_ROOT}/../soc-prebuilt-firmware/vmk180-versal" @@ -414,16 +418,12 @@ cp "${PREBUILT_DIR}/psmfw.elf" . cp "${PREBUILT_DIR}/bl31.elf" . cp "${PREBUILT_DIR}/system-default.dtb" . -# Generate BOOT.BIN from wolfBoot root directory source "${VITIS_PATH}/settings64.sh" -bootgen -arch versal -image ./tools/scripts/versal_boot.bif -w -o BOOT.BIN - -# Copy BOOT.BIN to TFTP directory -cp BOOT.BIN "${TFTP_DIR}/" - +rm -f BOOT.BIN +bootgen -arch versal -image ./tools/scripts/versal_boot.bif -w -o BOOT.BIN || { log_error "bootgen failed"; exit 1; } +cp BOOT.BIN "${TFTP_DIR}/" || { log_error "Failed to copy BOOT.BIN to TFTP directory"; exit 1; } filesize=$(stat -c%s "${TFTP_DIR}/BOOT.BIN") filesize_hex=$(printf "0x%x" $filesize) -log_info "BOOT.BIN size: $filesize bytes" # Get test app size if flashing it testapp_size_hex="0x0"