@ -37,6 +37,12 @@ static uint8_t ffa_boot_info_mem[PAGE_SIZE] __aligned(PAGE_SIZE);
* physical CPU the SP runs on .
* physical CPU the SP runs on .
*/
*/
# define SEL0_SP_EC_INDEX 0
# define SEL0_SP_EC_INDEX 0
# define SP_MEM_READ 0x1
# define SP_MEM_WRITE 0x2
# define SP_MEM_EXECUTE 0x4
# define SP_MEM_NON_SECURE 0x8
# define SP_MEM_READ_ONLY SP_MEM_READ
# define SP_MEM_READ_WRITE (SP_MEM_READ | SP_MEM_WRITE)
/*
/*
* This function creates a initialization descriptor in the memory reserved
* This function creates a initialization descriptor in the memory reserved
@ -170,75 +176,172 @@ void spmc_el0_sp_spsr_setup(entry_point_info_t *ep_info)
ep_info - > spsr = SPSR_64 ( MODE_EL0 , MODE_SP_EL0 , DISABLE_ALL_EXCEPTIONS ) ;
ep_info - > spsr = SPSR_64 ( MODE_EL0 , MODE_SP_EL0 , DISABLE_ALL_EXCEPTIONS ) ;
}
}
/* Setup context of an EL0 Secure Partition. */
static void read_optional_string ( void * manifest , int32_t offset ,
void spmc_el0_sp_setup ( struct secure_partition_desc * sp ,
char * property , char * out , size_t len )
int32_t boot_info_reg )
{
{
mmap_region_t sel1_exception_vectors =
const fdt32_t * prop ;
MAP_REGION_FLAT ( SPM_SHIM_EXCEPTIONS_START ,
int lenp ;
SPM_SHIM_EXCEPTIONS_SIZE ,
MT_CODE | MT_SECURE | MT_PRIVILEGED ) ;
cpu_context_t * ctx ;
ctx = & sp - > ec [ SEL0_SP_EC_INDEX ] . cpu_ctx ;
prop = fdt_getprop ( manifest , offset , property , & lenp ) ;
if ( prop = = NULL ) {
out [ 0 ] = ' \0 ' ;
} else {
memcpy ( out , prop , MIN ( lenp , ( int ) len ) ) ;
}
}
sp - > xlat_ctx_handle - > xlat_regime = EL1_EL0_REGIME ;
/*******************************************************************************
* This function will parse the Secure Partition Manifest for fetching secure
* partition specific memory region details . It will find base address , size ,
* memory attributes for each memory region and then add the respective region
* into secure parition ' s translation context .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void populate_sp_mem_regions ( struct secure_partition_desc * sp ,
void * sp_manifest ,
int node )
{
uintptr_t base_address ;
uint32_t mem_attr , mem_region , size ;
struct mmap_region sp_mem_regions ;
int32_t offset , ret ;
char description [ 10 ] ;
char * property ;
if ( fdt_node_check_compatible ( sp_manifest , node ,
" arm,ffa-manifest-memory-regions " ) ! = 0 ) {
WARN ( " Incompatible memory region node in manifest \n " ) ;
return ;
}
/* This region contains the exception vectors used at S-EL1. */
INFO ( " Mapping SP's memory regions \n " ) ;
mmap_add_region_ctx ( sp - > xlat_ctx_handle ,
& sel1_exception_vectors ) ;
/*
for ( offset = fdt_first_subnode ( sp_manifest , node ) , mem_region = 0 ;
* If the SP manifest specified the register to pass the address of the
offset > = 0 ;
* boot information , then map the memory region to pass boot
offset = fdt_next_subnode ( sp_manifest , offset ) , mem_region + + ) {
* information .
read_optional_string ( sp_manifest , offset , " description " ,
*/
description , sizeof ( description ) ) ;
if ( boot_info_reg > = 0 ) {
mmap_region_t ffa_boot_info_region = MAP_REGION_FLAT (
INFO ( " Mapping: region: %d, %s \n " , mem_region , description ) ;
( uintptr_t ) ffa_boot_info_mem ,
PAGE_SIZE ,
property = " base-address " ;
MT_RO_DATA | MT_SECURE | MT_USER ) ;
ret = fdt_read_uint64 ( sp_manifest , offset , property ,
mmap_add_region_ctx ( sp - > xlat_ctx_handle , & ffa_boot_info_region ) ;
& base_address ) ;
if ( ret < 0 ) {
WARN ( " Missing:%s for %s. \n " , property , description ) ;
continue ;
}
property = " pages-count " ;
ret = fdt_read_uint32 ( sp_manifest , offset , property , & size ) ;
if ( ret < 0 ) {
WARN ( " Missing: %s for %s. \n " , property , description ) ;
continue ;
}
size * = PAGE_SIZE ;
property = " attributes " ;
ret = fdt_read_uint32 ( sp_manifest , offset , property , & mem_attr ) ;
if ( ret < 0 ) {
WARN ( " Missing: %s for %s. \n " , property , description ) ;
continue ;
}
sp_mem_regions . attr = MT_USER ;
if ( ( mem_attr & SP_MEM_EXECUTE ) = = SP_MEM_EXECUTE ) {
sp_mem_regions . attr | = MT_CODE ;
} else if ( ( mem_attr & SP_MEM_READ_ONLY ) = = SP_MEM_READ_ONLY ) {
sp_mem_regions . attr | = MT_RO_DATA ;
} else if ( ( mem_attr & SP_MEM_READ_WRITE ) = =
SP_MEM_READ_WRITE ) {
sp_mem_regions . attr | = MT_RW_DATA ;
}
if ( ( mem_attr & SP_MEM_NON_SECURE ) = = SP_MEM_NON_SECURE ) {
sp_mem_regions . attr | = MT_NS ;
} else {
sp_mem_regions . attr | = MT_SECURE ;
}
sp_mem_regions . base_pa = base_address ;
sp_mem_regions . base_va = base_address ;
sp_mem_regions . size = size ;
sp_mem_regions . granularity = XLAT_BLOCK_SIZE ( 3 ) ;
mmap_add_region_ctx ( sp - > xlat_ctx_handle , & sp_mem_regions ) ;
}
}
}
static void spmc_el0_sp_setup_mmu ( struct secure_partition_desc * sp ,
cpu_context_t * ctx )
{
xlat_ctx_t * xlat_ctx ;
uint64_t mmu_cfg_params [ MMU_CFG_PARAM_MAX ] ;
xlat_ctx = sp - > xlat_ctx_handle ;
init_xlat_tables_ctx ( sp - > xlat_ctx_handle ) ;
setup_mmu_cfg ( ( uint64_t * ) & mmu_cfg_params , 0 , xlat_ctx - > base_table ,
xlat_ctx - > pa_max_address , xlat_ctx - > va_max_address ,
EL1_EL0_REGIME ) ;
write_ctx_reg ( get_el1_sysregs_ctx ( ctx ) , CTX_MAIR_EL1 ,
mmu_cfg_params [ MMU_CFG_MAIR ] ) ;
write_ctx_reg ( get_el1_sysregs_ctx ( ctx ) , CTX_TCR_EL1 ,
mmu_cfg_params [ MMU_CFG_TCR ] ) ;
write_ctx_reg ( get_el1_sysregs_ctx ( ctx ) , CTX_TTBR0_EL1 ,
mmu_cfg_params [ MMU_CFG_TTBR0 ] ) ;
}
static void spmc_el0_sp_setup_sctlr_el1 ( cpu_context_t * ctx )
{
u_register_t sctlr_el1 ;
/* Setup SCTLR_EL1 */
/* Setup SCTLR_EL1 */
u_register_t sctlr_el1 = read_ctx_reg ( get_el1_sysregs_ctx ( ctx ) , CTX_SCTLR_EL1 ) ;
sctlr_el1 = read_ctx_reg ( get_el1_sysregs_ctx ( ctx ) , CTX_SCTLR_EL1 ) ;
sctlr_el1 | =
sctlr_el1 | =
/*SCTLR_EL1_RES1 |*/
/*SCTLR_EL1_RES1 |*/
/* Don't trap DC CVAU, DC CIVAC, DC CVAC, DC CVAP, or IC IVAU */
/* Don't trap DC CVAU, DC CIVAC, DC CVAC, DC CVAP, or IC IVAU */
SCTLR_UCI_BIT |
SCTLR_UCI_BIT |
/* RW regions at xlat regime EL1&0 are forced to be XN. */
/* RW regions at xlat regime EL1&0 are forced to be XN. */
SCTLR_WXN_BIT |
SCTLR_WXN_BIT |
/* Don't trap to EL1 execution of WFI or WFE at EL0. */
/* Don't trap to EL1 execution of WFI or WFE at EL0. */
SCTLR_NTWI_BIT | SCTLR_NTWE_BIT |
SCTLR_NTWI_BIT | SCTLR_NTWE_BIT |
/* Don't trap to EL1 accesses to CTR_EL0 from EL0. */
/* Don't trap to EL1 accesses to CTR_EL0 from EL0. */
SCTLR_UCT_BIT |
SCTLR_UCT_BIT |
/* Don't trap to EL1 execution of DZ ZVA at EL0. */
/* Don't trap to EL1 execution of DZ ZVA at EL0. */
SCTLR_DZE_BIT |
SCTLR_DZE_BIT |
/* Enable SP Alignment check for EL0 */
/* Enable SP Alignment check for EL0 */
SCTLR_SA0_BIT |
SCTLR_SA0_BIT |
/* Don't change PSTATE.PAN on taking an exception to EL1 */
/* Don't change PSTATE.PAN on taking an exception to EL1 */
SCTLR_SPAN_BIT |
SCTLR_SPAN_BIT |
/* Allow cacheable data and instr. accesses to normal memory. */
/* Allow cacheable data and instr. accesses to normal memory. */
SCTLR_C_BIT | SCTLR_I_BIT |
SCTLR_C_BIT | SCTLR_I_BIT |
/* Enable MMU. */
/* Enable MMU. */
SCTLR_M_BIT
SCTLR_M_BIT ;
;
sctlr_el1 & = ~ (
sctlr_el1 & = ~ (
/* Explicit data accesses at EL0 are little-endian. */
/* Explicit data accesses at EL0 are little-endian. */
SCTLR_E0E_BIT |
SCTLR_E0E_BIT |
/*
/*
* Alignment fault checking disabled when at EL1 and EL0 as
* Alignment fault checking disabled when at EL1 and EL0 as
* the UEFI spec permits unaligned accesses .
* the UEFI spec permits unaligned accesses .
*/
*/
SCTLR_A_BIT |
SCTLR_A_BIT |
/* Accesses to DAIF from EL0 are trapped to EL1. */
/* Accesses to DAIF from EL0 are trapped to EL1. */
SCTLR_UMA_BIT
SCTLR_UMA_BIT
) ;
) ;
write_ctx_reg ( get_el1_sysregs_ctx ( ctx ) , CTX_SCTLR_EL1 , sctlr_el1 ) ;
write_ctx_reg ( get_el1_sysregs_ctx ( ctx ) , CTX_SCTLR_EL1 , sctlr_el1 ) ;
}
static void spmc_el0_sp_setup_system_registers ( struct secure_partition_desc * sp ,
cpu_context_t * ctx )
{
spmc_el0_sp_setup_mmu ( sp , ctx ) ;
spmc_el0_sp_setup_sctlr_el1 ( ctx ) ;
/* Setup other system registers. */
/* Setup other system registers. */
@ -260,6 +363,57 @@ void spmc_el0_sp_setup(struct secure_partition_desc *sp,
write_ctx_reg ( get_el1_sysregs_ctx ( ctx ) , CTX_CPACR_EL1 ,
write_ctx_reg ( get_el1_sysregs_ctx ( ctx ) , CTX_CPACR_EL1 ,
CPACR_EL1_FPEN ( CPACR_EL1_FP_TRAP_NONE ) ) ;
CPACR_EL1_FPEN ( CPACR_EL1_FP_TRAP_NONE ) ) ;
}
}
/* Setup context of an EL0 Secure Partition. */
void spmc_el0_sp_setup ( struct secure_partition_desc * sp ,
int32_t boot_info_reg ,
void * sp_manifest )
{
mmap_region_t sel1_exception_vectors =
MAP_REGION_FLAT ( SPM_SHIM_EXCEPTIONS_START ,
SPM_SHIM_EXCEPTIONS_SIZE ,
MT_CODE | MT_SECURE | MT_PRIVILEGED ) ;
cpu_context_t * ctx ;
int node ;
int offset = 0 ;
ctx = & sp - > ec [ SEL0_SP_EC_INDEX ] . cpu_ctx ;
sp - > xlat_ctx_handle - > xlat_regime = EL1_EL0_REGIME ;
/* This region contains the exception vectors used at S-EL1. */
mmap_add_region_ctx ( sp - > xlat_ctx_handle ,
& sel1_exception_vectors ) ;
/*
* If the SP manifest specified the register to pass the address of the
* boot information , then map the memory region to pass boot
* information .
*/
if ( boot_info_reg > = 0 ) {
mmap_region_t ffa_boot_info_region = MAP_REGION_FLAT (
( uintptr_t ) ffa_boot_info_mem ,
PAGE_SIZE ,
MT_RO_DATA | MT_SECURE | MT_USER ) ;
mmap_add_region_ctx ( sp - > xlat_ctx_handle , & ffa_boot_info_region ) ;
}
/*
* Parse the manifest for any memory regions that the SP wants to be
* mapped in its translation regime .
*/
node = fdt_subnode_offset_namelen ( sp_manifest , offset ,
" memory-regions " ,
sizeof ( " memory-regions " ) - 1 ) ;
if ( node < 0 ) {
WARN ( " Not found memory-region configuration for SP. \n " ) ;
} else {
populate_sp_mem_regions ( sp , sp_manifest , node ) ;
}
spmc_el0_sp_setup_system_registers ( sp , ctx ) ;
}
# endif /* SPMC_AT_EL3_SEL0_SP */
# endif /* SPMC_AT_EL3_SEL0_SP */
/* S-EL1 partition specific initialisation. */
/* S-EL1 partition specific initialisation. */