1/*
2 * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#include <arch.h>
8#include <asm_macros.S>
9#include <bl1.h>
10#include <bl_common.h>
11#include <context.h>
12#include <smcc_helpers.h>
13#include <smcc_macros.S>
14#include <xlat_tables.h>
15
16	.globl	bl1_aarch32_smc_handler
17
18
19func bl1_aarch32_smc_handler
20	/* On SMC entry, `sp` points to `smc_ctx_t`. Save `lr`. */
21	str	lr, [sp, #SMC_CTX_LR_MON]
22
23	/* ------------------------------------------------
24	 * SMC in BL1 is handled assuming that the MMU is
25	 * turned off by BL2.
26	 * ------------------------------------------------
27	 */
28
29	/* ----------------------------------------------
30	 * Detect if this is a RUN_IMAGE or other SMC.
31	 * ----------------------------------------------
32	 */
33	mov	lr, #BL1_SMC_RUN_IMAGE
34	cmp	lr, r0
35	bne	smc_handler
36
37	/* ------------------------------------------------
38	 * Make sure only Secure world reaches here.
39	 * ------------------------------------------------
40	 */
41	ldcopr  r8, SCR
42	tst	r8, #SCR_NS_BIT
43	blne	report_exception
44
45	/* ---------------------------------------------------------------------
46	 * Pass control to next secure image.
47	 * Here it expects r1 to contain the address of a entry_point_info_t
48	 * structure describing the BL entrypoint.
49	 * ---------------------------------------------------------------------
50	 */
51	mov	r8, r1
52	mov	r0, r1
53	bl	bl1_print_next_bl_ep_info
54
55#if SPIN_ON_BL1_EXIT
56	bl	print_debug_loop_message
57debug_loop:
58	b	debug_loop
59#endif
60
61	mov	r0, r8
62	bl	bl1_plat_prepare_exit
63
64	stcopr	r0, TLBIALL
65	dsb	sy
66	isb
67
68	/*
69	 * Extract PC and SPSR based on struct `entry_point_info_t`
70	 * and load it in LR and SPSR registers respectively.
71	 */
72	ldr	lr, [r8, #ENTRY_POINT_INFO_PC_OFFSET]
73	ldr	r1, [r8, #(ENTRY_POINT_INFO_PC_OFFSET + 4)]
74	msr	spsr, r1
75
76	add	r8, r8, #ENTRY_POINT_INFO_ARGS_OFFSET
77	ldm	r8, {r0, r1, r2, r3}
78	eret
79endfunc bl1_aarch32_smc_handler
80
81	/* -----------------------------------------------------
82	 * Save Secure/Normal world context and jump to
83	 * BL1 SMC handler.
84	 * -----------------------------------------------------
85	 */
86func smc_handler
87	/* -----------------------------------------------------
88	 * Save the GP registers.
89	 * -----------------------------------------------------
90	 */
91	smcc_save_gp_mode_regs
92
93	/*
94	 * `sp` still points to `smc_ctx_t`. Save it to a register
95	 * and restore the C runtime stack pointer to `sp`.
96	 */
97	mov	r6, sp
98	ldr	sp, [r6, #SMC_CTX_SP_MON]
99
100	ldr	r0, [r6, #SMC_CTX_SCR]
101	and	r7, r0, #SCR_NS_BIT		/* flags */
102
103	/* Switch to Secure Mode */
104	bic	r0, #SCR_NS_BIT
105	stcopr	r0, SCR
106	isb
107
108	/* If caller is from Secure world then turn on the MMU */
109	tst	r7, #SCR_NS_BIT
110	bne	skip_mmu_on
111
112	/* Turn on the MMU */
113	mov	r0, #DISABLE_DCACHE
114	bl	enable_mmu_secure
115
116	/* Enable the data cache. */
117	ldcopr	r9, SCTLR
118	orr	r9, r9, #SCTLR_C_BIT
119	stcopr	r9, SCTLR
120	isb
121
122skip_mmu_on:
123	/* Prepare arguments for BL1 SMC wrapper. */
124	ldr	r0, [r6, #SMC_CTX_GPREG_R0]	/* smc_fid */
125	mov	r1, #0				/* cookie */
126	mov	r2, r6				/* handle */
127	mov	r3, r7				/* flags */
128	bl	bl1_smc_wrapper
129
130	/* Get the smc_context for next BL image */
131	bl	smc_get_next_ctx
132	mov	r4, r0
133
134	/* Only turn-off MMU if going to secure world */
135	ldr	r5, [r4, #SMC_CTX_SCR]
136	tst	r5, #SCR_NS_BIT
137	bne	skip_mmu_off
138
139	/* Disable the MMU */
140	bl	disable_mmu_icache_secure
141	stcopr	r0, TLBIALL
142	dsb	sy
143	isb
144
145skip_mmu_off:
146	/* -----------------------------------------------------
147	 * Do the transition to next BL image.
148	 * -----------------------------------------------------
149	 */
150	mov	r0, r4
151	monitor_exit
152endfunc smc_handler
153