Skip to content

Commit

Permalink
core: add support for transfer list
Browse files Browse the repository at this point in the history
Add supports for Transfer List on both aarch32/64.
Fetch arguments from {x,r}{0-3} and check if a valid Transfer List
exists, which compliant to the Firmware Handoff specification.
The Transfer List will be mapped during early initialization and
unmapped before exiting to next boot stage.
DTB and pagable address will be parsed from the Transfer List if
they exist as Transfer Entries.
If Transfer List does not exist or is invalid, legacy argument
handoff is backwards compatible.

Signed-off-by: Raymond Mao <raymond.mao@linaro.org>
Reviewed-by: Jens Wiklander <jens.wiklander@linaro.org>
Reviewed-by: Etienne Carriere <etienne.carriere@foss.st.com>
  • Loading branch information
raymo200915 committed Oct 12, 2023
1 parent 3c5304e commit e7bbddd
Show file tree
Hide file tree
Showing 8 changed files with 197 additions and 33 deletions.
44 changes: 44 additions & 0 deletions core/arch/arm/kernel/boot.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include <ffa.h>
#include <initcall.h>
#include <inttypes.h>
#include <io.h>
#include <keep.h>
#include <kernel/asan.h>
#include <kernel/boot.h>
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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)
Expand Down
57 changes: 50 additions & 7 deletions core/arch/arm/kernel/entry_a32.S
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <kernel/asan.h>
#include <kernel/cache_helpers.h>
#include <kernel/thread_private.h>
#include <kernel/transfer_list.h>
#include <mm/core_mmu.h>
#include <platform_config.h>
#include <sm/optee_smc.h>
Expand Down Expand Up @@ -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)
/*
Expand All @@ -179,6 +198,7 @@ END_FUNC reset_vect_table
mov r4, r1
mov r5, #0
mov r7, #0
mov r10, #0
.endm
#else
/*
Expand All @@ -205,6 +225,7 @@ END_FUNC reset_vect_table
mov r6, r2
#endif
mov r7, r1
mov r10, #0
.endm
#endif

Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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
/*
Expand All @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down
59 changes: 50 additions & 9 deletions core/arch/arm/kernel/entry_a64.S
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <generated/asm-defines.h>
#include <keep.h>
#include <kernel/thread_private.h>
#include <kernel/transfer_list.h>
#include <mm/core_mmu.h>
#include <sm/optee_smc.h>
#include <sm/teesmc_opteed.h>
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down
8 changes: 8 additions & 0 deletions core/arch/arm/kernel/link_dummies_init.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
6 changes: 5 additions & 1 deletion core/include/kernel/boot.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#define __KERNEL_BOOT_H

#include <initcall.h>
#include <kernel/transfer_list.h>
#include <types_ext.h>

/*
Expand Down Expand Up @@ -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)
Expand Down
1 change: 1 addition & 0 deletions core/include/kernel/dt.h
Original file line number Diff line number Diff line change
Expand Up @@ -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[];
Expand Down
1 change: 1 addition & 0 deletions core/include/mm/core_mmu.h
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
Loading

0 comments on commit e7bbddd

Please sign in to comment.