blob: 8aa2a88aa1b3a4ef7b7e85e82e7fc9b091981f73 [file] [log] [blame]
Antonio Nino Diazf939a6a2018-11-08 14:12:40 +00001/*
Antonio Nino Diaz0e402d32019-01-30 16:01:49 +00002 * Copyright (c) 2018-2019, Arm Limited. All rights reserved.
Antonio Nino Diazf939a6a2018-11-08 14:12:40 +00003 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
Antonio Nino Diazf939a6a2018-11-08 14:12:40 +00007#include <assert.h>
Antonio Nino Diaz124a1fc2018-11-30 10:52:09 +00008#include <errno.h>
9#include <limits.h>
Antonio Nino Diaze0f90632018-12-14 00:18:21 +000010
11#include <arch_helpers.h>
12#include <common/debug.h>
Antonio Nino Diaz0e402d32019-01-30 16:01:49 +000013#include <common/runtime_svc.h>
Antonio Nino Diaze0f90632018-12-14 00:18:21 +000014#include <lib/el3_runtime/context_mgmt.h>
15#include <lib/smccc.h>
16#include <lib/utils.h>
17#include <plat/common/platform.h>
18#include <services/sprt_svc.h>
Antonio Nino Diazf939a6a2018-11-08 14:12:40 +000019#include <smccc_helpers.h>
Antonio Nino Diazf939a6a2018-11-08 14:12:40 +000020
21#include "spm_private.h"
22
23/*******************************************************************************
Antonio Nino Diaz124a1fc2018-11-30 10:52:09 +000024 * Functions to manipulate memory regions
25 ******************************************************************************/
26
27/*
28 * Attributes are encoded using a different format in the SMC interface than in
29 * the Trusted Firmware, where the mmap_attr_t enum type is used. This function
30 * converts an attributes value from the SMC format to the mmap_attr_t format by
31 * setting MT_RW/MT_RO, MT_USER/MT_PRIVILEGED and MT_EXECUTE/MT_EXECUTE_NEVER.
32 * The other fields are left as 0 because they are ignored by the function
33 * xlat_change_mem_attributes_ctx().
34 */
35static unsigned int smc_attr_to_mmap_attr(unsigned int attributes)
36{
37 unsigned int perm = attributes & SPRT_MEMORY_PERM_ATTR_MASK;
38
39 if (perm == SPRT_MEMORY_PERM_ATTR_RW) {
40 return MT_RW | MT_EXECUTE_NEVER | MT_USER;
41 } else if (perm == SPRT_MEMORY_PERM_ATTR_RO) {
42 return MT_RO | MT_EXECUTE_NEVER | MT_USER;
43 } else if (perm == SPRT_MEMORY_PERM_ATTR_RO_EXEC) {
44 return MT_RO | MT_USER;
45 } else {
46 return UINT_MAX;
47 }
48}
49
50/*
51 * This function converts attributes from the Trusted Firmware format into the
52 * SMC interface format.
53 */
54static unsigned int mmap_attr_to_smc_attr(unsigned int attr)
55{
56 unsigned int perm;
57
58 /* No access from EL0. */
59 if ((attr & MT_USER) == 0U)
60 return UINT_MAX;
61
62 if ((attr & MT_RW) != 0) {
63 assert(MT_TYPE(attr) != MT_DEVICE);
64 perm = SPRT_MEMORY_PERM_ATTR_RW;
65 } else {
66 if ((attr & MT_EXECUTE_NEVER) != 0U) {
67 perm = SPRT_MEMORY_PERM_ATTR_RO;
68 } else {
69 perm = SPRT_MEMORY_PERM_ATTR_RO_EXEC;
70 }
71 }
72
73 return perm << SPRT_MEMORY_PERM_ATTR_SHIFT;
74}
75
76static int32_t sprt_memory_perm_attr_get(sp_context_t *sp_ctx, uintptr_t base_va)
77{
78 uint32_t attributes;
79
80 spin_lock(&(sp_ctx->xlat_ctx_lock));
81
82 int ret = xlat_get_mem_attributes_ctx(sp_ctx->xlat_ctx_handle,
83 base_va, &attributes);
84
85 spin_unlock(&(sp_ctx->xlat_ctx_lock));
86
87 /* Convert error codes of xlat_get_mem_attributes_ctx() into SPM. */
88 assert((ret == 0) || (ret == -EINVAL));
89
90 if (ret != 0)
91 return SPRT_INVALID_PARAMETER;
92
93 unsigned int perm = mmap_attr_to_smc_attr(attributes);
94
95 if (perm == UINT_MAX)
96 return SPRT_INVALID_PARAMETER;
97
98 return SPRT_SUCCESS | perm;
99}
100
101static int32_t sprt_memory_perm_attr_set(sp_context_t *sp_ctx,
102 u_register_t page_address, u_register_t pages_count,
103 u_register_t smc_attributes)
104{
105 int ret;
106 uintptr_t base_va = (uintptr_t) page_address;
107 size_t size = pages_count * PAGE_SIZE;
108
109 VERBOSE(" Start address : 0x%lx\n", base_va);
110 VERBOSE(" Number of pages: %i (%zi bytes)\n", (int) pages_count, size);
111 VERBOSE(" Attributes : 0x%lx\n", smc_attributes);
112
113 uint32_t mmap_attr = smc_attr_to_mmap_attr(smc_attributes);
114
115 if (mmap_attr == UINT_MAX) {
116 WARN("%s: Invalid memory attributes: 0x%lx\n", __func__,
117 smc_attributes);
118 return SPRT_INVALID_PARAMETER;
119 }
120
121 /*
122 * Perform some checks before actually trying to change the memory
123 * attributes.
124 */
125
126 spin_lock(&(sp_ctx->xlat_ctx_lock));
127
128 uint32_t attributes;
129
130 ret = xlat_get_mem_attributes_ctx(sp_ctx->xlat_ctx_handle,
131 base_va, &attributes);
132
133 if (ret != 0) {
134 spin_unlock(&(sp_ctx->xlat_ctx_lock));
135 return SPRT_INVALID_PARAMETER;
136 }
137
138 if ((attributes & MT_USER) == 0U) {
139 /* Prohibit changing attributes of S-EL1 regions */
140 spin_unlock(&(sp_ctx->xlat_ctx_lock));
141 return SPRT_INVALID_PARAMETER;
142 }
143
144 ret = xlat_change_mem_attributes_ctx(sp_ctx->xlat_ctx_handle,
145 base_va, size, mmap_attr);
146
147 spin_unlock(&(sp_ctx->xlat_ctx_lock));
148
149 /* Convert error codes of xlat_change_mem_attributes_ctx() into SPM. */
150 assert((ret == 0) || (ret == -EINVAL));
151
152 return (ret == 0) ? SPRT_SUCCESS : SPRT_INVALID_PARAMETER;
153}
154
155/*******************************************************************************
Antonio Nino Diazf939a6a2018-11-08 14:12:40 +0000156 * This function handles all SMCs in the range reserved for SPRT.
157 ******************************************************************************/
Antonio Nino Diaz0e402d32019-01-30 16:01:49 +0000158static uintptr_t sprt_smc_handler(uint32_t smc_fid, u_register_t x1,
159 u_register_t x2, u_register_t x3,
160 u_register_t x4, void *cookie, void *handle,
161 u_register_t flags)
Antonio Nino Diazf939a6a2018-11-08 14:12:40 +0000162{
163 /* SPRT only supported from the Secure world */
164 if (is_caller_non_secure(flags) == SMC_FROM_NON_SECURE) {
165 SMC_RET1(handle, SMC_UNK);
166 }
167
168 assert(handle == cm_get_context(SECURE));
169
170 /*
171 * Only S-EL0 partitions are supported for now. Make the next ERET into
172 * the partition jump directly to S-EL0 instead of S-EL1.
173 */
174 cm_set_elr_spsr_el3(SECURE, read_elr_el1(), read_spsr_el1());
175
176 switch (smc_fid) {
177 case SPRT_VERSION:
178 SMC_RET1(handle, SPRT_VERSION_COMPILED);
179
Antonio Nino Diaz8c83ad82018-11-08 14:21:19 +0000180 case SPRT_PUT_RESPONSE_AARCH64:
181 /*
182 * Registers x1-x3 aren't saved by default to the context,
183 * but they are needed after spm_sp_synchronous_exit() because
184 * they hold return values.
185 */
186 SMC_SET_GP(handle, CTX_GPREG_X1, x1);
187 SMC_SET_GP(handle, CTX_GPREG_X2, x2);
188 SMC_SET_GP(handle, CTX_GPREG_X3, x3);
189 spm_sp_synchronous_exit(SPRT_PUT_RESPONSE_AARCH64);
190
191 case SPRT_YIELD_AARCH64:
192 spm_sp_synchronous_exit(SPRT_YIELD_AARCH64);
193
Antonio Nino Diaz124a1fc2018-11-30 10:52:09 +0000194 case SPRT_MEMORY_PERM_ATTR_GET_AARCH64:
195 {
196 /* Get context of the SP in use by this CPU. */
197 unsigned int linear_id = plat_my_core_pos();
198 sp_context_t *sp_ctx = spm_cpu_get_sp_ctx(linear_id);
199
200 SMC_RET1(handle, sprt_memory_perm_attr_get(sp_ctx, x1));
201 }
202
203 case SPRT_MEMORY_PERM_ATTR_SET_AARCH64:
204 {
205 /* Get context of the SP in use by this CPU. */
206 unsigned int linear_id = plat_my_core_pos();
207 sp_context_t *sp_ctx = spm_cpu_get_sp_ctx(linear_id);
208
209 SMC_RET1(handle, sprt_memory_perm_attr_set(sp_ctx, x1, x2, x3));
210 }
211
Antonio Nino Diazf939a6a2018-11-08 14:12:40 +0000212 default:
213 break;
214 }
215
216 WARN("SPRT: Unsupported call 0x%08x\n", smc_fid);
217 SMC_RET1(handle, SPRT_NOT_SUPPORTED);
218}
Antonio Nino Diaz0e402d32019-01-30 16:01:49 +0000219
220DECLARE_RT_SVC(
221 sprt_handler,
222 OEN_SPRT_START,
223 OEN_SPRT_END,
224 SMC_TYPE_FAST,
225 NULL,
226 sprt_smc_handler
227);