Home | History | Annotate | Download | only in sp_min
      1 /*
      2  * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
      3  *
      4  * SPDX-License-Identifier: BSD-3-Clause
      5  */
      6 
      7 #include <arch.h>
      8 #include <arch_helpers.h>
      9 #include <assert.h>
     10 #include <bl_common.h>
     11 #include <console.h>
     12 #include <context.h>
     13 #include <context_mgmt.h>
     14 #include <debug.h>
     15 #include <platform.h>
     16 #include <platform_def.h>
     17 #include <platform_sp_min.h>
     18 #include <psci.h>
     19 #include <runtime_svc.h>
     20 #include <smcc_helpers.h>
     21 #include <stddef.h>
     22 #include <stdint.h>
     23 #include <string.h>
     24 #include <types.h>
     25 #include <utils.h>
     26 #include "sp_min_private.h"
     27 
     28 /* Pointers to per-core cpu contexts */
     29 static void *sp_min_cpu_ctx_ptr[PLATFORM_CORE_COUNT];
     30 
     31 /* SP_MIN only stores the non secure smc context */
     32 static smc_ctx_t sp_min_smc_context[PLATFORM_CORE_COUNT];
     33 
     34 /******************************************************************************
     35  * Define the smcc helper library API's
     36  *****************************************************************************/
     37 void *smc_get_ctx(unsigned int security_state)
     38 {
     39 	assert(security_state == NON_SECURE);
     40 	return &sp_min_smc_context[plat_my_core_pos()];
     41 }
     42 
     43 void smc_set_next_ctx(unsigned int security_state)
     44 {
     45 	assert(security_state == NON_SECURE);
     46 	/* SP_MIN stores only non secure smc context. Nothing to do here */
     47 }
     48 
     49 void *smc_get_next_ctx(void)
     50 {
     51 	return &sp_min_smc_context[plat_my_core_pos()];
     52 }
     53 
     54 /*******************************************************************************
     55  * This function returns a pointer to the most recent 'cpu_context' structure
     56  * for the calling CPU that was set as the context for the specified security
     57  * state. NULL is returned if no such structure has been specified.
     58  ******************************************************************************/
     59 void *cm_get_context(uint32_t security_state)
     60 {
     61 	assert(security_state == NON_SECURE);
     62 	return sp_min_cpu_ctx_ptr[plat_my_core_pos()];
     63 }
     64 
     65 /*******************************************************************************
     66  * This function sets the pointer to the current 'cpu_context' structure for the
     67  * specified security state for the calling CPU
     68  ******************************************************************************/
     69 void cm_set_context(void *context, uint32_t security_state)
     70 {
     71 	assert(security_state == NON_SECURE);
     72 	sp_min_cpu_ctx_ptr[plat_my_core_pos()] = context;
     73 }
     74 
     75 /*******************************************************************************
     76  * This function returns a pointer to the most recent 'cpu_context' structure
     77  * for the CPU identified by `cpu_idx` that was set as the context for the
     78  * specified security state. NULL is returned if no such structure has been
     79  * specified.
     80  ******************************************************************************/
     81 void *cm_get_context_by_index(unsigned int cpu_idx,
     82 				unsigned int security_state)
     83 {
     84 	assert(security_state == NON_SECURE);
     85 	return sp_min_cpu_ctx_ptr[cpu_idx];
     86 }
     87 
     88 /*******************************************************************************
     89  * This function sets the pointer to the current 'cpu_context' structure for the
     90  * specified security state for the CPU identified by CPU index.
     91  ******************************************************************************/
     92 void cm_set_context_by_index(unsigned int cpu_idx, void *context,
     93 				unsigned int security_state)
     94 {
     95 	assert(security_state == NON_SECURE);
     96 	sp_min_cpu_ctx_ptr[cpu_idx] = context;
     97 }
     98 
     99 static void copy_cpu_ctx_to_smc_stx(const regs_t *cpu_reg_ctx,
    100 				smc_ctx_t *next_smc_ctx)
    101 {
    102 	next_smc_ctx->r0 = read_ctx_reg(cpu_reg_ctx, CTX_GPREG_R0);
    103 	next_smc_ctx->lr_mon = read_ctx_reg(cpu_reg_ctx, CTX_LR);
    104 	next_smc_ctx->spsr_mon = read_ctx_reg(cpu_reg_ctx, CTX_SPSR);
    105 	next_smc_ctx->scr = read_ctx_reg(cpu_reg_ctx, CTX_SCR);
    106 }
    107 
    108 /*******************************************************************************
    109  * This function invokes the PSCI library interface to initialize the
    110  * non secure cpu context and copies the relevant cpu context register values
    111  * to smc context. These registers will get programmed during `smc_exit`.
    112  ******************************************************************************/
    113 static void sp_min_prepare_next_image_entry(void)
    114 {
    115 	entry_point_info_t *next_image_info;
    116 	cpu_context_t *ctx = cm_get_context(NON_SECURE);
    117 	u_register_t ns_sctlr;
    118 
    119 	/* Program system registers to proceed to non-secure */
    120 	next_image_info = sp_min_plat_get_bl33_ep_info();
    121 	assert(next_image_info);
    122 	assert(NON_SECURE == GET_SECURITY_STATE(next_image_info->h.attr));
    123 
    124 	INFO("SP_MIN: Preparing exit to normal world\n");
    125 
    126 	psci_prepare_next_non_secure_ctx(next_image_info);
    127 	smc_set_next_ctx(NON_SECURE);
    128 
    129 	/* Copy r0, lr and spsr from cpu context to SMC context */
    130 	copy_cpu_ctx_to_smc_stx(get_regs_ctx(cm_get_context(NON_SECURE)),
    131 			smc_get_next_ctx());
    132 
    133 	/* Temporarily set the NS bit to access NS SCTLR */
    134 	write_scr(read_scr() | SCR_NS_BIT);
    135 	isb();
    136 	ns_sctlr = read_ctx_reg(get_regs_ctx(ctx), CTX_NS_SCTLR);
    137 	write_sctlr(ns_sctlr);
    138 	isb();
    139 
    140 	write_scr(read_scr() & ~SCR_NS_BIT);
    141 	isb();
    142 }
    143 
    144 /******************************************************************************
    145  * Implement the ARM Standard Service function to get arguments for a
    146  * particular service.
    147  *****************************************************************************/
    148 uintptr_t get_arm_std_svc_args(unsigned int svc_mask)
    149 {
    150 	/* Setup the arguments for PSCI Library */
    151 	DEFINE_STATIC_PSCI_LIB_ARGS_V1(psci_args, sp_min_warm_entrypoint);
    152 
    153 	/* PSCI is the only ARM Standard Service implemented */
    154 	assert(svc_mask == PSCI_FID_MASK);
    155 
    156 	return (uintptr_t)&psci_args;
    157 }
    158 
    159 /******************************************************************************
    160  * The SP_MIN main function. Do the platform and PSCI Library setup. Also
    161  * initialize the runtime service framework.
    162  *****************************************************************************/
    163 void sp_min_main(void)
    164 {
    165 	NOTICE("SP_MIN: %s\n", version_string);
    166 	NOTICE("SP_MIN: %s\n", build_message);
    167 
    168 	/* Perform the SP_MIN platform setup */
    169 	sp_min_platform_setup();
    170 
    171 	/* Initialize the runtime services e.g. psci */
    172 	INFO("SP_MIN: Initializing runtime services\n");
    173 	runtime_svc_init();
    174 
    175 	/*
    176 	 * We are ready to enter the next EL. Prepare entry into the image
    177 	 * corresponding to the desired security state after the next ERET.
    178 	 */
    179 	sp_min_prepare_next_image_entry();
    180 
    181 	/*
    182 	 * Perform any platform specific runtime setup prior to cold boot exit
    183 	 * from SP_MIN.
    184 	 */
    185 	sp_min_plat_runtime_setup();
    186 
    187 	console_flush();
    188 }
    189 
    190 /******************************************************************************
    191  * This function is invoked during warm boot. Invoke the PSCI library
    192  * warm boot entry point which takes care of Architectural and platform setup/
    193  * restore. Copy the relevant cpu_context register values to smc context which
    194  * will get programmed during `smc_exit`.
    195  *****************************************************************************/
    196 void sp_min_warm_boot(void)
    197 {
    198 	smc_ctx_t *next_smc_ctx;
    199 	cpu_context_t *ctx = cm_get_context(NON_SECURE);
    200 	u_register_t ns_sctlr;
    201 
    202 	psci_warmboot_entrypoint();
    203 
    204 	smc_set_next_ctx(NON_SECURE);
    205 
    206 	next_smc_ctx = smc_get_next_ctx();
    207 	zeromem(next_smc_ctx, sizeof(smc_ctx_t));
    208 
    209 	copy_cpu_ctx_to_smc_stx(get_regs_ctx(cm_get_context(NON_SECURE)),
    210 			next_smc_ctx);
    211 
    212 	/* Temporarily set the NS bit to access NS SCTLR */
    213 	write_scr(read_scr() | SCR_NS_BIT);
    214 	isb();
    215 	ns_sctlr = read_ctx_reg(get_regs_ctx(ctx), CTX_NS_SCTLR);
    216 	write_sctlr(ns_sctlr);
    217 	isb();
    218 
    219 	write_scr(read_scr() & ~SCR_NS_BIT);
    220 	isb();
    221 }
    222 
    223 #if SP_MIN_WITH_SECURE_FIQ
    224 /******************************************************************************
    225  * This function is invoked on secure interrupts. By construction of the
    226  * SP_MIN, secure interrupts can only be handled when core executes in non
    227  * secure state.
    228  *****************************************************************************/
    229 void sp_min_fiq(void)
    230 {
    231 	uint32_t id;
    232 
    233 	id = plat_ic_acknowledge_interrupt();
    234 	sp_min_plat_fiq_handler(id);
    235 	plat_ic_end_of_interrupt(id);
    236 }
    237 #endif /* SP_MIN_WITH_SECURE_FIQ */
    238