Skip to content

Commit ae63f60

Browse files
dgarskedanielinux
authored andcommitted
Fixes for EL2 -> EL1 on boot
1 parent ee3c313 commit ae63f60

6 files changed

Lines changed: 134 additions & 93 deletions

File tree

hal/versal.c

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1208,14 +1208,12 @@ void hal_init(void)
12081208
"========================================\n";
12091209
#endif
12101210

1211-
#ifdef DEBUG_UART
12121211
uart_init();
12131212

12141213
#ifdef __WOLFBOOT
12151214
wolfBoot_printf("%s", banner);
1216-
#endif
12171215
wolfBoot_printf("Current EL: %d\n", current_el());
1218-
#endif /* DEBUG_UART */
1216+
#endif
12191217

12201218
#ifdef EXT_FLASH
12211219
qspi_init();

hal/versal.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,14 @@
5959
/* ARM Errata */
6060
#define CONFIG_ARM_ERRATA_855873 1
6161

62+
/* BL31-applied errata/CVEs (preserve when modifying CPUACTLR):
63+
* - Erratum 859971
64+
* - Erratum 1319367
65+
* - CVE-2017-5715 (Spectre V2)
66+
* - CVE-2018-3639 (SSB)
67+
* - CVE-2022-23960
68+
*/
69+
6270
#endif /* USE_BUILTIN_STARTUP */
6371

6472
/* ============================================================================
@@ -519,7 +527,9 @@
519527
#define GQSPI_DUMMY_READ 8 /* Dummy clocks for Fast/Quad Read */
520528
#endif
521529

530+
#ifndef XALIGNED
522531
#define XALIGNED(x) __attribute__((aligned(x)))
532+
#endif
523533

524534

525535
/* ============================================================================

src/boot_aarch64.c

Lines changed: 9 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,11 @@
2525
#include "loader.h"
2626
#include "wolfboot/wolfboot.h"
2727

28+
/* Include platform-specific header for EL configuration defines */
29+
#ifdef TARGET_versal
30+
#include "hal/versal.h"
31+
#endif
32+
2833
/* Linker exported variables */
2934
extern unsigned int __bss_start__;
3035
extern unsigned int __bss_end__;
@@ -47,12 +52,15 @@ extern void gicv2_init_secure(void);
4752
#define SKIP_GIC_INIT
4853
#endif
4954

55+
#ifndef TARGET_versal
56+
/* current_el() is defined in hal/versal.h for Versal */
5057
unsigned int current_el(void)
5158
{
5259
unsigned long el;
5360
asm volatile("mrs %0, CurrentEL" : "=r" (el) : : "cc");
5461
return (unsigned int)((el >> 2) & 0x3U);
5562
}
63+
#endif
5664

5765
#if defined(BOOT_EL1) && defined(EL2_HYPERVISOR) && EL2_HYPERVISOR == 1
5866
/**
@@ -66,83 +74,7 @@ unsigned int current_el(void)
6674
* @param entry_point Address to jump to in EL1
6775
* @param dts_addr Device tree address (passed in x0 to application)
6876
*/
69-
static void RAMFUNCTION el2_to_el1_boot(uintptr_t entry_point, uintptr_t dts_addr)
70-
{
71-
/* 1. Configure timer access for EL1 */
72-
asm volatile(
73-
"mrs x0, cnthctl_el2\n\t"
74-
"orr x0, x0, #3\n\t" /* EL1PCEN | EL1PCTEN - enable EL1 timer access */
75-
"msr cnthctl_el2, x0\n\t"
76-
"msr cntvoff_el2, xzr" /* Clear virtual timer offset */
77-
::: "x0"
78-
);
79-
80-
/* 2. Configure virtual processor ID */
81-
asm volatile(
82-
"mrs x0, midr_el1\n\t"
83-
"msr vpidr_el2, x0\n\t"
84-
"mrs x0, mpidr_el1\n\t"
85-
"msr vmpidr_el2, x0"
86-
::: "x0"
87-
);
88-
89-
/* 3. Disable coprocessor traps to EL2 */
90-
asm volatile(
91-
"mov x0, #0x33ff\n\t" /* CPTR_EL2: RES1 bits, no traps */
92-
"msr cptr_el2, x0\n\t"
93-
"msr hstr_el2, xzr\n\t" /* No traps to EL2 on system registers */
94-
"mov x0, #(3 << 20)\n\t" /* CPACR_EL1: Full FP/SIMD access */
95-
"msr cpacr_el1, x0"
96-
::: "x0"
97-
);
98-
99-
/* 4. Initialize SCTLR_EL1 with safe defaults (RES1 bits, MMU/cache off) */
100-
asm volatile(
101-
"ldr x0, =0x30d00800\n\t" /* RES1 bits: 29,28,23,22,20,11 */
102-
"msr sctlr_el1, x0"
103-
::: "x0"
104-
);
105-
106-
/* 5. Migrate stack pointer and vector base to EL1 */
107-
asm volatile(
108-
"mov x0, sp\n\t"
109-
"msr sp_el1, x0\n\t"
110-
"mrs x0, vbar_el2\n\t"
111-
"msr vbar_el1, x0"
112-
::: "x0"
113-
);
114-
115-
/* 6. Configure HCR_EL2 - EL1 is AArch64, no hypervisor calls */
116-
asm volatile(
117-
"mov x0, #(1 << 31)\n\t" /* RW: EL1 is AArch64 */
118-
"orr x0, x0, #(1 << 29)\n\t" /* HCD: Disable HVC instruction */
119-
"msr hcr_el2, x0"
120-
::: "x0"
121-
);
122-
123-
/* 7. Set up SPSR_EL2 for return to EL1h with all interrupts masked */
124-
asm volatile(
125-
"mov x0, #0x3c4\n\t" /* DAIF masked (0xF<<6) + M[4:0]=0b00100 (EL1h) */
126-
"msr spsr_el2, x0"
127-
::: "x0"
128-
);
129-
130-
/* 8. Set exception return address and DTB pointer, then ERET */
131-
asm volatile(
132-
"msr elr_el2, %0\n\t" /* Entry point in ELR_EL2 */
133-
"mov x0, %1\n\t" /* DTB address in x0 (first arg) */
134-
"mov x1, xzr\n\t" /* Zero remaining argument registers */
135-
"mov x2, xzr\n\t"
136-
"mov x3, xzr\n\t"
137-
"eret"
138-
:
139-
: "r"(entry_point), "r"(dts_addr)
140-
: "x0", "x1", "x2", "x3"
141-
);
142-
143-
/* Should never reach here */
144-
__builtin_unreachable();
145-
}
77+
extern void el2_to_el1_boot(uintptr_t entry_point, uintptr_t dts_addr);
14678
#endif /* BOOT_EL1 && EL2_HYPERVISOR */
14779

14880
void boot_entry_C(void)

src/boot_aarch64_start.S

Lines changed: 102 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -198,8 +198,11 @@ InitEL3:
198198
orr w1, w1, #(1 << 1) /* Set IRQ bit (IRQs routed to EL3) */
199199
msr SCR_EL3, x1
200200

201-
/* Configure cpu auxiliary control register EL1 */
202-
ldr x0,=0x80CA000 /* L1 Data prefetch control - 5, Enable device split throttle, 2 independent data prefetch streams */
201+
/* Configure CPUACTLR_EL1 - read-modify-write to preserve BL31 workarounds:
202+
* 859971, 1319367, CVE-2017-5715, CVE-2018-3639, CVE-2022-23960 */
203+
mrs x0, S3_1_C15_C2_0 /* Read current CPUACTLR_EL1 */
204+
ldr x1,=0x80CA000 /* L1 Data prefetch control - 5, Enable device split throttle, 2 independent data prefetch streams */
205+
orr x0, x0, x1 /* Merge with existing value */
203206
#if defined(CONFIG_ARM_ERRATA_855873) && CONFIG_ARM_ERRATA_855873
204207
/* Set ENDCCASCI bit in CPUACTLR_EL1 register, to execute data
205208
* cache clean operations as data cache clean and invalidate
@@ -1231,4 +1234,101 @@ gicv2_init_secure:
12311234
1:
12321235
ret
12331236

1237+
#if defined(BOOT_EL1) && defined(EL2_HYPERVISOR) && EL2_HYPERVISOR == 1
1238+
/*
1239+
* Transition from EL2 to EL1 and jump to application
1240+
*
1241+
* Parameters:
1242+
* x0: entry_point - Address to jump to in EL1
1243+
* x1: dts_addr - Device tree address (passed in x0 to application)
1244+
*
1245+
* This function configures the necessary system registers for EL1 operation
1246+
* and performs an exception return (ERET) to drop from EL2 to EL1.
1247+
*
1248+
* Based on ARM Architecture Reference Manual and U-Boot implementation.
1249+
*/
1250+
.global el2_to_el1_boot
1251+
el2_to_el1_boot:
1252+
/* Save parameters - x0=entry_point, x1=dts_addr */
1253+
mov x19, x0 /* Save entry_point in x19 */
1254+
mov x20, x1 /* Save dts_addr in x20 */
1255+
1256+
/* 1. Configure timer access for EL1 */
1257+
mrs x0, CNTHCTL_EL2
1258+
orr x0, x0, #3 /* EL1PCEN | EL1PCTEN - enable EL1 timer access */
1259+
msr CNTHCTL_EL2, x0
1260+
msr CNTVOFF_EL2, xzr /* Clear virtual timer offset */
1261+
1262+
/* 2. Configure virtual processor ID */
1263+
mrs x0, MIDR_EL1
1264+
msr VPIDR_EL2, x0
1265+
mrs x0, MPIDR_EL1
1266+
msr VMPIDR_EL2, x0
1267+
1268+
/* 3. Disable coprocessor traps to EL2 */
1269+
mov x0, #0x33ff /* CPTR_EL2: RES1 bits, no traps */
1270+
msr CPTR_EL2, x0
1271+
msr HSTR_EL2, xzr /* No traps to EL2 on system registers */
1272+
mov x0, #(3 << 20) /* CPACR_EL1: Full FP/SIMD access */
1273+
msr CPACR_EL1, x0
1274+
1275+
/* 4. Initialize SCTLR_EL1 with safe defaults (RES1 bits, MMU/cache off) */
1276+
/* RES1 bits: 29,28,23,22,20,11 = 0x30d00800 */
1277+
movz x0, #0x800
1278+
movk x0, #0x30d0, lsl #16
1279+
msr SCTLR_EL1, x0
1280+
1281+
/* 5. Migrate stack pointer and vector base to EL1 */
1282+
/* SP_EL1 must be 16-byte aligned per ARM spec */
1283+
mov x0, sp
1284+
bic x0, x0, #0xF /* Ensure 16-byte alignment */
1285+
msr SP_EL1, x0
1286+
mrs x0, VBAR_EL2
1287+
msr VBAR_EL1, x0
1288+
dsb sy /* Ensure SP_EL1 and VBAR_EL1 writes complete */
1289+
isb /* Ensure writes take effect */
1290+
1291+
/* 6. Configure HCR_EL2 - EL1 is AArch64, no hypervisor calls */
1292+
/* Check if PAuth (Pointer Authentication) is supported */
1293+
mrs x0, ID_AA64ISAR1_EL1 /* Read ISA feature register */
1294+
mov x1, #(0xF << 28) /* GPI mask */
1295+
orr x1, x1, #(0xF << 24) /* GPA mask */
1296+
orr x1, x1, #(0xF << 8) /* API mask */
1297+
orr x1, x1, #(0xF << 4) /* APA mask */
1298+
tst x0, x1 /* Test if PAuth supported (Z=1 if not supported) */
1299+
mov x0, #(1 << 31) /* RW: EL1 is AArch64 */
1300+
orr x0, x0, #(1 << 29) /* HCD: Disable HVC instruction */
1301+
mov x1, x0 /* Copy base value */
1302+
orr x1, x1, #(1 << 41) /* API: Trap PAuth instructions */
1303+
orr x1, x1, #(1 << 40) /* APK: Trap PAuth key access */
1304+
csel x0, x0, x1, eq /* If PAuth not supported (eq), use x0 (base), else x1 (with traps) */
1305+
msr HCR_EL2, x0
1306+
dsb sy /* Ensure HCR_EL2 write completes */
1307+
isb /* Ensure HCR_EL2 takes effect */
1308+
1309+
/* 7. Set up SPSR_EL2 for return to EL1h with all interrupts masked */
1310+
/* M[3:0] = 0101 = EL1h (EL1 with SP_EL1) - NOT 0100 which is EL1t! */
1311+
/* M[4] = 0 = AArch64 mode (bit 4 must be 0 for AArch64, 1 for AArch32) */
1312+
/* DAIF = 0xF = all interrupts masked */
1313+
/* Value: 0x3C5 = (0xF << 6) | 0x5 */
1314+
movz x0, #0x3C5 /* DAIF=0xF (bits 9:6), M[3:0]=0x5 (EL1h) */
1315+
msr SPSR_EL2, x0
1316+
dsb sy /* Ensure SPSR_EL2 write completes */
1317+
isb /* Ensure SPSR_EL2 takes effect */
1318+
1319+
/* 8. Set exception return address and DTB pointer, then ERET */
1320+
/* Critical: All register writes must complete before eret */
1321+
msr ELR_EL2, x19 /* Entry point in ELR_EL2 */
1322+
mov x0, x20 /* DTB address in x0 (first arg) */
1323+
mov x1, xzr /* Zero remaining argument registers */
1324+
mov x2, xzr
1325+
mov x3, xzr
1326+
dsb sy /* Ensure all writes complete */
1327+
isb /* Ensure all effects are visible */
1328+
eret /* Exception return to EL1 */
1329+
1330+
/* Should never reach here */
1331+
b .
1332+
#endif /* BOOT_EL1 && EL2_HYPERVISOR */
1333+
12341334
.end

test-app/app_versal.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ void main(void)
3232
{
3333
uint32_t boot_version, update_version;
3434

35-
/* Initialize HAL (UART, etc.) */
3635
hal_init();
3736

3837
/* Get versions from both partitions */
@@ -44,9 +43,11 @@ void main(void)
4443
wolfBoot_printf(" wolfBoot Test Application - AMD Versal\n");
4544
wolfBoot_printf("===========================================\n\n");
4645

46+
wolfBoot_printf("Current EL: %d\n", current_el());
47+
4748
/* Print firmware versions */
48-
wolfBoot_printf("Boot Partition Version: %d (0x%08x)\n", boot_version, boot_version);
49-
wolfBoot_printf("Update Partition Version: %d (0x%08x)\n", update_version, update_version);
49+
wolfBoot_printf("BOOT: Version: %d (0x%08x)\n", boot_version, boot_version);
50+
wolfBoot_printf("UPDATE: Version: %d (0x%08x)\n", update_version, update_version);
5051

5152
wolfBoot_printf("Application running successfully!\n");
5253
wolfBoot_printf("\nEntering idle loop...\n");

tools/scripts/versal_test.sh

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -331,7 +331,10 @@ esac
331331
# Build wolfBoot
332332
log_info "Building wolfBoot..."
333333
cp config/examples/versal_vmk180.config .config
334-
make clean && make
334+
335+
make clean
336+
make || { log_error "Failed to build wolfBoot"; exit 1; }
337+
[ ! -f "wolfboot.elf" ] && { log_error "wolfboot.elf not found after build"; exit 1; }
335338

336339
# Build test app if requested
337340
if [ "$FLASH_TEST_APP" = "true" ]; then
@@ -396,6 +399,7 @@ fi
396399

397400
# Generate BOOT.BIN
398401
log_info "Generating BOOT.BIN..."
402+
[ ! -f "wolfboot.elf" ] && { log_error "wolfboot.elf not found - cannot generate BOOT.BIN"; exit 1; }
399403

400404
# Set PREBUILT_DIR (relative to wolfBoot root)
401405
export PREBUILT_DIR="${WOLFBOOT_ROOT}/../soc-prebuilt-firmware/vmk180-versal"
@@ -414,16 +418,12 @@ cp "${PREBUILT_DIR}/psmfw.elf" .
414418
cp "${PREBUILT_DIR}/bl31.elf" .
415419
cp "${PREBUILT_DIR}/system-default.dtb" .
416420

417-
# Generate BOOT.BIN from wolfBoot root directory
418421
source "${VITIS_PATH}/settings64.sh"
419-
bootgen -arch versal -image ./tools/scripts/versal_boot.bif -w -o BOOT.BIN
420-
421-
# Copy BOOT.BIN to TFTP directory
422-
cp BOOT.BIN "${TFTP_DIR}/"
423-
422+
rm -f BOOT.BIN
423+
bootgen -arch versal -image ./tools/scripts/versal_boot.bif -w -o BOOT.BIN || { log_error "bootgen failed"; exit 1; }
424+
cp BOOT.BIN "${TFTP_DIR}/" || { log_error "Failed to copy BOOT.BIN to TFTP directory"; exit 1; }
424425
filesize=$(stat -c%s "${TFTP_DIR}/BOOT.BIN")
425426
filesize_hex=$(printf "0x%x" $filesize)
426-
log_info "BOOT.BIN size: $filesize bytes"
427427

428428
# Get test app size if flashing it
429429
testapp_size_hex="0x0"

0 commit comments

Comments
 (0)