1 /*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Permission is hereby granted, free of charge, to any person
5 * obtaining a copy of this software and associated documentation
6 * files (the "Software"), to deal in the Software without
7 * restriction, including without limitation the rights to use, copy,
8 * modify, merge, publish, distribute, sublicense, and/or sell copies
9 * of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 */
24
25 #include <trusty/trusty_dev.h>
26 #include <trusty/util.h>
27
28 /* 48-bit physical address bits 47:12 */
29
30 #define NS_PTE_PHYSADDR_SHIFT 12
31 #define NS_PTE_PHYSADDR(pte) ((pte)&0xFFFFFFFFF000ULL)
32
33 /* Access permissions bits 7:6
34 * EL0 EL1
35 * 00 None RW
36 * 01 RW RW
37 * 10 None RO
38 * 11 RO RO
39 */
40 #define NS_PTE_AP_SHIFT 6
41 #define NS_PTE_AP_MASK (0x3 << NS_PTE_AP_SHIFT)
42
43 /* Memory type and cache attributes bits 55:48 */
44 #define NS_PTE_MAIR_SHIFT 48
45 #define NS_PTE_MAIR_MASK (0x00FFULL << NS_PTE_MAIR_SHIFT)
46
47 #define NS_PTE_MAIR_INNER_SHIFT 48
48 #define NS_PTE_MAIR_INNER_MASK (0x000FULL << NS_PTE_MAIR_INNER_SHIFT)
49
50 #define NS_PTE_MAIR_OUTER_SHIFT 52
51 #define NS_PTE_MAIR_OUTER_MASK (0x000FULL << NS_PTE_MAIR_OUTER_SHIFT)
52
53 /* Normal memory */
54
55 /* inner and outer write back read/write allocate */
56 #define NS_MAIR_NORMAL_CACHED_WB_RWA 0xFF
57 /* inner and outer write through read allocate */
58 #define NS_MAIR_NORMAL_CACHED_WT_RA 0xAA
59 /* inner and outer write back, read allocate */
60 #define NS_MAIR_NORMAL_CACHED_WB_RA 0xEE
61 /* uncached */
62 #define NS_MAIR_NORMAL_UNCACHED 0x44
63
64 /* Device memory */
65 /* nGnRnE (strongly ordered) */
66 #define NS_MAIR_DEVICE_STRONGLY_ORDERED 0x00
67 /* nGnRE (device) */
68 #define NS_MAIR_DEVICE 0x04
69 /* GRE */
70 #define NS_MAIR_DEVICE_GRE 0x0C
71
72 /* shareable attributes bits 9:8 */
73 #define NS_PTE_SHAREABLE_SHIFT 8
74
75 #define NS_NON_SHAREABLE 0x0
76 #define NS_OUTER_SHAREABLE 0x2
77 #define NS_INNER_SHAREABLE 0x3
78
79 typedef uintptr_t addr_t;
80 typedef uintptr_t vaddr_t;
81 typedef uintptr_t paddr_t;
82
83 #if NS_ARCH_ARM64
84
85 #define PAR_F (0x1 << 0)
86
87 /*
88 * ARM64
89 */
90
91 /* Note: this will crash if called from user space */
arm64_write_ATS1ExW(uint64_t vaddr)92 static void arm64_write_ATS1ExW(uint64_t vaddr) {
93 uint64_t _current_el;
94
95 __asm__ volatile("mrs %0, CurrentEL" : "=r"(_current_el));
96
97 _current_el = (_current_el >> 2) & 0x3;
98 switch (_current_el) {
99 case 0x1:
100 __asm__ volatile("at S1E1W, %0" ::"r"(vaddr));
101 break;
102 case 0x2:
103 __asm__ volatile("at S1E2W, %0" ::"r"(vaddr));
104 break;
105 case 0x3:
106 default:
107 trusty_fatal("Unsupported execution state: EL%u\n", _current_el);
108 break;
109 }
110
111 __asm__ volatile("isb" ::: "memory");
112 }
113
arm64_read_par64(void)114 static uint64_t arm64_read_par64(void) {
115 uint64_t _val;
116 __asm__ volatile("mrs %0, par_el1" : "=r"(_val));
117 return _val;
118 }
119
va2par(vaddr_t va)120 static uint64_t va2par(vaddr_t va) {
121 uint64_t par;
122 unsigned long irq_state;
123
124 trusty_local_irq_disable(&irq_state);
125 arm64_write_ATS1ExW(va);
126 par = arm64_read_par64();
127 trusty_local_irq_restore(&irq_state);
128
129 return par;
130 }
131
par2attr(uint64_t par)132 static uint64_t par2attr(uint64_t par) {
133 uint64_t attr;
134
135 /* set phys address */
136 attr = NS_PTE_PHYSADDR(par);
137
138 /* cache attributes */
139 attr |= ((par >> 56) & 0xFF) << NS_PTE_MAIR_SHIFT;
140
141 /* shareable attributes */
142 attr |= ((par >> 7) & 0x03) << NS_PTE_SHAREABLE_SHIFT;
143
144 /* the memory is writable and accessible so leave AP field 0 */
145 attr |= 0x0 << NS_PTE_AP_SHIFT;
146
147 return attr;
148 }
149
150 #else
151
152 #define PAR_F (0x1 << 0)
153 #define PAR_SS (0x1 << 1)
154 #define PAR_SH (0x1 << 7)
155 #define PAR_NOS (0x1 << 10)
156 #define PAR_LPAE (0x1 << 11)
157
158 /*
159 * ARM32
160 */
161
162 /* Note: this will crash if called from user space */
arm_write_ATS1xW(uint64_t vaddr)163 static void arm_write_ATS1xW(uint64_t vaddr) {
164 uint32_t _cpsr;
165
166 __asm__ volatile("mrs %0, cpsr" : "=r"(_cpsr));
167
168 if ((_cpsr & 0xF) == 0xa)
169 __asm__ volatile("mcr p15, 4, %0, c7, c8, 1" : : "r"(vaddr));
170 else
171 __asm__ volatile("mcr p15, 0, %0, c7, c8, 1" : : "r"(vaddr));
172 }
173
arm_read_par64(void)174 static uint64_t arm_read_par64(void) {
175 uint32_t lower, higher;
176
177 __asm__ volatile(
178 "mrc p15, 0, %0, c7, c4, 0 \n"
179 "tst %0, #(1 << 11) @ LPAE / long desc format\n"
180 "moveq %1, #0 \n"
181 "mrrcne p15, 0, %0, %1, c7 \n"
182 : "=r"(lower), "=r"(higher)
183 :
184 :);
185
186 return ((uint64_t)higher << 32) | lower;
187 }
188
189 static uint8_t ish_to_mair[8] = {
190 0x04, /* 0b000 Non cacheble */
191 0x00, /* 0b001 Strongly ordered */
192 0xF0, /* 0b010 reserved */
193 0x04, /* 0b011 device */
194 0xF0, /* 0b100 reserved */
195 0x0F, /* 0b101 write back - write allocate */
196 0x0A, /* 0b110 write through */
197 0x0E, /* 0b111 write back - no write allocate */
198 };
199
200 static uint8_t osh_to_mair[4] = {
201 0x00, /* 0b00 Non-cacheable */
202 0x0F, /* 0b01 Write-back, Write-allocate */
203 0x0A, /* 0b10 Write-through, no Write-allocate */
204 0x0E, /* 0b11 Write-back, no Write-allocate */
205 };
206
par2attr(uint64_t par)207 static uint64_t par2attr(uint64_t par) {
208 uint64_t attr;
209
210 if (par & PAR_LPAE) {
211 /* set phys address */
212 attr = NS_PTE_PHYSADDR(par);
213
214 /* cache attributes */
215 attr |= ((par >> 56) & 0xFF) << NS_PTE_MAIR_SHIFT;
216
217 /* shareable attributes */
218 attr |= ((par >> 7) & 0x03) << NS_PTE_SHAREABLE_SHIFT;
219
220 } else {
221 /* set phys address */
222 trusty_assert((par & PAR_SS) == 0); /* super section not supported */
223 attr = NS_PTE_PHYSADDR(par);
224
225 /* cache attributes */
226 uint64_t inner = ((uint64_t)ish_to_mair[(par >> 4) & 0x7])
227 << NS_PTE_MAIR_INNER_SHIFT;
228 uint64_t outer = ((uint64_t)osh_to_mair[(par >> 2) & 0x3])
229 << NS_PTE_MAIR_OUTER_SHIFT;
230 uint64_t cache_attributes = (outer << 4) | inner;
231
232 /* Trusty does not support any kind of device memory, so we will force
233 * cache attributes to be NORMAL UNCACHED on the Trusty side.
234 */
235 if (cache_attributes == NS_MAIR_DEVICE_STRONGLY_ORDERED) {
236 attr |= ((uint64_t)NS_MAIR_NORMAL_UNCACHED << NS_PTE_MAIR_SHIFT);
237 } else {
238 attr |= inner;
239 attr |= outer;
240 }
241
242 /* shareable attributes */
243 if (par & PAR_SH) {
244 /* how to handle NOS bit ? */
245 attr |= ((uint64_t)NS_INNER_SHAREABLE) << NS_PTE_SHAREABLE_SHIFT;
246 } else {
247 attr |= ((uint64_t)NS_NON_SHAREABLE) << NS_PTE_SHAREABLE_SHIFT;
248 }
249 }
250
251 /* the memory is writable and accessible so leave AP field 0 */
252 attr |= 0x0 << NS_PTE_AP_SHIFT;
253
254 return attr;
255 }
256
va2par(vaddr_t va)257 static uint64_t va2par(vaddr_t va) {
258 uint64_t par;
259 unsigned long irq_state;
260
261 trusty_local_irq_disable(&irq_state);
262 arm_write_ATS1xW(va);
263 par = arm_read_par64();
264 trusty_local_irq_restore(&irq_state);
265
266 return par;
267 }
268
269 #endif /* ARM64 */
270
trusty_encode_page_info(struct ns_mem_page_info * inf,void * va)271 int trusty_encode_page_info(struct ns_mem_page_info* inf, void* va) {
272 uint64_t par = va2par((vaddr_t)va);
273
274 if (par & PAR_F) {
275 return -1;
276 }
277
278 inf->attr = par2attr(par);
279
280 return 0;
281 }
282