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