blob: 6e5755f5807ec94f855ef2a962d4817b6dd3aa0f [file] [log] [blame]
Tushar Khandelwal59f673a2024-05-08 14:42:10 +01001/*
2 * SPDX-License-Identifier: BSD-3-Clause
3 * SPDX-FileCopyrightText: Copyright TF-RMM Contributors.
4 */
5
6#include <arch_features.h>
7#include <assert.h>
8#include <atomics.h>
9#include <sizes.h>
10#include <mec.h>
11#include <smc-rmi.h>
12#include <smc.h>
13#include <stdint.h>
14#include <rmm_el3_ifc.h>
15
16#define MECID_WIDTH U(16)
17#define MEC_MAX_COUNT (U(1) << MECID_WIDTH)
18
19#define MECID_INVALID (-1U)
20
21#define MECID_ARRAY_SIZE ((MEC_MAX_COUNT) / BITS_PER_UL)
22
23/*
24 * Before enabling the MMU, the RMM code is written and read with MECID 0, so
25 * the only possible value at the moment for MECID_SYSTEM is 0.
26 */
27#define MECID_SYSTEM 0
28
29/*
30 * Together, the mec_reserved array and the shared_mec value define the
31 * state of all MECs in the system.
32 *
33 * For a given mecid:
34 *
35 * if mecid == shared_mec
36 * MEC state is SHARED
37 * else
38 * if mec_reserved[mecid] == true
39 * MEC state is PRIVATE_ASSIGNED
40 * else
41 * MEC state is PRIVATE_UNASSIGNED
42 */
43
44static unsigned int mecid_count;
45static unsigned int shared_mec_members;
46static unsigned int shared_mec = MECID_INVALID;
47
48/*
49 * The bitmap for the reserved/used MECID values.
50 */
51static unsigned long mec_reserved[MECID_ARRAY_SIZE];
52
53/* Maximum MECID allocatable for Realms */
54unsigned int mecid_max(void)
55{
56 return mecid_count ? (mecid_count - 1) : 0;
57}
58
59bool mec_reserve(unsigned int mecid)
60{
61 unsigned int offset, bit;
62
63 assert (mecid <= mecid_max());
64
65 offset = mecid / BITS_PER_UL;
66 bit = mecid % BITS_PER_UL;
67
68 if (!atomic_bit_set_acquire_release_64(&mec_reserved[offset], bit)) {
69 rmm_el3_ifc_allocate_mec_key(mecid);
70 return true;
71 }
72
73 return false;
74}
75
76bool mec_release(unsigned int mecid)
77{
78 unsigned int offset, bit;
79
80 assert (mecid <= mecid_max());
81
82 rmm_el3_ifc_release_mec_key(mecid);
83
84 offset = mecid / BITS_PER_UL;
85 bit = mecid % BITS_PER_UL;
86 atomic_bit_clear_release_64(&mec_reserved[offset], bit);
87
88 return true;
89}
90
91unsigned long smc_mec_set_shared(unsigned long mecid)
92{
93 if (!is_feat_mec_present()) {
94 return RMI_ERROR_INPUT;
95 }
96
97 /*
98 * Check for the requested MECID state, if its not already
99 * shared state then to create a new shared MECID, make sure
100 * there is no realm with existing shared MECID.
101 */
102
103 if (mecid > mecid_max()) {
104 return RMI_ERROR_INPUT;
105 }
106
107 if (shared_mec == MECID_INVALID && mec_reserve(mecid)) {
108 shared_mec = mecid;
109 return RMI_SUCCESS;
110 }
111
112 return RMI_ERROR_INPUT;
113}
114
115unsigned long smc_mec_set_private(unsigned long mecid)
116{
117 if (!is_feat_mec_present()) {
118 return RMI_ERROR_INPUT;
119 }
120
121 if (mecid > mecid_max()) {
122 return RMI_ERROR_INPUT;
123 }
124
125 if (shared_mec_members == 0 && mecid == shared_mec) {
126 mec_release(mecid);
127 shared_mec = MECID_INVALID;
128 return RMI_SUCCESS;
129 }
130
131 return RMI_ERROR_INPUT;
132}
133
134bool mec_assign(unsigned int mecid)
135{
136 if (!is_feat_mec_present()) {
137 return true;
138 }
139
140 assert (mecid <= mecid_max());
141
142 if (mecid == shared_mec) {
143 assert (shared_mec_members < UINT32_MAX);
144 shared_mec_members++;
145 return true;
146 }
147
148 return mec_reserve(mecid);
149}
150
151bool mec_unassign(unsigned int mecid)
152{
153 if (!is_feat_mec_present()) {
154 return true;
155 }
156
157 assert (mecid <= mecid_max());
158
159 if (mecid == shared_mec) {
160 if (shared_mec_members > 0) {
161 shared_mec_members--;
162 return true;
163 } else {
164 return false;
165 }
166 }
167
168 mec_release(mecid);
169 return true;
170}
171
172void mec_init_mmu(void)
173{
174 uint16_t mecid;
175 unsigned int offset, bit;
176
177 if (!is_feat_mec_present()) {
178 return;
179 }
180
181 /* Assume all CPUs have the same MECID size */
182 mecid_count = 1U << (EXTRACT(MECIDR_MECIDWIDTHM1, read_mecidr_el2()) + 1);
183
184 mecid = MECID_SYSTEM;
185 offset = mecid / BITS_PER_UL;
186 bit = mecid % BITS_PER_UL;
187 /* Early alloc, MMU is still disabled */
188 mec_reserved[offset] |= (1ULL << bit);
189
190 /* MECID_* reset to UNKNOWN values */
191 write_mecid_p0_el2(mecid);
192 write_mecid_p1_el2(mecid);
193 write_mecid_a0_el2(mecid);
194 write_mecid_a1_el2(mecid);
195 isb();
196
197 write_sctlr2_el2(read_sctlr2_el2() | SCTLR2_ELx_EMEC_BIT);
198}