diff --git a/core/arch/arm/kernel/boot.c b/core/arch/arm/kernel/boot.c index 9a132240eb2..e9c83eb7de2 100644 --- a/core/arch/arm/kernel/boot.c +++ b/core/arch/arm/kernel/boot.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -86,6 +87,8 @@ static void *manifest_dt __nex_bss; static uint32_t cntfrq; #endif +static unsigned long transfer_list_pa; + /* May be overridden in plat-$(PLATFORM)/main.c */ __weak void plat_primary_init_early(void) { @@ -1256,14 +1259,55 @@ void __weak boot_init_primary_early(unsigned long pageable_part, unsigned long nsec_entry __maybe_unused) { unsigned long e = PADDR_INVALID; + struct transfer_list_entry *te = NULL; + struct transfer_list_header *tl = NULL; + struct dt_descriptor *dt = get_external_dt_desc(); #if !defined(CFG_WITH_ARM_TRUSTED_FW) e = nsec_entry; #endif + /* When a TL is passed in, pageable_part has been forced to 0 */ + if (IS_ENABLED(CFG_TRANSFER_LIST) && transfer_list_pa && + !pageable_part) { + /* map the TL */ + tl = transfer_list_map(transfer_list_pa); + if (!tl) + panic("Failed to map transfer list"); + dt->tl = tl; /* save the mapped TL */ + + te = transfer_list_find(tl, TL_TAG_OPTEE_PAGABLE_PART); + if (IS_ENABLED(CFG_WITH_PAGER) && te) + pageable_part = get_le64(transfer_list_entry_data(te)); + } init_primary(pageable_part, e); } +#if defined(CFG_TRANSFER_LIST) +/* + * Note: this function is weak just to make it possible to exclude it from + * the unpaged area so that it lies in the init area. + */ +void __weak boot_save_transfer_list(unsigned long transfer_list, + unsigned long fdt) +{ + struct transfer_list_header *tl = (void *)transfer_list; + struct transfer_list_entry *te = NULL; + + if (!IS_ALIGNED(transfer_list, TL_ALIGNMENT_FROM_ORDER(tl->alignment))) + panic("Transfer list base address is not aligned"); + + if (transfer_list_check_header(tl) == TL_OPS_NON) + panic("Invalid transfer list"); + + te = transfer_list_find(tl, TL_TAG_FDT); + if (fdt != (unsigned long)transfer_list_entry_data(te)) + panic("DT does not match to the DT entry of the TL"); + + transfer_list_pa = transfer_list; +} +#endif + #if defined(CFG_WITH_ARM_TRUSTED_FW) unsigned long boot_cpu_on_handler(unsigned long a0 __maybe_unused, unsigned long a1 __unused) diff --git a/core/arch/arm/kernel/entry_a32.S b/core/arch/arm/kernel/entry_a32.S index 2ef44c3d0d8..01bf4d5939d 100644 --- a/core/arch/arm/kernel/entry_a32.S +++ b/core/arch/arm/kernel/entry_a32.S @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -162,6 +163,24 @@ END_FUNC reset_vect_table #endif write_sctlr r0 .endm +#if defined(CFG_TRANSFER_LIST) + /* + * FW Handoff register use: + * entry r0: Zero + * entry r1: TRANSFER_LIST_SIGNATURE | REGISTER_CONVENTION_VERSION_MASK + * entry r2, saved r6: device tree address + * entry r3, saved r10: Transfer list base address + * saved r4, r7: Zero + * entry lr, saved r5: non-secure entry address + */ + .macro bootargs_entry_tl + mov r5, lr /* non-secure entry address */ + mov r4, #0 /* Pagable or TOS FW config address is in TL */ + mov r6, r2 /* Save DT address */ + mov r7, #0 + mov r10, r3 /* Save TL address */ + .endm +#endif #if defined(CFG_CORE_SEL1_SPMC) && defined(CFG_WITH_ARM_TRUSTED_FW) /* @@ -179,6 +198,7 @@ END_FUNC reset_vect_table mov r4, r1 mov r5, #0 mov r7, #0 + mov r10, #0 .endm #else /* @@ -205,6 +225,7 @@ END_FUNC reset_vect_table mov r6, r2 #endif mov r7, r1 + mov r10, #0 .endm #endif @@ -239,8 +260,20 @@ END_FUNC reset_vect_table FUNC _start , : UNWIND( .cantunwind) - +#if defined(CFG_TRANSFER_LIST) + /* check if the TL signature exists */ + ldr r4, =TRANSFER_LIST_SIGNATURE + ldr r5, =REGISTER_CONVENTION_VERSION_MASK + orr r6, r4, r5 + cmp r1, r6 + bne no_tl_sig + /* TL signature exists */ + bootargs_entry_tl + b sav_arg_done +no_tl_sig: /* TL signature does not exist, legacy mode */ +#endif bootargs_entry +sav_arg_done: /* arguments saved */ /* * 32bit entry is expected to execute Supervisor mode, @@ -365,7 +398,7 @@ DECLARE_KEEP_INIT _start LOCAL_FUNC reset_primary , : , .identity_map UNWIND( .cantunwind) - /* preserve r4-r7: bootargs */ + /* preserve r4-r7 and r10: bootargs */ #ifdef CFG_WITH_PAGER /* @@ -390,8 +423,8 @@ UNWIND( .cantunwind) str r0, cached_mem_end ldr r2, =__init_start copy_init: - ldmdb r1!, {r3, r8-r12} - stmdb r0!, {r3, r8-r12} + ldmdb r1!, {r3, r8-r9, r11-r12} + stmdb r0!, {r3, r8-r9, r11-r12} cmp r0, r2 bgt copy_init #else @@ -411,8 +444,8 @@ copy_init: ldr r2, =__end copy_init: - ldmdb r1!, {r3, r8-r12} - stmdb r0!, {r3, r8-r12} + ldmdb r1!, {r3, r8-r9, r11-r12} + stmdb r0!, {r3, r8-r9, r11-r12} cmp r0, r2 bgt copy_init #endif @@ -499,8 +532,18 @@ shadow_stack_access_ok: bl arm_cl2_enable #endif +#if defined(CFG_TRANSFER_LIST) + /* + * Check if the TL header valid and DT matches the TL's DT entry. + * Save the validated TL + */ + mov r0, r10 /* TL address */ + mov r1, r6 /* DT address */ + bl boot_save_transfer_list +#endif + #ifdef CFG_CORE_ASLR - mov r0, r6 + mov r0, r6 /* DT address */ bl get_aslr_seed #else mov r0, #0 diff --git a/core/arch/arm/kernel/entry_a64.S b/core/arch/arm/kernel/entry_a64.S index dd82e7106cb..1937ec87bdd 100644 --- a/core/arch/arm/kernel/entry_a64.S +++ b/core/arch/arm/kernel/entry_a64.S @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -160,19 +161,47 @@ .endm FUNC _start , : +#if defined(CFG_TRANSFER_LIST) /* - * Register use: - * x0 - CFG_CORE_FFA=y && CFG_CORE_SEL2_SPMC=n: - * if non-NULL holds the TOS FW config [1] address - * - CFG_CORE_FFA=y && CFG_CORE_SEL2_SPMC=y: - * address of FF-A Boot Information Blob - * - CFG_CORE_FFA=n: - * if non-NULL holds the pagable part address - * x2 - CFG_CORE_SEL2_SPMC=n: - * if non-NULL holds the system DTB address + * FW Handoff register use: + * x0 - DTB address or 0 + * x1 - TRANSFER_LIST_SIGNATURE | REGISTER_CONVENTION_VERSION_MASK + * x2 - 0 + * x3 - Transfer list base address + * + * x19 - 0 + * x20 - saved x0 + * x23 - saved x3 + */ + /* check if the TL signature exists */ + ldr x19, =TRANSFER_LIST_SIGNATURE + ldr x20, =REGISTER_CONVENTION_VERSION_MASK + orr x23, x19, x20 + cmp x1, x23 + b.ne no_tl_sig + /* Transfer list signature exists */ + mov x19, #0 /* Pagable or TOS FW config address is in TL */ + mov x20, x0 /* Save DT address */ + mov x23, x3 /* Save TL address */ + b sav_arg_done +no_tl_sig: +#endif + /* + * No transfer list signature exist + * + * Case 1: CFG_CORE_FFA=y && CFG_CORE_SEL2_SPMC=n + * x0 - TOS FW config [1] address or 0 + * x2 - DTB address or 0 + * Case 2: CFG_CORE_FFA=y && CFG_CORE_SEL2_SPMC=y + * x0 - Address of FF-A Boot Information Blob + * x2 - 0 + * Case 3: CFG_CORE_FFA=n + * x0 - Pagable part address or 0 + * x2 - DTB address or 0 * * x19 - saved x0 * x20 - saved x2 + * x23 - 0 * * [1] A TF-A concept: TOS_FW_CONFIG - Trusted OS Firmware * configuration file. Used by Trusted OS (BL32), that is, OP-TEE @@ -184,7 +213,9 @@ FUNC _start , : #else mov x20, x2 /* Save DT address */ #endif + mov x23, #0 +sav_arg_done: /* arguments saved */ adr x0, reset_vect_table msr vbar_el1, x0 isb @@ -326,6 +357,16 @@ clear_nex_bss: bl boot_init_memtag #endif +#if defined(CFG_TRANSFER_LIST) + /* + * Check if the TL header valid and DT matches the TL's DT entry. + * Save the validated TL + */ + mov x0, x23 /* TL address */ + mov x1, x20 /* DT address */ + bl boot_save_transfer_list +#endif + #ifdef CFG_CORE_ASLR mov x0, x20 /* DT address */ bl get_aslr_seed diff --git a/core/arch/arm/kernel/link_dummies_init.c b/core/arch/arm/kernel/link_dummies_init.c index 5c90271f785..9a14c314beb 100644 --- a/core/arch/arm/kernel/link_dummies_init.c +++ b/core/arch/arm/kernel/link_dummies_init.c @@ -28,3 +28,11 @@ boot_init_primary_early(unsigned long pageable_part __unused, unsigned long nsec_entry __unused) { } + +#if defined(CFG_TRANSFER_LIST) +void __section(".text.dummy.boot_save_transfer_list") +boot_save_transfer_list(unsigned long transfer_list __unused, + unsigned long fdt __unused) +{ +} +#endif diff --git a/core/include/kernel/boot.h b/core/include/kernel/boot.h index 14025b30cc2..14bd0a39190 100644 --- a/core/include/kernel/boot.h +++ b/core/include/kernel/boot.h @@ -7,6 +7,7 @@ #define __KERNEL_BOOT_H #include +#include #include /* @@ -48,7 +49,10 @@ void boot_init_primary_early(unsigned long pageable_part, void boot_init_primary_late(unsigned long fdt, unsigned long manifest); void boot_init_memtag(void); void boot_save_boot_info(void *boot_info); - +#if defined(CFG_TRANSFER_LIST) +void boot_save_transfer_list(unsigned long transfer_list, + unsigned long fdt); +#endif void __panic_at_smc_return(void) __noreturn; #if defined(CFG_WITH_ARM_TRUSTED_FW) diff --git a/core/include/kernel/dt.h b/core/include/kernel/dt.h index 7a7bd9afdcc..16913c4256c 100644 --- a/core/include/kernel/dt.h +++ b/core/include/kernel/dt.h @@ -83,6 +83,7 @@ struct dt_descriptor { #ifdef _CFG_USE_DTB_OVERLAY int frag_id; #endif + struct transfer_list_header *tl; }; extern uint8_t embedded_secure_dtb[]; diff --git a/core/include/mm/core_mmu.h b/core/include/mm/core_mmu.h index fe9166c0051..7348f75c4d2 100644 --- a/core/include/mm/core_mmu.h +++ b/core/include/mm/core_mmu.h @@ -77,6 +77,7 @@ * MEM_AREA_IO_SEC: Secure HW mapped registers * MEM_AREA_EXT_DT: Memory loads external device tree * MEM_AREA_MANIFEST_DT: Memory loads manifest device tree + * MEM_AREA_TRANSFER_LIST: Memory area mapped for Transfer List * MEM_AREA_RES_VASPACE: Reserved virtual memory space * MEM_AREA_SHM_VASPACE: Virtual memory space for dynamic shared memory buffers * MEM_AREA_TS_VASPACE: TS va space, only used with phys_to_virt() diff --git a/core/kernel/dt.c b/core/kernel/dt.c index 299aba11017..41abc19de31 100644 --- a/core/kernel/dt.c +++ b/core/kernel/dt.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -553,23 +554,35 @@ void init_external_dt(unsigned long phys_dt) if (!IS_ENABLED(CFG_EXTERNAL_DT)) return; - if (!phys_dt) { + if (IS_ENABLED(CFG_TRANSFER_LIST)) + fdt = transfer_list_entry_data(transfer_list_find(dt->tl, + TL_TAG_FDT)); + + if (!fdt) { + if (!phys_dt) { + /* + * No need to panic as we're not using the DT in OP-TEE + * yet, we're only adding some nodes for normal world + * use. + * This makes the switch to using DT easier as we can + * boot a newer OP-TEE with older boot loaders. + * Once we start to initialize devices based on DT + * we'll likely panic instead of returning here. + */ + IMSG("No non-secure external DT"); + return; + } + /* - * No need to panic as we're not using the DT in OP-TEE - * yet, we're only adding some nodes for normal world use. - * This makes the switch to using DT easier as we can boot - * a newer OP-TEE with older boot loaders. Once we start to - * initialize devices based on DT we'll likely panic - * instead of returning here. + * if DTB does not exist in the mapped TL, + * try to map the PA for backwards compatibility */ - IMSG("No non-secure external DT"); - return; + fdt = core_mmu_add_mapping(MEM_AREA_EXT_DT, phys_dt, + CFG_DTB_MAX_SIZE); + if (!fdt) + panic("Failed to map external DTB"); } - fdt = core_mmu_add_mapping(MEM_AREA_EXT_DT, phys_dt, CFG_DTB_MAX_SIZE); - if (!fdt) - panic("Failed to map external DTB"); - dt->blob = fdt; ret = init_dt_overlay(dt, CFG_DTB_MAX_SIZE); @@ -600,6 +613,8 @@ void *get_external_dt(void) static TEE_Result release_external_dt(void) { int ret = 0; + struct transfer_list_header *tl = external_dt.tl; + struct transfer_list_entry *te = NULL; if (!IS_ENABLED(CFG_EXTERNAL_DT)) return TEE_SUCCESS; @@ -614,12 +629,19 @@ static TEE_Result release_external_dt(void) panic(); } - if (core_mmu_remove_mapping(MEM_AREA_EXT_DT, external_dt.blob, - CFG_DTB_MAX_SIZE)) + if (IS_ENABLED(CFG_TRANSFER_LIST) && tl) { + te = transfer_list_find(tl, TL_TAG_FDT); + assert(external_dt.blob == transfer_list_entry_data(te)); + transfer_list_set_data_size(tl, te, + fdt_totalsize(external_dt.blob)); + transfer_list_unmap_sync(tl); + } else if (core_mmu_remove_mapping(MEM_AREA_EXT_DT, external_dt.blob, + CFG_DTB_MAX_SIZE)) { panic("Failed to remove temporary Device Tree mapping"); + } /* External DTB no more reached, reset pointer to invalid */ - external_dt.blob = NULL; + memset(&external_dt, 0, sizeof(external_dt)); return TEE_SUCCESS; }