1 /*-
2 * Copyright (c) 2004 Marcel Moolenaar
3 * Copyright (c) 2001 Doug Rabson
4 * Copyright (c) 2016 The FreeBSD Foundation
5 * Copyright (c) 2017 Andrew Turner
6 * All rights reserved.
7 *
8 * Portions of this software were developed by Konstantin Belousov
9 * under sponsorship from the FreeBSD Foundation.
10 *
11 * This software was developed by SRI International and the University of
12 * Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-10-C-0237
13 * ("CTSRD"), as part of the DARPA CRASH research programme.
14 *
15 * Redistribution and use in source and binary forms, with or without
16 * modification, are permitted provided that the following conditions
17 * are met:
18 * 1. Redistributions of source code must retain the above copyright
19 * notice, this list of conditions and the following disclaimer.
20 * 2. Redistributions in binary form must reproduce the above copyright
21 * notice, this list of conditions and the following disclaimer in the
22 * documentation and/or other materials provided with the distribution.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 */
36
37 #include <sys/cdefs.h>
38 __FBSDID("$FreeBSD$");
39
40 #include <sys/param.h>
41 #include <sys/efi.h>
42 #include <sys/kernel.h>
43 #include <sys/linker.h>
44 #include <sys/lock.h>
45 #include <sys/mutex.h>
46 #include <sys/proc.h>
47 #include <sys/rwlock.h>
48 #include <sys/systm.h>
49 #include <sys/vmmeter.h>
50
51 #include <machine/metadata.h>
52 #include <machine/pcb.h>
53 #include <machine/pte.h>
54 #include <machine/vfp.h>
55 #include <machine/vmparam.h>
56
57 #include <vm/vm.h>
58 #include <vm/pmap.h>
59 #include <vm/vm_map.h>
60 #include <vm/vm_object.h>
61 #include <vm/vm_page.h>
62 #include <vm/vm_pager.h>
63
64 static vm_object_t obj_1t1_pt;
65 static vm_page_t efi_l0_page;
66 static pd_entry_t *efi_l0;
67 static vm_pindex_t efi_1t1_idx;
68
69 void
efi_destroy_1t1_map(void)70 efi_destroy_1t1_map(void)
71 {
72 vm_page_t m;
73
74 if (obj_1t1_pt != NULL) {
75 VM_OBJECT_RLOCK(obj_1t1_pt);
76 TAILQ_FOREACH(m, &obj_1t1_pt->memq, listq)
77 m->wire_count = 0;
78 vm_wire_sub(obj_1t1_pt->resident_page_count);
79 VM_OBJECT_RUNLOCK(obj_1t1_pt);
80 vm_object_deallocate(obj_1t1_pt);
81 }
82
83 obj_1t1_pt = NULL;
84 efi_l0 = NULL;
85 efi_l0_page = NULL;
86 }
87
88 static vm_page_t
efi_1t1_page(void)89 efi_1t1_page(void)
90 {
91
92 return (vm_page_grab(obj_1t1_pt, efi_1t1_idx++, VM_ALLOC_NOBUSY |
93 VM_ALLOC_WIRED | VM_ALLOC_ZERO));
94 }
95
96 static pt_entry_t *
efi_1t1_l3(vm_offset_t va)97 efi_1t1_l3(vm_offset_t va)
98 {
99 pd_entry_t *l0, *l1, *l2;
100 pt_entry_t *l3;
101 vm_pindex_t l0_idx, l1_idx, l2_idx;
102 vm_page_t m;
103 vm_paddr_t mphys;
104
105 l0_idx = pmap_l0_index(va);
106 l0 = &efi_l0[l0_idx];
107 if (*l0 == 0) {
108 m = efi_1t1_page();
109 mphys = VM_PAGE_TO_PHYS(m);
110 *l0 = mphys | L0_TABLE;
111 } else {
112 mphys = *l0 & ~ATTR_MASK;
113 }
114
115 l1 = (pd_entry_t *)PHYS_TO_DMAP(mphys);
116 l1_idx = pmap_l1_index(va);
117 l1 += l1_idx;
118 if (*l1 == 0) {
119 m = efi_1t1_page();
120 mphys = VM_PAGE_TO_PHYS(m);
121 *l1 = mphys | L1_TABLE;
122 } else {
123 mphys = *l1 & ~ATTR_MASK;
124 }
125
126 l2 = (pd_entry_t *)PHYS_TO_DMAP(mphys);
127 l2_idx = pmap_l2_index(va);
128 l2 += l2_idx;
129 if (*l2 == 0) {
130 m = efi_1t1_page();
131 mphys = VM_PAGE_TO_PHYS(m);
132 *l2 = mphys | L2_TABLE;
133 } else {
134 mphys = *l2 & ~ATTR_MASK;
135 }
136
137 l3 = (pt_entry_t *)PHYS_TO_DMAP(mphys);
138 l3 += pmap_l3_index(va);
139 KASSERT(*l3 == 0, ("%s: Already mapped: va %#jx *pt %#jx", __func__,
140 va, *l3));
141
142 return (l3);
143 }
144
145 /*
146 * Map a physical address from EFI runtime space into KVA space. Returns 0 to
147 * indicate a failed mapping so that the caller may handle error.
148 */
149 vm_offset_t
efi_phys_to_kva(vm_paddr_t paddr)150 efi_phys_to_kva(vm_paddr_t paddr)
151 {
152
153 if (!PHYS_IN_DMAP(paddr))
154 return (0);
155 return (PHYS_TO_DMAP(paddr));
156 }
157
158 /*
159 * Create the 1:1 virtual to physical map for EFI
160 */
161 bool
efi_create_1t1_map(struct efi_md * map,int ndesc,int descsz)162 efi_create_1t1_map(struct efi_md *map, int ndesc, int descsz)
163 {
164 struct efi_md *p;
165 pt_entry_t *l3, l3_attr;
166 vm_offset_t va;
167 uint64_t idx;
168 int i, mode;
169
170 obj_1t1_pt = vm_pager_allocate(OBJT_PHYS, NULL, L0_ENTRIES +
171 L0_ENTRIES * Ln_ENTRIES + L0_ENTRIES * Ln_ENTRIES * Ln_ENTRIES +
172 L0_ENTRIES * Ln_ENTRIES * Ln_ENTRIES * Ln_ENTRIES,
173 VM_PROT_ALL, 0, NULL);
174 VM_OBJECT_WLOCK(obj_1t1_pt);
175 efi_1t1_idx = 0;
176 efi_l0_page = efi_1t1_page();
177 VM_OBJECT_WUNLOCK(obj_1t1_pt);
178 efi_l0 = (pd_entry_t *)PHYS_TO_DMAP(VM_PAGE_TO_PHYS(efi_l0_page));
179 bzero(efi_l0, L0_ENTRIES * sizeof(*efi_l0));
180
181 for (i = 0, p = map; i < ndesc; i++, p = efi_next_descriptor(p,
182 descsz)) {
183 if ((p->md_attr & EFI_MD_ATTR_RT) == 0)
184 continue;
185 if (p->md_virt != NULL && (uint64_t)p->md_virt != p->md_phys) {
186 if (bootverbose)
187 printf("EFI Runtime entry %d is mapped\n", i);
188 goto fail;
189 }
190 if ((p->md_phys & EFI_PAGE_MASK) != 0) {
191 if (bootverbose)
192 printf("EFI Runtime entry %d is not aligned\n",
193 i);
194 goto fail;
195 }
196 if (p->md_phys + p->md_pages * EFI_PAGE_SIZE < p->md_phys ||
197 p->md_phys + p->md_pages * EFI_PAGE_SIZE >=
198 VM_MAXUSER_ADDRESS) {
199 printf("EFI Runtime entry %d is not in mappable for RT:"
200 "base %#016jx %#jx pages\n",
201 i, (uintmax_t)p->md_phys,
202 (uintmax_t)p->md_pages);
203 goto fail;
204 }
205 if ((p->md_attr & EFI_MD_ATTR_WB) != 0)
206 mode = VM_MEMATTR_WRITE_BACK;
207 else if ((p->md_attr & EFI_MD_ATTR_WT) != 0)
208 mode = VM_MEMATTR_WRITE_THROUGH;
209 else if ((p->md_attr & EFI_MD_ATTR_WC) != 0)
210 mode = VM_MEMATTR_WRITE_COMBINING;
211 else if ((p->md_attr & EFI_MD_ATTR_UC) != 0)
212 mode = VM_MEMATTR_DEVICE;
213 else {
214 if (bootverbose)
215 printf("EFI Runtime entry %d mapping "
216 "attributes unsupported\n", i);
217 mode = VM_MEMATTR_UNCACHEABLE;
218 }
219
220 printf("MAP %lx mode %x pages %lu\n", p->md_phys, mode, p->md_pages);
221
222 l3_attr = ATTR_DEFAULT | ATTR_IDX(mode) | ATTR_AP(ATTR_AP_RW) |
223 L3_PAGE;
224 if (mode == VM_MEMATTR_DEVICE)
225 l3_attr |= ATTR_UXN | ATTR_PXN;
226
227 VM_OBJECT_WLOCK(obj_1t1_pt);
228 for (va = p->md_phys, idx = 0; idx < p->md_pages; idx++,
229 va += PAGE_SIZE) {
230 l3 = efi_1t1_l3(va);
231 *l3 = va | l3_attr;
232 }
233 VM_OBJECT_WUNLOCK(obj_1t1_pt);
234 }
235
236 return (true);
237 fail:
238 efi_destroy_1t1_map();
239 return (false);
240 }
241
242 int
efi_arch_enter(void)243 efi_arch_enter(void)
244 {
245
246 __asm __volatile(
247 "msr ttbr0_el1, %0 \n"
248 "isb \n"
249 "dsb ishst \n"
250 "tlbi vmalle1is \n"
251 "dsb ish \n"
252 "isb \n"
253 : : "r"(VM_PAGE_TO_PHYS(efi_l0_page)));
254
255 return (0);
256 }
257
258 void
efi_arch_leave(void)259 efi_arch_leave(void)
260 {
261 struct thread *td;
262
263 /*
264 * Restore the pcpu pointer. Some UEFI implementations trash it and
265 * we don't store it before calling into them. To fix this we need
266 * to restore it after returning to the kernel context. As reading
267 * curthread will access x18 we need to restore it before loading
268 * the thread pointer.
269 */
270 __asm __volatile(
271 "mrs x18, tpidr_el1 \n"
272 );
273 td = curthread;
274 __asm __volatile(
275 "msr ttbr0_el1, %0 \n"
276 "isb \n"
277 "dsb ishst \n"
278 "tlbi vmalle1is \n"
279 "dsb ish \n"
280 "isb \n"
281 : : "r"(td->td_proc->p_md.md_l0addr));
282 }
283
284 int
efi_rt_arch_call(struct efirt_callinfo * ec)285 efi_rt_arch_call(struct efirt_callinfo *ec)
286 {
287
288 panic("not implemented");
289 }
290