pmap_machdep.h revision 1.10 1 /* $NetBSD: pmap_machdep.h,v 1.10 2025/10/09 06:18:38 skrll Exp $ */
2
3 /*-
4 * Copyright (c) 2022 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Nick Hudson
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #ifndef _AARCH64_PMAP_MACHDEP_H_
33 #define _AARCH64_PMAP_MACHDEP_H_
34
35 #include <arm/cpufunc.h>
36
37 #define PMAP_HWPAGEWALKER 1
38
39 #define PMAP_PDETABSIZE (PAGE_SIZE / sizeof(pd_entry_t))
40 #define PMAP_SEGTABSIZE NSEGPG
41
42 #define PMAP_INVALID_PDETAB_ADDRESS ((pmap_pdetab_t *)(VM_MIN_KERNEL_ADDRESS - PAGE_SIZE))
43 #define PMAP_INVALID_SEGTAB_ADDRESS ((pmap_segtab_t *)(VM_MIN_KERNEL_ADDRESS - PAGE_SIZE))
44
45 #define NPTEPG (PAGE_SIZE / sizeof(pt_entry_t))
46 #define NPDEPG (PAGE_SIZE / sizeof(pd_entry_t))
47
48 #define PTPSHIFT 3
49 #define PTPLENGTH (PGSHIFT - PTPSHIFT)
50 #define SEGSHIFT (PGSHIFT + PTPLENGTH) /* LOG2(NBSEG) */
51
52 #define NBSEG (1 << SEGSHIFT) /* bytes/segment */
53 #define SEGOFSET (NBSEG - 1) /* byte offset into segment */
54
55 #define SEGLENGTH (PGSHIFT - 3)
56
57 #define XSEGSHIFT (SEGSHIFT + SEGLENGTH + SEGLENGTH)
58 /* LOG2(NBXSEG) */
59
60 #define NBXSEG (1UL << XSEGSHIFT) /* bytes/xsegment */
61 #define XSEGOFSET (NBXSEG - 1) /* byte offset into xsegment */
62 #define XSEGLENGTH (PGSHIFT - 3)
63 #define NXSEGPG (1 << XSEGLENGTH)
64 #define NSEGPG (1 << SEGLENGTH)
65
66
67 #ifndef __BSD_PTENTRY_T__
68 #define __BSD_PTENTRY_T__
69 #define PRIxPTE PRIx64
70 #endif /* __BSD_PTENTRY_T__ */
71
72 #define KERNEL_PID 0
73
74 #define __HAVE_PMAP_PV_TRACK
75 #define __HAVE_PMAP_MD
76
77 /* XXX temporary */
78 #define __HAVE_UNLOCKED_PMAP
79
80 #define PMAP_PAGE_INIT(pp) \
81 do { \
82 (pp)->pp_md.mdpg_first.pv_next = NULL; \
83 (pp)->pp_md.mdpg_first.pv_pmap = NULL; \
84 (pp)->pp_md.mdpg_first.pv_va = 0; \
85 (pp)->pp_md.mdpg_attrs = 0; \
86 VM_PAGEMD_PVLIST_LOCK_INIT(&(pp)->pp_md); \
87 } while (/* CONSTCOND */ 0)
88
89 struct pmap_md {
90 paddr_t pmd_l0_pa;
91 };
92
93 #define pm_l0_pa pm_md.pmd_l0_pa
94
95 void pmap_md_pdetab_init(struct pmap *);
96 void pmap_md_pdetab_fini(struct pmap *);
97
98 vaddr_t pmap_md_map_poolpage(paddr_t, size_t);
99 paddr_t pmap_md_unmap_poolpage(vaddr_t, size_t);
100
101 struct vm_page *
102 pmap_md_alloc_poolpage(int);
103
104 bool pmap_md_direct_mapped_vaddr_p(vaddr_t);
105 paddr_t pmap_md_direct_mapped_vaddr_to_paddr(vaddr_t);
106 vaddr_t pmap_md_direct_map_paddr(paddr_t);
107 bool pmap_md_io_vaddr_p(vaddr_t);
108
109 void pmap_md_activate_efirt(void);
110 void pmap_md_deactivate_efirt(void);
111
112 void pmap_icache_sync_range(pmap_t, vaddr_t, vaddr_t);
113
114 vsize_t pmap_kenter_range(vaddr_t, paddr_t, vsize_t, vm_prot_t, u_int flags);
115
116 #include <uvm/pmap/vmpagemd.h>
117 #include <uvm/pmap/pmap.h>
118 #include <uvm/pmap/pmap_pvt.h>
119 #include <uvm/pmap/pmap_tlb.h>
120 #include <uvm/pmap/pmap_synci.h>
121 #include <uvm/pmap/tlb.h>
122
123 #include <uvm/uvm_page.h>
124
125 #define POOL_VTOPHYS(va) vtophys((vaddr_t)(va))
126
127 struct pmap_page {
128 struct vm_page_md pp_md;
129 };
130
131 #define PMAP_PAGE_TO_MD(ppage) (&((ppage)->pp_md))
132
133 #define PVLIST_EMPTY_P(pg) VM_PAGEMD_PVLIST_EMPTY_P(VM_PAGE_TO_MD(pg))
134
135 #define LX_BLKPAG_OS_MODIFIED LX_BLKPAG_OS_0
136
137 #define PMAP_PTE_OS0 "modified"
138 #define PMAP_PTE_OS1 "(unk)"
139
140 static inline paddr_t
141 pmap_l0pa(struct pmap *pm)
142 {
143 return pm->pm_l0_pa;
144 }
145
146 #if defined(__PMAP_PRIVATE)
147
148 #include <uvm/uvm_physseg.h>
149 struct vm_page_md;
150
151 void pmap_md_icache_sync_all(void);
152 void pmap_md_icache_sync_range_index(vaddr_t, vsize_t);
153 void pmap_md_page_syncicache(struct vm_page_md *, const kcpuset_t *);
154 bool pmap_md_vca_add(struct vm_page_md *, vaddr_t, pt_entry_t *);
155 void pmap_md_vca_clean(struct vm_page_md *, int);
156 void pmap_md_vca_remove(struct vm_page_md *, vaddr_t, bool, bool);
157 bool pmap_md_ok_to_steal_p(const uvm_physseg_t, size_t);
158
159 void pmap_md_xtab_activate(pmap_t, struct lwp *);
160 void pmap_md_xtab_deactivate(pmap_t);
161
162 vaddr_t pmap_md_direct_map_paddr(paddr_t);
163
164
165 #ifdef MULTIPROCESSOR
166 #define PMAP_NO_PV_UNCACHED
167 #endif
168
169 static inline void
170 pmap_md_init(void)
171 {
172 // nothing
173 }
174
175
176 static inline bool
177 pmap_md_tlb_check_entry(void *ctx, vaddr_t va, tlb_asid_t asid, pt_entry_t pte)
178 {
179 // TLB not walked and so not called.
180 return false;
181 }
182
183
184 static inline bool
185 pmap_md_virtual_cache_aliasing_p(void)
186 {
187 return false;
188 }
189
190
191 static inline vsize_t
192 pmap_md_cache_prefer_mask(void)
193 {
194 return 0;
195 }
196
197
198 static inline pt_entry_t *
199 pmap_md_nptep(pt_entry_t *ptep)
200 {
201
202 return ptep + 1;
203 }
204
205
206 static __inline paddr_t
207 pte_to_paddr(pt_entry_t pte)
208 {
209
210 return l3pte_pa(pte);
211 }
212
213
214 static inline bool
215 pte_valid_p(pt_entry_t pte)
216 {
217
218 return l3pte_valid(pte);
219 }
220
221
222 static inline void
223 pmap_md_clean_page(struct vm_page_md *md, bool is_src)
224 {
225 }
226
227
228 static inline bool
229 pte_modified_p(pt_entry_t pte)
230 {
231
232 return (pte & LX_BLKPAG_OS_MODIFIED) != 0;
233 }
234
235
236 static inline bool
237 pte_wired_p(pt_entry_t pte)
238 {
239
240 return (pte & LX_BLKPAG_OS_WIRED) != 0;
241 }
242
243
244 static inline pt_entry_t
245 pte_wire_entry(pt_entry_t pte)
246 {
247
248 return pte | LX_BLKPAG_OS_WIRED;
249 }
250
251
252 static inline pt_entry_t
253 pte_unwire_entry(pt_entry_t pte)
254 {
255
256 return pte & ~LX_BLKPAG_OS_WIRED;
257 }
258
259
260 static inline uint64_t
261 pte_value(pt_entry_t pte)
262 {
263
264 return pte;
265 }
266
267 static inline bool
268 pte_cached_p(pt_entry_t pte)
269 {
270
271 return ((pte & LX_BLKPAG_ATTR_MASK) == LX_BLKPAG_ATTR_NORMAL_WB);
272 }
273
274 static inline bool
275 pte_deferred_exec_p(pt_entry_t pte)
276 {
277
278 return false;
279 }
280
281 static inline pt_entry_t
282 pte_nv_entry(bool kernel_p)
283 {
284
285 /* Not valid entry */
286 return kernel_p ? 0 : 0;
287 }
288
289 static inline pt_entry_t
290 pte_prot_downgrade(pt_entry_t pte, vm_prot_t prot)
291 {
292
293 return (pte & ~LX_BLKPAG_AP)
294 | (((prot) & (VM_PROT_READ | VM_PROT_WRITE)) == VM_PROT_READ ? LX_BLKPAG_AP_RO : LX_BLKPAG_AP_RW);
295 }
296
297 static inline pt_entry_t
298 pte_prot_nowrite(pt_entry_t pte)
299 {
300
301 return pte & ~LX_BLKPAG_AF;
302 }
303
304 static inline pt_entry_t
305 pte_cached_change(pt_entry_t pte, bool cached)
306 {
307 pte &= ~LX_BLKPAG_ATTR_MASK;
308 pte |= (cached ? LX_BLKPAG_ATTR_NORMAL_WB : LX_BLKPAG_ATTR_NORMAL_NC);
309
310 return pte;
311 }
312
313 static inline void
314 pte_set(pt_entry_t *ptep, pt_entry_t pte)
315 {
316
317 *ptep = pte;
318 dsb(ishst);
319 /*
320 * if this mapping is going to be used by userland then the eret *can*
321 * act as the isb, but might not (apple m1).
322 *
323 * if this mapping is kernel then the isb is always needed (for some
324 * micro-architectures)
325 */
326
327 isb();
328 }
329
330 static inline pd_entry_t
331 pte_invalid_pde(void)
332 {
333
334 return 0;
335 }
336
337
338 static inline pd_entry_t
339 pte_pde_pdetab(paddr_t pa, bool kernel_p)
340 {
341
342 return LX_VALID | LX_TYPE_TBL | (kernel_p ? 0 : LX_BLKPAG_NG) | pa;
343 }
344
345
346 static inline pd_entry_t
347 pte_pde_ptpage(paddr_t pa, bool kernel_p)
348 {
349
350 return LX_VALID | LX_TYPE_TBL | (kernel_p ? 0 : LX_BLKPAG_NG) | pa;
351 }
352
353
354 static inline bool
355 pte_pde_valid_p(pd_entry_t pde)
356 {
357
358 return lxpde_valid(pde);
359 }
360
361
362 static inline paddr_t
363 pte_pde_to_paddr(pd_entry_t pde)
364 {
365
366 return lxpde_pa(pde);
367 }
368
369
370 static inline pd_entry_t
371 pte_pde_cas(pd_entry_t *pdep, pd_entry_t opde, pt_entry_t npde)
372 {
373 #ifdef MULTIPROCESSOR
374 opde = atomic_cas_64(pdep, opde, npde);
375 #else
376 *pdep = npde;
377 #endif
378 return opde;
379 }
380
381
382 static inline void
383 pte_pde_set(pd_entry_t *pdep, pd_entry_t npde)
384 {
385
386 *pdep = npde;
387 }
388
389
390 static inline pt_entry_t
391 pte_memattr(u_int flags)
392 {
393
394 switch (flags & (PMAP_DEV_MASK | PMAP_CACHE_MASK)) {
395 case PMAP_DEV_NP ... PMAP_DEV_NP | PMAP_CACHE_MASK:
396 /* Device-nGnRnE */
397 return LX_BLKPAG_ATTR_DEVICE_MEM_NP;
398 case PMAP_DEV ... PMAP_DEV | PMAP_CACHE_MASK:
399 /* Device-nGnRE */
400 return LX_BLKPAG_ATTR_DEVICE_MEM;
401 case PMAP_NOCACHE:
402 case PMAP_NOCACHE_OVR:
403 case PMAP_WRITE_COMBINE:
404 /* only no-cache */
405 return LX_BLKPAG_ATTR_NORMAL_NC;
406 case PMAP_WRITE_BACK:
407 case 0:
408 default:
409 return LX_BLKPAG_ATTR_NORMAL_WB;
410 }
411 }
412
413
414 static inline pt_entry_t
415 pte_make_kenter_pa(paddr_t pa, struct vm_page_md *mdpg, vm_prot_t prot,
416 u_int flags)
417 {
418 KASSERTMSG((pa & ~L3_PAG_OA) == 0, "pa %" PRIxPADDR, pa);
419
420 pt_entry_t pte = pa
421 | LX_VALID
422 #ifdef MULTIPROCESSOR
423 | LX_BLKPAG_SH_IS
424 #endif
425 | L3_TYPE_PAG
426 | LX_BLKPAG_AF
427 | LX_BLKPAG_UXN | LX_BLKPAG_PXN
428 | (((prot) & (VM_PROT_READ | VM_PROT_WRITE)) == VM_PROT_READ ? LX_BLKPAG_AP_RO : LX_BLKPAG_AP_RW)
429 | LX_BLKPAG_OS_WIRED;
430
431 if (prot & VM_PROT_EXECUTE)
432 pte &= ~LX_BLKPAG_PXN;
433
434 pte &= ~LX_BLKPAG_ATTR_MASK;
435 pte |= pte_memattr(flags);
436
437 return pte;
438 }
439
440
441 #if defined(EFI_RUNTIME)
442 static inline pt_entry_t
443 pte_make_enter_efirt(paddr_t pa, vm_prot_t prot, u_int flags)
444 {
445 KASSERTMSG((pa & ~L3_PAG_OA) == 0, "pa %" PRIxPADDR, pa);
446
447 pt_entry_t npte = pa
448 | LX_VALID
449 #ifdef MULTIPROCESSOR
450 | LX_BLKPAG_SH_IS
451 #endif
452 | L3_TYPE_PAG
453 | LX_BLKPAG_AF
454 | LX_BLKPAG_NG /* | LX_BLKPAG_APUSER */
455 | LX_BLKPAG_UXN | LX_BLKPAG_PXN
456 | (((prot) & (VM_PROT_READ | VM_PROT_WRITE)) == VM_PROT_READ ? LX_BLKPAG_AP_RO : LX_BLKPAG_AP_RW);
457
458 if (prot & VM_PROT_EXECUTE)
459 npte &= ~LX_BLKPAG_PXN;
460
461 npte &= ~LX_BLKPAG_ATTR_MASK;
462 npte |= pte_memattr(flags);
463
464 return npte;
465 }
466 #endif
467
468
469 static inline pt_entry_t
470 pte_make_enter(paddr_t pa, const struct vm_page_md *mdpg, vm_prot_t prot,
471 u_int flags, bool is_kernel_pmap_p)
472 {
473 KASSERTMSG((pa & ~L3_PAG_OA) == 0, "pa %" PRIxPADDR, pa);
474
475 pt_entry_t npte = pa
476 | LX_VALID
477 #ifdef MULTIPROCESSOR
478 | LX_BLKPAG_SH_IS
479 #endif
480 | L3_TYPE_PAG
481 | LX_BLKPAG_UXN | LX_BLKPAG_PXN
482 | (((prot) & (VM_PROT_READ | VM_PROT_WRITE)) == VM_PROT_READ ? LX_BLKPAG_AP_RO : LX_BLKPAG_AP_RW);
483
484 if ((prot & VM_PROT_WRITE) != 0 &&
485 ((flags & VM_PROT_WRITE) != 0 || VM_PAGEMD_MODIFIED_P(mdpg))) {
486 /*
487 * This is a writable mapping, and the page's mod state
488 * indicates it has already been modified. No need for
489 * modified emulation.
490 */
491 npte |= LX_BLKPAG_AF;
492 } else if ((flags & VM_PROT_ALL) || VM_PAGEMD_REFERENCED_P(mdpg)) {
493 /*
494 * - The access type indicates that we don't need to do
495 * referenced emulation.
496 * OR
497 * - The physical page has already been referenced so no need
498 * to re-do referenced emulation here.
499 */
500 npte |= LX_BLKPAG_AF;
501 }
502
503 if (prot & VM_PROT_EXECUTE)
504 npte &= (is_kernel_pmap_p ? ~LX_BLKPAG_PXN : ~LX_BLKPAG_UXN);
505
506 npte &= ~LX_BLKPAG_ATTR_MASK;
507 npte |= pte_memattr(flags);
508
509 /*
510 * Make sure userland mappings get the right permissions
511 */
512 if (!is_kernel_pmap_p) {
513 npte |= LX_BLKPAG_NG | LX_BLKPAG_APUSER;
514 }
515
516 return npte;
517 }
518 #endif /* __PMAP_PRIVATE */
519
520 #endif /* _AARCH64_PMAP_MACHDEP_H_ */
521
522