2 * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
4 * SPDX-License-Identifier: BSD-3-Clause
12 #include <platform_def.h>
15 #include <arch_helpers.h>
16 #include <common/bl_common.h>
17 #include <common/debug.h>
18 #include <common/runtime_svc.h>
20 #include <drivers/console.h>
21 #include <lib/el3_runtime/context_mgmt.h>
22 #include <lib/psci/psci.h>
23 #include <lib/utils.h>
24 #include <plat/common/platform.h>
25 #include <platform_sp_min.h>
26 #include <services/std_svc.h>
27 #include <smccc_helpers.h>
29 #include "sp_min_private.h"
31 /* Pointers to per-core cpu contexts */
32 static void *sp_min_cpu_ctx_ptr
[PLATFORM_CORE_COUNT
];
34 /* SP_MIN only stores the non secure smc context */
35 static smc_ctx_t sp_min_smc_context
[PLATFORM_CORE_COUNT
];
37 /******************************************************************************
38 * Define the smccc helper library API's
39 *****************************************************************************/
40 void *smc_get_ctx(unsigned int security_state
)
42 assert(security_state
== NON_SECURE
);
43 return &sp_min_smc_context
[plat_my_core_pos()];
46 void smc_set_next_ctx(unsigned int security_state
)
48 assert(security_state
== NON_SECURE
);
49 /* SP_MIN stores only non secure smc context. Nothing to do here */
52 void *smc_get_next_ctx(void)
54 return &sp_min_smc_context
[plat_my_core_pos()];
57 /*******************************************************************************
58 * This function returns a pointer to the most recent 'cpu_context' structure
59 * for the calling CPU that was set as the context for the specified security
60 * state. NULL is returned if no such structure has been specified.
61 ******************************************************************************/
62 void *cm_get_context(uint32_t security_state
)
64 assert(security_state
== NON_SECURE
);
65 return sp_min_cpu_ctx_ptr
[plat_my_core_pos()];
68 /*******************************************************************************
69 * This function sets the pointer to the current 'cpu_context' structure for the
70 * specified security state for the calling CPU
71 ******************************************************************************/
72 void cm_set_context(void *context
, uint32_t security_state
)
74 assert(security_state
== NON_SECURE
);
75 sp_min_cpu_ctx_ptr
[plat_my_core_pos()] = context
;
78 /*******************************************************************************
79 * This function returns a pointer to the most recent 'cpu_context' structure
80 * for the CPU identified by `cpu_idx` that was set as the context for the
81 * specified security state. NULL is returned if no such structure has been
83 ******************************************************************************/
84 void *cm_get_context_by_index(unsigned int cpu_idx
,
85 unsigned int security_state
)
87 assert(security_state
== NON_SECURE
);
88 return sp_min_cpu_ctx_ptr
[cpu_idx
];
91 /*******************************************************************************
92 * This function sets the pointer to the current 'cpu_context' structure for the
93 * specified security state for the CPU identified by CPU index.
94 ******************************************************************************/
95 void cm_set_context_by_index(unsigned int cpu_idx
, void *context
,
96 unsigned int security_state
)
98 assert(security_state
== NON_SECURE
);
99 sp_min_cpu_ctx_ptr
[cpu_idx
] = context
;
102 static void copy_cpu_ctx_to_smc_stx(const regs_t
*cpu_reg_ctx
,
103 smc_ctx_t
*next_smc_ctx
)
105 next_smc_ctx
->r0
= read_ctx_reg(cpu_reg_ctx
, CTX_GPREG_R0
);
106 next_smc_ctx
->r1
= read_ctx_reg(cpu_reg_ctx
, CTX_GPREG_R1
);
107 next_smc_ctx
->r2
= read_ctx_reg(cpu_reg_ctx
, CTX_GPREG_R2
);
108 next_smc_ctx
->lr_mon
= read_ctx_reg(cpu_reg_ctx
, CTX_LR
);
109 next_smc_ctx
->spsr_mon
= read_ctx_reg(cpu_reg_ctx
, CTX_SPSR
);
110 next_smc_ctx
->scr
= read_ctx_reg(cpu_reg_ctx
, CTX_SCR
);
113 /*******************************************************************************
114 * This function invokes the PSCI library interface to initialize the
115 * non secure cpu context and copies the relevant cpu context register values
116 * to smc context. These registers will get programmed during `smc_exit`.
117 ******************************************************************************/
118 static void sp_min_prepare_next_image_entry(void)
120 entry_point_info_t
*next_image_info
;
121 cpu_context_t
*ctx
= cm_get_context(NON_SECURE
);
122 u_register_t ns_sctlr
;
124 /* Program system registers to proceed to non-secure */
125 next_image_info
= sp_min_plat_get_bl33_ep_info();
126 assert(next_image_info
);
127 assert(NON_SECURE
== GET_SECURITY_STATE(next_image_info
->h
.attr
));
129 INFO("SP_MIN: Preparing exit to normal world\n");
131 psci_prepare_next_non_secure_ctx(next_image_info
);
132 smc_set_next_ctx(NON_SECURE
);
134 /* Copy r0, lr and spsr from cpu context to SMC context */
135 copy_cpu_ctx_to_smc_stx(get_regs_ctx(cm_get_context(NON_SECURE
)),
138 /* Temporarily set the NS bit to access NS SCTLR */
139 write_scr(read_scr() | SCR_NS_BIT
);
141 ns_sctlr
= read_ctx_reg(get_regs_ctx(ctx
), CTX_NS_SCTLR
);
142 write_sctlr(ns_sctlr
);
145 write_scr(read_scr() & ~SCR_NS_BIT
);
149 /******************************************************************************
150 * Implement the ARM Standard Service function to get arguments for a
151 * particular service.
152 *****************************************************************************/
153 uintptr_t get_arm_std_svc_args(unsigned int svc_mask
)
155 /* Setup the arguments for PSCI Library */
156 DEFINE_STATIC_PSCI_LIB_ARGS_V1(psci_args
, sp_min_warm_entrypoint
);
158 /* PSCI is the only ARM Standard Service implemented */
159 assert(svc_mask
== PSCI_FID_MASK
);
161 return (uintptr_t)&psci_args
;
164 /******************************************************************************
165 * The SP_MIN main function. Do the platform and PSCI Library setup. Also
166 * initialize the runtime service framework.
167 *****************************************************************************/
168 void sp_min_main(void)
170 NOTICE("SP_MIN: %s\n", version_string
);
171 NOTICE("SP_MIN: %s\n", build_message
);
173 /* Perform the SP_MIN platform setup */
174 sp_min_platform_setup();
176 /* Initialize the runtime services e.g. psci */
177 INFO("SP_MIN: Initializing runtime services\n");
181 * We are ready to enter the next EL. Prepare entry into the image
182 * corresponding to the desired security state after the next ERET.
184 sp_min_prepare_next_image_entry();
187 * Perform any platform specific runtime setup prior to cold boot exit
190 sp_min_plat_runtime_setup();
195 /******************************************************************************
196 * This function is invoked during warm boot. Invoke the PSCI library
197 * warm boot entry point which takes care of Architectural and platform setup/
198 * restore. Copy the relevant cpu_context register values to smc context which
199 * will get programmed during `smc_exit`.
200 *****************************************************************************/
201 void sp_min_warm_boot(void)
203 smc_ctx_t
*next_smc_ctx
;
204 cpu_context_t
*ctx
= cm_get_context(NON_SECURE
);
205 u_register_t ns_sctlr
;
207 psci_warmboot_entrypoint();
209 smc_set_next_ctx(NON_SECURE
);
211 next_smc_ctx
= smc_get_next_ctx();
212 zeromem(next_smc_ctx
, sizeof(smc_ctx_t
));
214 copy_cpu_ctx_to_smc_stx(get_regs_ctx(cm_get_context(NON_SECURE
)),
217 /* Temporarily set the NS bit to access NS SCTLR */
218 write_scr(read_scr() | SCR_NS_BIT
);
220 ns_sctlr
= read_ctx_reg(get_regs_ctx(ctx
), CTX_NS_SCTLR
);
221 write_sctlr(ns_sctlr
);
224 write_scr(read_scr() & ~SCR_NS_BIT
);
228 #if SP_MIN_WITH_SECURE_FIQ
229 /******************************************************************************
230 * This function is invoked on secure interrupts. By construction of the
231 * SP_MIN, secure interrupts can only be handled when core executes in non
233 *****************************************************************************/
234 void sp_min_fiq(void)
238 id
= plat_ic_acknowledge_interrupt();
239 sp_min_plat_fiq_handler(id
);
240 plat_ic_end_of_interrupt(id
);
242 #endif /* SP_MIN_WITH_SECURE_FIQ */