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>
  • Loading branch information
raymo200915 committed Sep 26, 2023
1 parent 0f86273 commit cb0a351
Show file tree
Hide file tree
Showing 8 changed files with 182 additions and 31 deletions.
33 changes: 30 additions & 3 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 @@ -1253,13 +1254,30 @@ static void init_secondary_helper(unsigned long nsec_entry)
* the unpaged area so that it lies in the init area.
*/
void __weak boot_init_primary_early(unsigned long pageable_part,
unsigned long nsec_entry __maybe_unused)
unsigned long nsec_entry __maybe_unused,
unsigned long transfer_list)
{
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
if (IS_ENABLED(CFG_TRANSFER_LIST) && transfer_list) {
/* map the TL */
tl = transfer_list_map(transfer_list);
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) && !pageable_part && te) {
pageable_part = get_le64(transfer_list_entry_data(te));
transfer_list_rem(tl, te);
}
}

init_primary(pageable_part, e);
}
Expand Down Expand Up @@ -1321,7 +1339,7 @@ struct ns_entry_context *boot_core_hpen(void)

#if defined(CFG_CORE_ASLR)
#if defined(CFG_DT)
unsigned long __weak get_aslr_seed(void *fdt)
unsigned long __weak get_aslr_seed(void *fdt, struct transfer_list_header *tl)
{
int rc = 0;
const uint64_t *seed = NULL;
Expand All @@ -1333,6 +1351,14 @@ unsigned long __weak get_aslr_seed(void *fdt)
goto err;
}

if (tl && IS_ENABLED(CFG_TRANSFER_LIST)) {
if (fdt != transfer_list_entry_data
(transfer_list_find(tl, TL_TAG_FDT))) {
EMSG("fdt does not match to the fdt entry of the TL");
goto err;
}
}

rc = fdt_check_header(fdt);
if (rc) {
DMSG("Bad fdt: %d", rc);
Expand All @@ -1357,7 +1383,8 @@ unsigned long __weak get_aslr_seed(void *fdt)
return plat_get_aslr_seed();
}
#else /*!CFG_DT*/
unsigned long __weak get_aslr_seed(void *fdt __unused)
unsigned long __weak get_aslr_seed(void *fdt __unused,
struct transfer_list_header *tl __unused)
{
/* Try platform implementation */
return plat_get_aslr_seed();
Expand Down
61 changes: 54 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,20 @@ shadow_stack_access_ok:
bl arm_cl2_enable
#endif

#if defined(CFG_TRANSFER_LIST)
/* check if the TL header valid */
mov r0, r10
bl transfer_list_check_header
ldr r1, =TL_OPS_NON
cmp r0, r1
bne tl_valid
mov r10, #0 /* clean the address if TL is invalid */
tl_valid:
#endif

#ifdef CFG_CORE_ASLR
mov r0, r6
mov r0, r6 /* DT address */
mov r1, r10 /* TL address */
bl get_aslr_seed
#else
mov r0, #0
Expand Down Expand Up @@ -549,6 +594,7 @@ shadow_stack_access_ok:

mov r0, r4 /* pageable part address */
mov r1, r5 /* ns-entry address */
mov r2, r10 /* TL address */
bl boot_init_primary_early
#ifndef CFG_NS_VIRTUALIZATION
mov r9, sp
Expand All @@ -562,6 +608,7 @@ shadow_stack_access_ok:
#endif
mov r0, r6 /* DT address */
mov r1, #0 /* unused */
/* PA of TL is not needed as it is already mapped */
bl boot_init_primary_late
#ifndef CFG_NS_VIRTUALIZATION
mov r0, #THREAD_CLF_TMP
Expand Down
46 changes: 45 additions & 1 deletion 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,8 +161,28 @@
.endm

FUNC _start , :
#if defined(CFG_TRANSFER_LIST)
/*
* Register use:
* 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.eq tl_sig_exist
#endif
/* Transfer list signature does not exist, legacy mode
*
* Legacy 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:
Expand All @@ -173,6 +194,7 @@ FUNC _start , :
*
* 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 +206,15 @@ FUNC _start , :
#else
mov x20, x2 /* Save DT address */
#endif
mov x23, #0
b sav_arg_done

tl_sig_exist: /* 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 */

sav_arg_done: /* arguments saved */
adr x0, reset_vect_table
msr vbar_el1, x0
isb
Expand Down Expand Up @@ -326,8 +356,20 @@ clear_nex_bss:
bl boot_init_memtag
#endif

#if defined(CFG_TRANSFER_LIST)
/* check if the TL header valid */
mov x0, x23
bl transfer_list_check_header
ldr x1, =TL_OPS_NON
cmp x0, x1
b.ne tl_valid
mov x23, #0 /* clean the address if TL is invalid */
tl_valid:
#endif

#ifdef CFG_CORE_ASLR
mov x0, x20 /* DT address */
mov x1, x23 /* TL address */
bl get_aslr_seed
#else
mov x0, #0
Expand Down Expand Up @@ -382,6 +424,7 @@ clear_nex_bss:
mov x0, x19 /* pagable part address */
#endif
mov x1, #-1
mov x2, x23 /* TL address */
bl boot_init_primary_early

#ifdef CFG_MEMTAG
Expand All @@ -403,6 +446,7 @@ clear_nex_bss:
#else
mov x1, xzr /* unused */
#endif
/* PA of TL is not needed as it is already mapped */
bl boot_init_primary_late
#ifdef CFG_CORE_PAUTH
init_pauth_per_cpu
Expand Down
5 changes: 3 additions & 2 deletions core/arch/arm/kernel/link_dummies_init.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ boot_save_boot_info(void *boot_info __unused)
}

unsigned long __section(".text.dummy.get_aslr_seed")
get_aslr_seed(void *fdt __unused)
get_aslr_seed(void *fdt __unused, struct transfer_list_header *tl __unused)
{
return 0;
}
Expand All @@ -25,6 +25,7 @@ core_init_mmu_map(unsigned long seed __unused,

void __section(".text.dummy.boot_init_primary_early")
boot_init_primary_early(unsigned long pageable_part __unused,
unsigned long nsec_entry __unused)
unsigned long nsec_entry __unused,
unsigned long transfer_list __unused)
{
}
7 changes: 5 additions & 2 deletions 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 @@ -44,7 +45,8 @@ extern const struct core_mmu_config boot_mmu_config;

/* @nsec_entry is unused if using CFG_WITH_ARM_TRUSTED_FW */
void boot_init_primary_early(unsigned long pageable_part,
unsigned long nsec_entry);
unsigned long nsec_entry,
unsigned long transfer_list);
void boot_init_primary_late(unsigned long fdt, unsigned long manifest);
void boot_init_memtag(void);
void boot_save_boot_info(void *boot_info);
Expand Down Expand Up @@ -97,9 +99,10 @@ void *get_manifest_dt(void);
/*
* get_aslr_seed() - return a random seed for core ASLR
* @fdt: Pointer to a device tree if CFG_DT_ADDR=y
* @tl: Pointer to a transfer list
*
* This function has a __weak default implementation.
*/
unsigned long get_aslr_seed(void *fdt);
unsigned long get_aslr_seed(void *fdt, struct transfer_list_header *tl);

#endif /* __KERNEL_BOOT_H */
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 cb0a351

Please sign in to comment.