Home | History | Annotate | Line # | Download | only in aarch64
      1 /*	$NetBSD: pmap_machdep.c,v 1.18 2026/06/13 12:12:47 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 #include "opt_arm_debug.h"
     33 #include "opt_efi.h"
     34 #include "opt_multiprocessor.h"
     35 #include "opt_uvmhist.h"
     36 
     37 #define __PMAP_PRIVATE
     38 
     39 #include <sys/cdefs.h>
     40 __KERNEL_RCSID(0, "$NetBSD: pmap_machdep.c,v 1.18 2026/06/13 12:12:47 skrll Exp $");
     41 
     42 #include <sys/param.h>
     43 #include <sys/types.h>
     44 
     45 #include <sys/buf.h>
     46 #include <sys/cpu.h>
     47 #include <sys/kernel.h>
     48 
     49 #include <uvm/uvm.h>
     50 #include <uvm/uvm_page.h>
     51 #include <uvm/pmap/pmap_pvt.h>
     52 
     53 #include <aarch64/cpufunc.h>
     54 
     55 #include <arm/locore.h>
     56 
     57 #ifdef VERBOSE_INIT_ARM
     58 #define VPRINTF(...)	printf(__VA_ARGS__)
     59 #else
     60 #define VPRINTF(...)	__nothing
     61 #endif
     62 
     63 /* Set to LX_BLKPAG_GP if supported. */
     64 uint64_t pmap_attr_gp = 0;
     65 
     66 /*
     67  * Misc variables
     68  */
     69 vaddr_t virtual_avail;
     70 vaddr_t virtual_end;
     71 
     72 PMAP_COUNTER(fixup_referenced, "page reference emulations");
     73 PMAP_COUNTER(fixup_modified, "page modification emulations");
     74 
     75 paddr_t
     76 vtophys(vaddr_t va)
     77 {
     78 	paddr_t pa;
     79 
     80 	if (pmap_extract(pmap_kernel(), va, &pa) == false)
     81 		return 0;
     82 	return pa;
     83 }
     84 
     85 bool
     86 pmap_extract_coherency(pmap_t pm, vaddr_t va, paddr_t *pap, bool *coherentp)
     87 {
     88 	paddr_t pa;
     89 	bool coherency = false;
     90 
     91 	if (pm == pmap_kernel()) {
     92 		if (pmap_md_direct_mapped_vaddr_p(va)) {
     93 			pa = pmap_md_direct_mapped_vaddr_to_paddr(va);
     94 			goto done;
     95 		}
     96 		if (pmap_md_io_vaddr_p(va))
     97 			panic("pmap_extract: io address %#"PRIxVADDR"", va);
     98 
     99 		if (va >= pmap_limits.virtual_end)
    100 			panic("%s: illegal kernel mapped address %#"PRIxVADDR,
    101 			    __func__, va);
    102 	}
    103 
    104 	kpreempt_disable();
    105 	const pt_entry_t * const ptep = pmap_pte_lookup(pm, va);
    106 	pt_entry_t pte;
    107 
    108 	if (ptep == NULL || !pte_valid_p(pte = *ptep)) {
    109 		kpreempt_enable();
    110 		return false;
    111 	}
    112 	kpreempt_enable();
    113 
    114 	pa = pte_to_paddr(pte) | (va & PGOFSET);
    115 
    116 	switch (pte & LX_BLKPAG_ATTR_MASK) {
    117 	case LX_BLKPAG_ATTR_NORMAL_NC:
    118 	case LX_BLKPAG_ATTR_DEVICE_MEM:
    119 	case LX_BLKPAG_ATTR_DEVICE_MEM_NP:
    120 		coherency = true;
    121 		break;
    122 	}
    123 
    124  done:
    125 	if (pap != NULL) {
    126 		*pap = pa;
    127 	}
    128 	if (coherentp != NULL) {
    129 		*coherentp = coherency;
    130 	}
    131 	return true;
    132 }
    133 
    134 bool
    135 pmap_fault_fixup(pmap_t pm, vaddr_t va, vm_prot_t ftype, bool user)
    136 {
    137 	UVMHIST_FUNC(__func__); UVMHIST_CALLED(pmaphist);
    138 
    139 	KASSERT(!user || (pm != pmap_kernel()));
    140 
    141 	kpreempt_disable();
    142 
    143 //	struct cpu_info * const ci = curcpu();
    144 	struct pmap_asid_info * const pai = PMAP_PAI(pm, cpu_tlb_info(ci));
    145 
    146 	UVMHIST_LOG(pmaphist, " pm=%#jx, va=%#jx, ftype=%#jx, user=%jd",
    147 	    (uintptr_t)pm, va, ftype, user);
    148 	UVMHIST_LOG(pmaphist, " ti=%#jx pai=%#jx asid=%#jx",
    149 	    (uintptr_t)cpu_tlb_info(curcpu()),
    150 	    (uintptr_t)pai, (uintptr_t)pai->pai_asid, 0);
    151 
    152 	bool fixed = false;
    153 	pt_entry_t * const ptep = pmap_pte_lookup(pm, va);
    154 	if (ptep == NULL) {
    155 		UVMHIST_LOG(pmaphist, "... no ptep", 0, 0, 0, 0);
    156 		goto done;
    157 	}
    158 
    159 	const pt_entry_t opte = atomic_load_relaxed(ptep);
    160 	if (!l3pte_valid(opte)) {
    161 		UVMHIST_LOG(pmaphist, "invalid pte: %016llx: va=%016lx",
    162 		    opte, va, 0, 0);
    163 		goto done;
    164 	}
    165 
    166 	const paddr_t pa = l3pte_pa(opte);
    167 	struct vm_page * const pg = PHYS_TO_VM_PAGE(pa);
    168 	if (pg == NULL) {
    169 		UVMHIST_LOG(pmaphist, "pg not found: va=%016lx", va, 0, 0, 0);
    170 		goto done;
    171 	}
    172 
    173 	struct vm_page_md * const mdpg = VM_PAGE_TO_MD(pg);
    174 	UVMHIST_LOG(pmaphist, " pg=%#jx, opte=%#jx, ptep=%#jx", (uintptr_t)pg,
    175 	    opte, (uintptr_t)ptep, 0);
    176 
    177 	if ((ftype & VM_PROT_WRITE) && (opte & LX_BLKPAG_OS_MODEMUL) != 0) {
    178 		/*
    179 		 * This is "page modified" emulation...
    180 		 */
    181 		pmap_page_set_attributes(mdpg, VM_PAGEMD_MODIFIED | VM_PAGEMD_REFERENCED);
    182 
    183                 /*
    184 		 * Enable write permissions for the page by setting the Access
    185 		 * Flag, marking the page as writeable. The PTE being writeable
    186 		 * and OS_MODEMUL indicates it's been modified.
    187 		 */
    188 		const pt_entry_t npte =
    189 		    (opte & ~LX_BLKPAG_AP) |
    190 		    LX_BLKPAG_AF |
    191 		    LX_BLKPAG_AP_RW;
    192 		atomic_swap_64(ptep, npte);
    193 		// tlb_invalidate_addr does dsb(ishst)
    194 		tlb_invalidate_addr(va, pai->pai_asid);
    195 		fixed = true;
    196 
    197 		PMAP_COUNT(fixup_modified);
    198 
    199 		UVMHIST_LOG(pmaphist, " <-- done (mod emul: changed pte "
    200 		    "from %#jx to %#jx)", opte, npte, 0, 0);
    201 	} else if ((ftype & VM_PROT_READ) && (opte & LX_BLKPAG_AP) == LX_BLKPAG_AP_RO) {
    202 		/*
    203 		 * This looks like a good candidate for "page referenced"
    204 		 * emulation.
    205 		 */
    206 
    207 		KASSERT((opte & LX_BLKPAG_AF) == 0);
    208 
    209 		pmap_page_set_attributes(mdpg, VM_PAGEMD_REFERENCED);
    210 
    211 		/*
    212 		 * Enable write permissions for the page by setting the Access Flag.
    213 		 */
    214 		const pt_entry_t npte = opte | LX_BLKPAG_AF;
    215 		atomic_swap_64(ptep, npte);
    216 		// tlb_invalidate_addr does dsb(ishst)
    217 		tlb_invalidate_addr(va, pai->pai_asid);
    218 		fixed = true;
    219 
    220 		PMAP_COUNT(fixup_referenced);
    221 
    222 		UVMHIST_LOG(pmaphist, " <-- done (ref emul: changed pte "
    223 		    "from %#jx to %#jx)", opte, npte, 0, 0);
    224 	}
    225 
    226 done:
    227 	kpreempt_enable();
    228 
    229 	return fixed;
    230 }
    231 
    232 
    233 void
    234 pmap_icache_sync_range(pmap_t pm, vaddr_t sva, vaddr_t eva)
    235 {
    236 	UVMHIST_FUNC(__func__);
    237 	UVMHIST_CALLARGS(pmaphist, "pm %#jx sva %#jx eva %#jx",
    238 	   (uintptr_t)pm, sva, eva, 0);
    239 
    240 	KASSERT((sva & PAGE_MASK) == 0);
    241 	KASSERT((eva & PAGE_MASK) == 0);
    242 
    243 	pmap_lock(pm);
    244 
    245 	for (vaddr_t va = sva; va < eva; va += PAGE_SIZE) {
    246 		pt_entry_t * const ptep = pmap_pte_lookup(pm, va);
    247 		if (ptep == NULL)
    248 			continue;
    249 
    250 		pt_entry_t opte = *ptep;
    251 		if (!l3pte_valid(opte)) {
    252 			UVMHIST_LOG(pmaphist, "invalid pte: %016llx: va=%016lx",
    253 			    opte, va, 0, 0);
    254 			goto done;
    255 		}
    256 
    257 		if (l3pte_readable(opte)) {
    258 			cpu_icache_sync_range(va, PAGE_SIZE);
    259 		} else {
    260 			/*
    261 			 * change to accessible temporarily
    262 			 * to do cpu_icache_sync_range()
    263 			 */
    264 			struct pmap_asid_info * const pai = PMAP_PAI(pm,
    265 			    cpu_tlb_info(ci));
    266 
    267 			atomic_swap_64(ptep, opte | LX_BLKPAG_AF);
    268 			// tlb_invalidate_addr does the dsb(ishst);
    269 			tlb_invalidate_addr(va, pai->pai_asid);
    270 			cpu_icache_sync_range(va, PAGE_SIZE);
    271 			atomic_swap_64(ptep, opte);
    272 			tlb_invalidate_addr(va, pai->pai_asid);
    273 		}
    274 	}
    275 done:
    276 	pmap_unlock(pm);
    277 }
    278 
    279 
    280 struct vm_page *
    281 pmap_md_alloc_poolpage(int flags)
    282 {
    283 
    284 	/*
    285 	 * Any managed page works for us.
    286 	 */
    287 	return uvm_pagealloc(NULL, 0, NULL, flags);
    288 }
    289 
    290 
    291 vaddr_t
    292 pmap_md_map_poolpage(paddr_t pa, size_t len)
    293 {
    294 	struct vm_page * const pg = PHYS_TO_VM_PAGE(pa);
    295 	const vaddr_t va = pmap_md_direct_map_paddr(pa);
    296 	KASSERT(cold || pg != NULL);
    297 
    298 	if (pg != NULL) {
    299 		struct vm_page_md * const mdpg = VM_PAGE_TO_MD(pg);
    300 		const pv_entry_t pv = &mdpg->mdpg_first;
    301 		const vaddr_t last_va = trunc_page(pv->pv_va);
    302 
    303 		KASSERT(len == PAGE_SIZE || last_va == pa);
    304 		KASSERT(pv->pv_pmap == NULL);
    305 		KASSERT(pv->pv_next == NULL);
    306 		KASSERT(!VM_PAGEMD_EXECPAGE_P(mdpg));
    307 
    308 		pv->pv_va = va;
    309 	}
    310 
    311 	return va;
    312 }
    313 
    314 
    315 paddr_t
    316 pmap_md_unmap_poolpage(vaddr_t va, size_t len)
    317 {
    318 	KASSERT(len == PAGE_SIZE);
    319 	KASSERT(pmap_md_direct_mapped_vaddr_p(va));
    320 
    321 	const paddr_t pa = pmap_md_direct_mapped_vaddr_to_paddr(va);
    322 	struct vm_page * const pg = PHYS_TO_VM_PAGE(pa);
    323 
    324 	KASSERT(pg);
    325 	struct vm_page_md * const mdpg = VM_PAGE_TO_MD(pg);
    326 
    327 	KASSERT(!VM_PAGEMD_EXECPAGE_P(mdpg));
    328 
    329 	const pv_entry_t pv = &mdpg->mdpg_first;
    330 
    331 	/* Note last mapped address for future color check */
    332 	pv->pv_va = va;
    333 
    334 	KASSERT(pv->pv_pmap == NULL);
    335 	KASSERT(pv->pv_next == NULL);
    336 
    337 	return pa;
    338 }
    339 
    340 
    341 bool
    342 pmap_md_kernel_vaddr_p(vaddr_t va)
    343 {
    344 	extern char __kernel_text[];
    345 	extern char _end[];
    346 	extern long kernend_extra;
    347 
    348 	const vaddr_t kernstart = trunc_page((vaddr_t)__kernel_text);
    349 	const vaddr_t kernend = round_page((vaddr_t)_end);
    350 
    351 	const vaddr_t fva = L2_TRUNC_BLOCK(kernstart);
    352 	const vaddr_t lva = L2_ROUND_BLOCK(kernend + kernend_extra);
    353 
    354 	if (va >= fva && va < lva) {
    355 		return true;
    356 	}
    357 
    358 	return false;
    359 }
    360 
    361 paddr_t
    362 pmap_md_kernel_vaddr_to_paddr(vaddr_t va)
    363 {
    364 
    365 	if (pmap_md_kernel_vaddr_p(va)) {
    366 		return KERN_VTOPHYS(va);
    367 	}
    368 	panic("%s: va %#" PRIxVADDR " not direct mapped!", __func__, va);
    369 }
    370 
    371 
    372 bool
    373 pmap_md_direct_mapped_vaddr_p(vaddr_t va)
    374 {
    375 	if (!AARCH64_KVA_P(va))
    376 		return false;
    377 
    378 	paddr_t pa = AARCH64_KVA_TO_PA(va);
    379 	if (physical_start <= pa && pa < physical_end)
    380 		return true;
    381 
    382 	return false;
    383 }
    384 
    385 
    386 paddr_t
    387 pmap_md_direct_mapped_vaddr_to_paddr(vaddr_t va)
    388 {
    389 
    390 	return AARCH64_KVA_TO_PA(va);
    391 }
    392 
    393 
    394 vaddr_t
    395 pmap_md_direct_map_paddr(paddr_t pa)
    396 {
    397 
    398 	return AARCH64_PA_TO_KVA(pa);
    399 }
    400 
    401 
    402 bool
    403 pmap_md_io_vaddr_p(vaddr_t va)
    404 {
    405 
    406 	if (pmap_devmap_find_va(va, PAGE_SIZE)) {
    407 		return true;
    408 	}
    409 	return false;
    410 }
    411 
    412 
    413 static void
    414 pmap_md_grow(pmap_pdetab_t *ptb, vaddr_t va, vsize_t vshift,
    415     vsize_t *remaining)
    416 {
    417 	KASSERT((va & (NBSEG - 1)) == 0);
    418 	const vaddr_t pdetab_mask = PMAP_PDETABSIZE - 1;
    419 	const vsize_t vinc = 1UL << vshift;
    420 
    421 	for (size_t i = (va >> vshift) & pdetab_mask;
    422 	    i < PMAP_PDETABSIZE; i++, va += vinc) {
    423 		pd_entry_t * const pde_p =
    424 		    &ptb->pde_pde[(va >> vshift) & pdetab_mask];
    425 
    426 		vaddr_t pdeva;
    427 		if (pte_pde_valid_p(*pde_p)) {
    428 			const paddr_t pa = pte_pde_to_paddr(*pde_p);
    429 			pdeva = pmap_md_direct_map_paddr(pa);
    430 		} else {
    431 			/*
    432 			 * uvm_pageboot_alloc() returns a direct mapped address
    433 			 */
    434 			pdeva = uvm_pageboot_alloc(Ln_TABLE_SIZE);
    435 			paddr_t pdepa = AARCH64_KVA_TO_PA(pdeva);
    436 			*pde_p = pte_pde_pdetab(pdepa, true);
    437 			memset((void *)pdeva, 0, PAGE_SIZE);
    438 		}
    439 
    440 		if (vshift > SEGSHIFT) {
    441 			pmap_md_grow((pmap_pdetab_t *)pdeva, va,
    442 			    vshift - SEGLENGTH, remaining);
    443 		} else {
    444 			if (*remaining > vinc)
    445 				*remaining -= vinc;
    446 			else
    447 				*remaining = 0;
    448 		}
    449 		if (*remaining == 0)
    450 			return;
    451 	}
    452 }
    453 
    454 
    455 void
    456 pmap_bootstrap(vaddr_t vstart, vaddr_t vend)
    457 {
    458 	pmap_t pm = pmap_kernel();
    459 
    460 	/*
    461 	 * Initialise the kernel pmap object
    462 	 */
    463 	virtual_avail = vstart;
    464 	virtual_end = vend;
    465 
    466 	aarch64_tlbi_all();
    467 
    468 	pm->pm_l0_pa = __SHIFTOUT(reg_ttbr1_el1_read(), TTBR_BADDR);
    469 	pm->pm_pdetab = (pmap_pdetab_t *)AARCH64_PA_TO_KVA(pm->pm_l0_pa);
    470 
    471 	VPRINTF("common ");
    472 	pmap_bootstrap_common();
    473 
    474 	VPRINTF("tlb0 ");
    475 	pmap_tlb_info_init(&pmap_tlb0_info);
    476 
    477 #ifdef MULTIPROCESSOR
    478 	VPRINTF("kcpusets ");
    479 
    480 	kcpuset_create(&pm->pm_onproc, true);
    481 	kcpuset_create(&pm->pm_active, true);
    482 	KASSERT(pm->pm_onproc != NULL);
    483 	KASSERT(pm->pm_active != NULL);
    484 	kcpuset_set(pm->pm_onproc, cpu_number());
    485 	kcpuset_set(pm->pm_active, cpu_number());
    486 #endif
    487 
    488 	VPRINTF("nkmempages ");
    489 	/*
    490 	 * Compute the number of pages kmem_arena will have.  This will also
    491 	 * be called by uvm_km_bootstrap later, but that doesn't matter
    492 	 */
    493 	kmeminit_nkmempages();
    494 
    495 	/* Get size of buffer cache and set an upper limit */
    496 	buf_setvalimit((VM_MAX_KERNEL_ADDRESS - VM_MIN_KERNEL_ADDRESS) / 8);
    497 	vsize_t bufsz = buf_memcalc();
    498 	buf_setvalimit(bufsz);
    499 
    500 	vsize_t kvmsize = (VM_PHYS_SIZE + (ubc_nwins << ubc_winshift) +
    501 	    bufsz + 16 * NCARGS + pager_map_size) +
    502 	    /*(maxproc * UPAGES) + */nkmempages * NBPG;
    503 
    504 #ifdef SYSVSHM
    505 	kvmsize += shminfo.shmall;
    506 #endif
    507 
    508 	/* Calculate VA address space and roundup to NBSEG tables */
    509 	kvmsize = roundup(kvmsize, NBSEG);
    510 
    511 	/*
    512 	 * Initialize `FYI' variables.	Note we're relying on
    513 	 * the fact that BSEARCH sorts the vm_physmem[] array
    514 	 * for us.  Must do this before uvm_pageboot_alloc()
    515 	 * can be called.
    516 	 */
    517 	pmap_limits.avail_start = ptoa(uvm_physseg_get_start(uvm_physseg_get_first()));
    518 	pmap_limits.avail_end = ptoa(uvm_physseg_get_end(uvm_physseg_get_last()));
    519 
    520 	/*
    521 	 * Update the naive settings in pmap_limits to the actual KVA range.
    522 	 */
    523 	pmap_limits.virtual_start = vstart;
    524 	pmap_limits.virtual_end = vend;
    525 
    526 	VPRINTF("\nlimits: %" PRIxVADDR " - %" PRIxVADDR "\n", vstart, vend);
    527 
    528 	const vaddr_t kvmstart = vstart;
    529 	pmap_curmaxkvaddr = vstart + kvmsize;
    530 
    531 	VPRINTF("kva   : %" PRIxVADDR " - %" PRIxVADDR "\n", kvmstart,
    532 	    pmap_curmaxkvaddr);
    533 
    534 	pmap_md_grow(pmap_kernel()->pm_pdetab, kvmstart, XSEGSHIFT, &kvmsize);
    535 
    536 #if defined(EFI_RUNTIME)
    537 	vaddr_t efi_l0va = uvm_pageboot_alloc(Ln_TABLE_SIZE);
    538 	KASSERT((efi_l0va & PAGE_MASK) == 0);
    539 
    540 	pmap_t efipm = pmap_efirt();
    541 	efipm->pm_l0_pa = AARCH64_KVA_TO_PA(efi_l0va);
    542 	efipm->pm_pdetab = (pmap_pdetab_t *)efi_l0va;
    543 #endif
    544 
    545 	pool_init(&pmap_pmap_pool, PMAP_SIZE, 0, 0, 0, "pmappl",
    546 	    &pool_allocator_nointr, IPL_NONE);
    547 
    548 	pool_init(&pmap_pv_pool, sizeof(struct pv_entry), 0, 0, 0, "pvpl",
    549 #ifdef KASAN
    550 	    NULL,
    551 #else
    552 	    &pmap_pv_page_allocator,
    553 #endif
    554 	    IPL_NONE);
    555 
    556 	// arm_dcache_align
    557 	pmap_pvlist_lock_init(CACHE_LINE_SIZE);
    558 
    559 	VPRINTF("done\n");
    560 }
    561 
    562 
    563 #if defined(EFI_RUNTIME)
    564 void
    565 pmap_md_activate_efirt(void)
    566 {
    567 	kpreempt_disable();
    568 
    569 //	struct cpu_info * const ci = curcpu();
    570 	struct pmap * const pm = pmap_efirt();
    571 	struct pmap_asid_info * const pai = PMAP_PAI(pm, cpu_tlb_info(ci));
    572 
    573 	pmap_md_asid_activate(pai->pai_asid, pmap_efirt(), NULL);
    574 }
    575 
    576 void
    577 pmap_md_deactivate_efirt(void)
    578 {
    579 	pmap_md_asid_deactivate(pmap_efirt());
    580 
    581 	KASSERT((reg_tcr_el1_read() & TCR_EPD0) != 0);
    582 
    583 	kpreempt_enable();
    584 }
    585 #endif
    586 
    587 
    588 void
    589 pmap_md_pdetab_init(struct pmap *pm)
    590 {
    591 
    592 	KASSERT(pm != NULL);
    593 
    594 	pmap_extract(pmap_kernel(), (vaddr_t)pm->pm_pdetab, &pm->pm_l0_pa);
    595 }
    596 
    597 void
    598 pmap_md_pdetab_fini(struct pmap *pm)
    599 {
    600 
    601 	KASSERT(pm != NULL);
    602 }
    603 
    604 
    605 void
    606 pmap_md_page_syncicache(struct vm_page_md *mdpg, const kcpuset_t *onproc)
    607 {
    608 	UVMHIST_FUNC(__func__); UVMHIST_CALLED(pmaphist);
    609 
    610 	/*
    611 	 * This handles the PIPT case where we can use the direct map
    612 	 * to sync the icache without worrying about aliasing.
    613 	 */
    614 	struct vm_page * const pg = VM_MD_TO_PAGE(mdpg);
    615 	const paddr_t pa = VM_PAGE_TO_PHYS(pg);
    616 	const vaddr_t kva = pmap_md_direct_map_paddr(pa);
    617 	cpu_icache_sync_range(kva, PAGE_SIZE);
    618 }
    619 
    620 
    621 bool
    622 pmap_md_ok_to_steal_p(const uvm_physseg_t bank, size_t npgs)
    623 {
    624 
    625 	return true;
    626 }
    627 
    628 
    629 pd_entry_t *
    630 pmap_l0table(struct pmap *pm)
    631 {
    632 
    633 	return pm->pm_pdetab->pde_pde;
    634 }
    635 
    636 
    637 #define	L1_BLK_MAPPABLE_P(va, pa, size)					\
    638     ((((va) | (pa)) & L1_OFFSET) == 0 && (size) >= L1_SIZE)
    639 
    640 #define	L2_BLK_MAPPABLE_P(va, pa, size)					\
    641     ((((va) | (pa)) & L2_OFFSET) == 0 && (size) >= L2_SIZE)
    642 
    643 
    644 vsize_t
    645 pmap_kenter_range(vaddr_t va, paddr_t pa, vsize_t size,
    646     vm_prot_t prot, u_int flags)
    647 {
    648 	pt_entry_t attr;
    649 	psize_t blocksize;
    650 
    651 	vsize_t resid = round_page(size);
    652 	vsize_t mapped = 0;
    653 
    654 	while (resid > 0) {
    655 		if (L1_BLK_MAPPABLE_P(va, pa, resid)) {
    656 			blocksize = L1_SIZE;
    657 			attr = L1_BLOCK;
    658 		} else if (L2_BLK_MAPPABLE_P(va, pa, resid)) {
    659 			blocksize = L2_SIZE;
    660 			attr = L2_BLOCK;
    661 		} else {
    662 			blocksize = L3_SIZE;
    663 			attr = L3_PAGE;
    664 		}
    665 
    666 		pt_entry_t pte = pte_make_kenter_pa(pa, NULL, prot, flags);
    667 		pte &= ~LX_TYPE;
    668 		attr |= pte;
    669 
    670 		pmapboot_enter(va, pa, blocksize, blocksize, attr, NULL);
    671 
    672 		va += blocksize;
    673 		pa += blocksize;
    674 		resid -= blocksize;
    675 		mapped += blocksize;
    676 	}
    677 
    678 	return mapped;
    679 }
    680 
    681 #ifdef MULTIPROCESSOR
    682 void
    683 pmap_md_tlb_info_attach(struct pmap_tlb_info *ti, struct cpu_info *ci)
    684 {
    685 	/* nothing */
    686 }
    687 #endif /* MULTIPROCESSOR */
    688