First version
[3rdparty/ote_partner/tlk.git] / arch / arm / arm / mmu.c
1 /*
2  * Copyright (c) 2008-2009 Travis Geiselbrecht
3  * Copyright (c) 2012-2014, NVIDIA CORPORATION. All rights reserved
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining
6  * a copy of this software and associated documentation files
7  * (the "Software"), to deal in the Software without restriction,
8  * including without limitation the rights to use, copy, modify, merge,
9  * publish, distribute, sublicense, and/or sell copies of the Software,
10  * and to permit persons to whom the Software is furnished to do so,
11  * subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be
14  * included in all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23  */
24
25 #include <debug.h>
26 #include <assert.h>
27 #include <sys/types.h>
28 #include <err.h>
29 #include <compiler.h>
30 #include <malloc.h>
31 #include <string.h>
32 #include <arch.h>
33 #include <arch/arm.h>
34 #include <arch/arm/mmu.h>
35 #include <kernel/thread.h>
36 #include <kernel/task.h>
37 #include <platform.h>
38 #include <platform/platform_p.h>
39
40 #if ARM_WITH_MMU
41
42 void arm_mmu_init(void)
43 {
44 #if !defined(ARM_USE_MMU_RELOC)
45         /* setup MMU, since wasn't done in early boot */
46         arm_mmu_desc_config_mmu();
47 #else
48         /* translation table setup already in start.S */
49         platform_init_mmu_mappings();
50 #endif
51 }
52
53 void arch_disable_mmu(void)
54 {
55         arm_write_sctlr(arm_read_sctlr() & ~(1<<0));
56 }
57
58 void arm_mmu_map_kpage(vaddr_t vaddr, paddr_t paddr, task_map_t *mptr)
59 {
60         ASSERT(mptr->map_attrs);
61
62         mptr->flags |= TM_KERN_VA;
63         arm_mmu_desc_map_page(vaddr, paddr, NULL, mptr->flags, mptr->map_attrs);
64 }
65
66 void arm_mmu_map_upage(task_t *taskp, addr_t vaddr, paddr_t paddr,
67                        task_map_t *mptr)
68 {
69         ASSERT(mptr->map_attrs);
70         arm_mmu_desc_map_page(vaddr, paddr, &taskp->page_table,
71                               mptr->flags, mptr->map_attrs);
72 }
73
74 void arm_mmu_unmap_upage(task_t *taskp, addr_t vaddr)
75 {
76         arm_mmu_desc_unmap_page(taskp->page_table, vaddr, taskp->context_id);
77 }
78
79 status_t arm_mmu_set_attrs_task_init(task_map_t *mptr)
80 {
81         mptr->map_attrs = calloc(1, sizeof(arm_phys_attrs_t));
82         if (mptr->map_attrs == NULL)
83                 return ERR_NO_MEMORY;
84         arm_mmu_desc_set_default_task(mptr->map_attrs);
85         return NO_ERROR;
86 }
87
88 status_t arm_mmu_set_attrs_from_mapping(nsaddr_t vaddr, uint32_t type,
89                                         arm_phys_attrs_t *attrs)
90 {
91         uint64_t par;
92
93         par = platform_translate_nsaddr(vaddr, type);
94
95         attrs->faulted = !!(par & PAR_ATTR_FAULTED);
96         if (attrs->faulted) {
97                 dprintf(CRITICAL,
98                         "%s: vaddr 0x%016llx addr translation fault (par = 0x%016llx)\n",
99                         __func__, (nsaddr_t)vaddr, par);
100                 attrs->physaddr = INVALID_PHYSADDR;
101                 return ERR_NOT_VALID;
102         }
103
104         if (par & PAR_ATTR_LPAE) {
105                 attrs->physaddr = PAR_LDESC_ALIGNED_PA(par);
106                 attrs->inner = PAR_LDESC_ATTR_INNER(par);
107                 attrs->outer = PAR_LDESC_ATTR_OUTER(par);
108                 attrs->shareable = PAR_LDESC_ATTR_SHAREABLE(par);
109                 attrs->is_lpae = true;
110         } else {
111                 attrs->physaddr = PAR_SDESC_ALIGNED_PA(par);
112                 attrs->inner = PAR_SDESC_ATTR_INNER(par);
113                 attrs->outer = PAR_SDESC_ATTR_OUTER(par);
114                 attrs->shareable = PAR_SDESC_ATTR_SHAREABLE(par);
115                 attrs->is_lpae = false;
116         }
117
118 #if !ARM_WITH_LPAE
119         /* without LPAE enabled, we can't map memory beyond 4GB */
120         if (attrs->physaddr >> 32) {
121                 dprintf(CRITICAL,
122                         "%s: physaddr (0x%016llx) >= 4GB and LPAE is unsupported\n",
123                         __func__, attrs->physaddr);
124                 attrs->physaddr = INVALID_PHYSADDR;
125                 return ERR_NOT_SUPPORTED;
126         }
127 #endif
128         return NO_ERROR;
129 }
130
131 paddr_t arm_mmu_virt_to_phys(nsaddr_t vaddr, bool ns, bool priv)
132 {
133         uint32_t type;
134         arm_phys_attrs_t attrs;
135
136         if (ns && priv)
137                 type = V2POWPR;         /* other world, priv */
138         else if (ns && !priv)
139                 type = V2POWUR;         /* other world, user */
140         else if (!ns && priv)
141                 type = V2PCWPR;         /* curr world, priv */
142         else
143                 type = V2PCWUR;         /* curr world, user */
144
145         if (arm_mmu_set_attrs_from_mapping(vaddr, type, &attrs) != NO_ERROR)
146                 return INVALID_PHYSADDR;
147
148         /* vtop HW always returns PAGE_MASK aligned phys addrs */
149         return (paddr_t)attrs.physaddr + (vaddr & PAGE_MASK);
150 }
151
152 static bool arm_mmu_compare_attrs(arm_phys_attrs_t *attr1, arm_phys_attrs_t *attr2)
153 {
154         if ((attr1->shareable == attr2->shareable) ||
155             (attr1->inner == attr2->inner) || (attr1->outer == attr2->outer))
156                 return true;
157         return false;
158 }
159
160 void arm_mmu_translate_range(nsaddr_t vaddr, paddr_t *pagelist, task_map_t *mptr)
161 {
162         u_int type, pg;
163
164         mptr->map_attrs = malloc(sizeof(arm_phys_attrs_t));
165         if (mptr->map_attrs == NULL)
166                 return;
167
168         if (mptr->flags & TM_SEC_VA)
169                 type = V2PCWUR;
170         else if (mptr->flags & TM_NS_MEM_PRIV)
171                 type = V2POWPR;
172         else
173                 type = V2POWUR;
174
175         for (pg = 0; pg < (mptr->size / PAGE_SIZE); pg++, pagelist++) {
176                 arm_phys_attrs_t attr;
177                 status_t retval;
178
179                 retval = arm_mmu_set_attrs_from_mapping(vaddr, type, &attr);
180                 if (retval != NO_ERROR) {
181                         free(mptr->map_attrs);
182                         mptr->map_attrs = NULL;
183                         return;
184                 }
185
186                 /*
187                  * Set flags on first page and check for attribute
188                  * consistency on subsequent pages
189                  */
190                 if (pg == 0) {
191                         *(arm_phys_attrs_t *)(mptr->map_attrs) = attr;
192                 } else if (!arm_mmu_compare_attrs(mptr->map_attrs, &attr)) {
193                         dprintf(CRITICAL, "%s: attribute inconsistency\n",
194                                 __func__);
195                         attr.physaddr = INVALID_PHYSADDR;
196                 }
197                 *pagelist = attr.physaddr;
198                 vaddr += PAGE_SIZE;
199         }
200 }
201
202 #endif // ARM_WITH_MMU