First version
[3rdparty/ote_partner/tlk.git] / arch / arm / arm / mmu_sdesc.c
1 /*
2  * Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining
5  * a copy of this software and associated documentation files
6  * (the "Software"), to deal in the Software without restriction,
7  * including without limitation the rights to use, copy, modify, merge,
8  * publish, distribute, sublicense, and/or sell copies of the Software,
9  * and to permit persons to whom the Software is furnished to do so,
10  * 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 NONINFRINGEMENT.
18  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22  */
23
24 #include <debug.h>
25 #include <assert.h>
26 #include <sys/types.h>
27 #include <err.h>
28 #include <compiler.h>
29 #include <malloc.h>
30 #include <string.h>
31 #include <arch.h>
32 #include <arch/arm.h>
33 #include <arch/arm/mmu.h>
34 #include <arch/arm/mmu_sdesc.h>
35 #include <platform.h>
36
37 #if ARM_WITH_MMU
38
39 #define MB (1024*1024)
40
41 /* the location of the table may be brought in from outside */
42 #if WITH_EXTERNAL_TRANSLATION_TABLE
43 #if !defined(MMU_TRANSLATION_TABLE_ADDR)
44 #error must set MMU_TRANSLATION_TABLE_ADDR in the make configuration
45 #endif
46 uint32_t *tt = (void *)MMU_TRANSLATION_TABLE_ADDR;
47 #else
48 /* the main translation table */
49 uint32_t tt[4096] __ALIGNED(16384) __SECTION(".bss.prebss.translation_table");
50 #endif
51
52 typedef enum {
53         NONE = 0,
54         LEVEL_1_USER,
55         LEVEL_1_PRIV,
56         LEVEL_2,
57 } pgtbl_lvl_t;
58
59 vaddr_t arm_mmu_desc_get_max_user_space()
60 {
61         return ((MMU_MEMORY_TTBR0_L1_SIZE / 4) * \
62                         ((MMU_MEMORY_TTBR_L2_SIZE / 4) * PAGE_SIZE));
63 }
64
65 void arm_mmu_desc_set_default_kernel(arm_phys_attrs_t *attrs)
66 {
67         attrs->inner = MMU_MEMORY_WRITE_BACK_ALLOCATE;
68         attrs->outer = MMU_MEMORY_WRITE_BACK_NO_ALLOCATE;
69         attrs->is_lpae = false;
70 }
71
72 void arm_mmu_desc_set_default_task(arm_phys_attrs_t *attrs)
73 {
74         attrs->inner = MMU_MEMORY_WRITE_BACK_ALLOCATE;
75         attrs->outer = MMU_MEMORY_WRITE_BACK_NO_ALLOCATE;
76         attrs->is_lpae = false;
77 }
78
79 static u_int *arm_mmu_desc_alloc_pgtbl(pgtbl_lvl_t type)
80 {
81         u_int size;
82         u_int *pgtable = NULL;
83
84         switch (type) {
85         case LEVEL_1_USER:
86                 size = MMU_MEMORY_TTBR0_L1_SIZE;
87                 break;
88         case LEVEL_1_PRIV:
89                 size = MMU_MEMORY_TTBR1_L1_SIZE;
90                 break;
91         case LEVEL_2:
92                 size = MMU_MEMORY_TTBR_L2_SIZE;
93                 break;
94         default:
95                 dprintf(CRITICAL, "unrecognized pgtbl_type %d\n", type);
96                 return pgtable;
97         }
98
99         pgtable = memalign(size, size);
100         if (pgtable)
101                 memset(pgtable, 0, size);
102
103         return pgtable;
104 }
105
106 static uint32_t arm_mmu_desc_l2_cache_attrs(arm_phys_attrs_t *attrs)
107 {
108         uint32_t l2_attrs = 0;
109
110         /* check if attrs are from a short or long desc */
111         if (!attrs->is_lpae) {
112                 /* short desc -> short desc */
113                 if (attrs->shareable)
114                         l2_attrs |= MMU_MEMORY_L2_SHAREABLE;
115
116                 /* inner cacheable (cb) */
117                 l2_attrs |= MMU_MEMORY_SET_L2_INNER(attrs->inner);
118
119                 /* outer cacheable (tex) */
120                 l2_attrs |= (MMU_MEMORY_SET_L2_CACHEABLE_MEM |
121                         MMU_MEMORY_SET_L2_OUTER(attrs->outer));
122         } else {
123                 /* long desc -> short desc */
124                 uint32_t cache_attr;
125
126                 if (attrs->shareable == 0x3)
127                         l2_attrs |= MMU_MEMORY_L2_SHAREABLE;
128
129                 /* inner cacheable (cb) */
130                 if ((attrs->inner & 0xC) == 0x1)
131                         cache_attr = MMU_MEMORY_NON_CACHEABLE;
132                 else if ((attrs->inner & 0xC) == 0x8)
133                         cache_attr = MMU_MEMORY_WRITE_THROUGH_NO_ALLOCATE;
134                 else if ((attrs->inner & 0xF) == 0xE)
135                         cache_attr = MMU_MEMORY_WRITE_BACK_NO_ALLOCATE;
136                 else
137                         cache_attr = MMU_MEMORY_WRITE_BACK_ALLOCATE;
138
139                 l2_attrs |= MMU_MEMORY_SET_L2_INNER(cache_attr);
140
141                 /* outer cacheable (tex) */
142                 if ((attrs->inner & 0xC) == 0x1)
143                         cache_attr = MMU_MEMORY_NON_CACHEABLE;
144                 else if ((attrs->inner & 0xC) == 0x8)
145                         cache_attr = MMU_MEMORY_WRITE_THROUGH_NO_ALLOCATE;
146                 else if ((attrs->inner & 0xF) == 0xE)
147                         cache_attr = MMU_MEMORY_WRITE_BACK_NO_ALLOCATE;
148                 else
149                         cache_attr = MMU_MEMORY_WRITE_BACK_ALLOCATE;
150
151                 l2_attrs |= (MMU_MEMORY_SET_L2_CACHEABLE_MEM |
152                                 MMU_MEMORY_SET_L2_OUTER(cache_attr));
153         }
154         return l2_attrs;
155 }
156
157 void arm_mmu_desc_map_page(vaddr_t vaddr, paddr_t paddr, paddr_t *pgtbl,
158                            tmflags_t flags, arm_phys_attrs_t *attrs)
159 {
160         uint32_t *page_table;
161         uint32_t *level_2;
162         uint32_t idx, l1_flags, l2_flags;
163         bool is_kmap;
164
165         is_kmap = (flags & TM_KERN_VA);
166         if (is_kmap) {
167                 page_table = tt;
168         } else {
169                 /* task mapping */
170                 if (*pgtbl == NULL) {
171                         page_table = arm_mmu_desc_alloc_pgtbl(LEVEL_1_USER);
172                         if (page_table == NULL) {
173                                 dprintf(CRITICAL,
174                                         "unable to allocate LEVEL_1 page table\n");
175                                 halt();
176                         }
177                         *pgtbl = virtual_to_physical((vaddr_t)page_table);
178                 } else {
179                         /* task page tables are kept as phys addrs */
180                         page_table = (uint *)physical_to_virtual(*pgtbl);
181                 }
182         }
183
184         ASSERT(page_table);
185
186         /* setup level 1 flags */
187         l1_flags = (flags & (TM_NS_MEM | TM_NS_MEM_PRIV)) ?
188                         MMU_MEMORY_L1_NON_SECURE : 0;
189
190         idx = vaddr >> 20;
191
192         level_2 = (u_int *)(page_table[idx] & ~(MMU_MEMORY_TTBR_L2_SIZE - 1));
193         if (!level_2) {
194                 /* alloc level 2 page table */
195                 level_2 = arm_mmu_desc_alloc_pgtbl(LEVEL_2);
196                 if (level_2 == NULL) {
197                         dprintf(CRITICAL, "unable to allocate LEVEL_2 page table\n");
198                         halt();
199                 }
200
201                 /* install in level_1 */
202                 page_table[idx]  = (u_int)(virtual_to_physical((vaddr_t)level_2));
203                 page_table[idx] |= ((MMU_MEMORY_DOMAIN_MEM << 5) | l1_flags | 0x1);
204         } else {
205                 /* convert from a section to page table */
206                 if ((page_table[idx] & 0x3) == 0x2) {
207                         ASSERT(is_kmap);
208                         level_2 = arm_mmu_desc_alloc_pgtbl(LEVEL_2);
209                         if (level_2 == NULL) {
210                                 dprintf(CRITICAL,
211                                         "unable to allocate LEVEL_2 page table\n");
212                                 halt();
213                         }
214                         /* install in level_1 */
215                         page_table[idx]  = (u_int)(virtual_to_physical((vaddr_t)level_2));
216                         page_table[idx] |= ((MMU_MEMORY_DOMAIN_MEM << 5) | l1_flags | 0x1);
217                 } else {
218                         level_2 = (uint *)physical_to_virtual((paddr_t)level_2);
219                 }
220         }
221
222         idx = vaddr >> 12;
223         idx &= MMU_MEMORY_TTBR_L2_INDEX_MASK;
224
225         ASSERT(!level_2[idx]);
226
227         /* setup level 2 flags */
228         l2_flags  = (!is_kmap) ? MMU_MEMORY_L2_NON_GLOBAL : 0;
229         l2_flags |= (flags & TM_UW) ?
230                         MMU_MEMORY_L2_AP_P_RW_U_RW : MMU_MEMORY_L2_AP_P_RW_U_RO;
231
232         /* set cache attribs */
233         if (flags & TM_IO)
234                 l2_flags |= MMU_MEMORY_L2_TYPE_STRONGLY_ORDERED;
235         else
236                 l2_flags |= arm_mmu_desc_l2_cache_attrs(attrs);
237
238         /* install level_2 4K entry */
239         level_2[idx]  = paddr & ~PAGE_MASK;
240         level_2[idx] |= (l2_flags | 0x2);
241 }
242
243 void arm_mmu_desc_unmap_page(paddr_t pgtbl, vaddr_t vaddr, uint32_t asid)
244 {
245         u_int *page_table;
246         u_int *level_2;
247         u_int idx;
248
249         ASSERT(pgtbl);
250         page_table = (u_int *)physical_to_virtual(pgtbl);
251
252         idx = vaddr >> 20;
253         idx &= MMU_MEMORY_TTBR0_L1_INDEX_MASK;
254
255         level_2 = (u_int *)(page_table[idx] & ~(MMU_MEMORY_TTBR_L2_SIZE - 1));
256         ASSERT(level_2);
257         level_2 = (u_int *)physical_to_virtual((paddr_t)level_2);
258
259         idx = vaddr >> 12;
260         idx &= MMU_MEMORY_TTBR_L2_INDEX_MASK;
261
262         level_2[idx] = 0;       /* invalid entry */
263         arm_invalidate_tlb_byaddr_asid(vaddr, asid);
264 }
265
266 #if !defined(ARM_USE_MMU_RELOC)
267 static void arm_mmu_desc_map_section(addr_t paddr, addr_t vaddr, uint flags)
268 {
269         int index;
270
271         /* Get the index into the translation table */
272         index = vaddr / MB;
273
274         /* Set the entry value:
275          * (2<<0): Section entry
276          * (0<<5): Domain = 0
277          *  flags: TEX, CB and AP bit settings provided by the caller.
278          */
279         tt[index] = (paddr & ~(MB-1)) | (MMU_MEMORY_DOMAIN_MEM << 5) | (2<<0) | flags;
280
281         arm_invalidate_tlb();
282 }
283
284 void arm_mmu_desc_config_mmu()
285 {
286         int i;
287         uint32_t reg;
288
289         /* set some mmu specific control bits:
290          * access flag disabled, TEX remap disabled, mmu disabled
291          */
292         arm_write_sctlr(arm_read_sctlr() & ~((1<<29)|(1<<28)|(1<<0)));
293
294         /* set up an identity-mapped translation table with
295          * strongly ordered memory type and read/write access.
296          */
297         for (i=0; i < 4096; i++) {
298                 arm_mmu_desc_map_section(i * MB,
299                                          i * MB,
300                                          MMU_MEMORY_L1_TYPE_STRONGLY_ORDERED |
301                                          MMU_MEMORY_L1_AP_P_RW_U_NA);
302         }
303
304         platform_init_mmu_mappings();
305
306         /* configure N=7, (kernel uses TTBR1 / user uses TTBR0) */
307         arm_write_ttbcr(MMU_MEMORY_TTBCR_N);
308
309         /* set up the translation table base */
310 #if defined(ARM_USE_CPU_CACHING)
311         /* I:wb/alloc O:wb/alloc */
312         arm_write_ttbr1((uint32_t)tt | MMU_MEMORY_TTBR1_IRGN_RGN);
313 #else
314         arm_write_ttbr1((uint32_t)tt);
315 #endif
316
317         /* set up the domain access register */
318         arm_write_dacr(0x1 << (MMU_MEMORY_DOMAIN_MEM * 2));
319
320         /* turn on the mmu */
321         reg = arm_read_sctlr();
322         arm_write_sctlr(reg | 0x1);
323 }
324 #endif // ARM_USE_MMU_RELOC
325
326 #endif // ARM_WITH_MMU