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