Home | History | Annotate | Line # | Download | only in sh3
      1 /*	$NetBSD: pmap.c,v 1.94 2021/09/08 12:00:50 rin Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 2002 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by UCHIYAMA Yasushi.
      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 <sys/cdefs.h>
     33 __KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.94 2021/09/08 12:00:50 rin Exp $");
     34 
     35 #include <sys/param.h>
     36 #include <sys/systm.h>
     37 #include <sys/pool.h>
     38 #include <sys/msgbuf.h>
     39 #include <sys/socketvar.h>	/* XXX: for sock_loan_thresh */
     40 
     41 #include <uvm/uvm.h>
     42 #include <uvm/uvm_physseg.h>
     43 
     44 #include <sh3/mmu.h>
     45 #include <sh3/cache.h>
     46 
     47 #ifdef DEBUG
     48 #define	STATIC
     49 #else
     50 #define	STATIC	static
     51 #endif
     52 
     53 #define	__PMAP_PTP_SHIFT	22
     54 #define	__PMAP_PTP_TRUNC(va)						\
     55 	(((va) + (1 << __PMAP_PTP_SHIFT) - 1) & ~((1 << __PMAP_PTP_SHIFT) - 1))
     56 #define	__PMAP_PTP_PG_N		(PAGE_SIZE / sizeof(pt_entry_t))
     57 #define	__PMAP_PTP_INDEX(va)	(((va) >> __PMAP_PTP_SHIFT) & (__PMAP_PTP_N - 1))
     58 #define	__PMAP_PTP_OFSET(va)	((va >> PGSHIFT) & (__PMAP_PTP_PG_N - 1))
     59 
     60 struct pmap __pmap_kernel;
     61 struct pmap *const kernel_pmap_ptr = &__pmap_kernel;
     62 STATIC vaddr_t __pmap_kve;	/* VA of last kernel virtual */
     63 paddr_t avail_start;		/* PA of first available physical page */
     64 paddr_t avail_end;		/* PA of last available physical page */
     65 
     66 /* For the fast tlb miss handler */
     67 pt_entry_t **curptd;		/* p1 va of curlwp->...->pm_ptp */
     68 
     69 /* pmap pool */
     70 STATIC struct pool __pmap_pmap_pool;
     71 
     72 /* pv_entry ops. */
     73 struct pv_entry {
     74 	struct pmap *pv_pmap;
     75 	vaddr_t pv_va;
     76 	SLIST_ENTRY(pv_entry) pv_link;
     77 };
     78 #define	__pmap_pv_alloc()	pool_get(&__pmap_pv_pool, PR_NOWAIT)
     79 #define	__pmap_pv_free(pv)	pool_put(&__pmap_pv_pool, (pv))
     80 STATIC int __pmap_pv_enter(pmap_t, struct vm_page *, vaddr_t);
     81 STATIC void __pmap_pv_remove(pmap_t, struct vm_page *, vaddr_t);
     82 STATIC void *__pmap_pv_page_alloc(struct pool *, int);
     83 STATIC void __pmap_pv_page_free(struct pool *, void *);
     84 STATIC struct pool __pmap_pv_pool;
     85 STATIC struct pool_allocator pmap_pv_page_allocator = {
     86 	__pmap_pv_page_alloc, __pmap_pv_page_free, 0,
     87 };
     88 
     89 /* ASID ops. */
     90 STATIC int __pmap_asid_alloc(void);
     91 STATIC void __pmap_asid_free(int);
     92 STATIC struct {
     93 	uint32_t map[8];
     94 	int hint;	/* hint for next allocation */
     95 } __pmap_asid;
     96 
     97 /* page table entry ops. */
     98 STATIC pt_entry_t *__pmap_pte_alloc(pmap_t, vaddr_t);
     99 
    100 /* pmap_enter util */
    101 STATIC bool __pmap_map_change(pmap_t, vaddr_t, paddr_t, vm_prot_t,
    102     pt_entry_t);
    103 
    104 void
    105 pmap_bootstrap(void)
    106 {
    107 
    108 	/* Steal msgbuf area */
    109 	initmsgbuf((void *)uvm_pageboot_alloc(MSGBUFSIZE), MSGBUFSIZE);
    110 
    111 	avail_start = ptoa(uvm_physseg_get_start(uvm_physseg_get_first()));
    112 	avail_end = ptoa(uvm_physseg_get_end(uvm_physseg_get_last()));
    113 	__pmap_kve = VM_MIN_KERNEL_ADDRESS;
    114 
    115 	pmap_kernel()->pm_refcnt = 1;
    116 	pmap_kernel()->pm_ptp = (pt_entry_t **)uvm_pageboot_alloc(PAGE_SIZE);
    117 	memset(pmap_kernel()->pm_ptp, 0, PAGE_SIZE);
    118 
    119 	/* Enable MMU */
    120 	sh_mmu_start();
    121 	/* Mask all interrupt */
    122 	_cpu_intr_suspend();
    123 	/* Enable exception for P3 access */
    124 	_cpu_exception_resume(0);
    125 }
    126 
    127 vaddr_t
    128 pmap_steal_memory(vsize_t size, vaddr_t *vstart, vaddr_t *vend)
    129 {
    130 	int npage;
    131 	paddr_t pa;
    132 	vaddr_t va;
    133 	uvm_physseg_t bank;
    134 
    135 	KDASSERT(!uvm.page_init_done);
    136 
    137 	size = round_page(size);
    138 	npage = atop(size);
    139 
    140 	for (bank = uvm_physseg_get_first();
    141 	     uvm_physseg_valid_p(bank);
    142 	     bank = uvm_physseg_get_next(bank)) {
    143 		if (npage <= uvm_physseg_get_avail_end(bank)
    144 				- uvm_physseg_get_avail_start(bank))
    145 			break;
    146 	}
    147 
    148 	KDASSERT(uvm_physseg_valid_p(bank));
    149 
    150 	/* Steal pages */
    151 	pa = ptoa(uvm_physseg_get_avail_start(bank));
    152 	uvm_physseg_unplug(atop(pa), npage);
    153 	va = SH3_PHYS_TO_P1SEG(pa);
    154 	memset((void *)va, 0, size);
    155 
    156 	return va;
    157 }
    158 
    159 vaddr_t
    160 pmap_growkernel(vaddr_t maxkvaddr)
    161 {
    162 	int i, n;
    163 
    164 	if (maxkvaddr <= __pmap_kve)
    165 		return __pmap_kve;
    166 
    167 	i = __PMAP_PTP_INDEX(__pmap_kve - VM_MIN_KERNEL_ADDRESS);
    168 	__pmap_kve = __PMAP_PTP_TRUNC(maxkvaddr);
    169 	n = __PMAP_PTP_INDEX(__pmap_kve - VM_MIN_KERNEL_ADDRESS);
    170 
    171 	/* Allocate page table pages */
    172 	for (;i < n; i++) {
    173 		if (__pmap_kernel.pm_ptp[i] != NULL)
    174 			continue;
    175 
    176 		if (uvm.page_init_done) {
    177 			struct vm_page *pg = uvm_pagealloc(NULL, 0, NULL,
    178 			    UVM_PGA_USERESERVE | UVM_PGA_ZERO);
    179 			if (pg == NULL)
    180 				goto error;
    181 			__pmap_kernel.pm_ptp[i] = (pt_entry_t *)
    182 			    SH3_PHYS_TO_P1SEG(VM_PAGE_TO_PHYS(pg));
    183 		} else {
    184 			pt_entry_t *ptp = (pt_entry_t *)
    185 			    uvm_pageboot_alloc(PAGE_SIZE);
    186 			if (ptp == NULL)
    187 				goto error;
    188 			__pmap_kernel.pm_ptp[i] = ptp;
    189 			memset(ptp, 0, PAGE_SIZE);
    190 		}
    191 	}
    192 
    193 	return __pmap_kve;
    194  error:
    195 	panic("%s: out of memory", __func__);
    196 	/* NOTREACHED */
    197 }
    198 
    199 void
    200 pmap_virtual_space(vaddr_t *start, vaddr_t *end)
    201 {
    202 
    203 	*start = VM_MIN_KERNEL_ADDRESS;
    204 	*end = VM_MAX_KERNEL_ADDRESS;
    205 }
    206 
    207 void
    208 pmap_init(void)
    209 {
    210 
    211 	/* Initialize pmap module */
    212 	pool_init(&__pmap_pmap_pool, sizeof(struct pmap), 0, 0, 0, "pmappl",
    213 	    &pool_allocator_nointr, IPL_NONE);
    214 	pool_init(&__pmap_pv_pool, sizeof(struct pv_entry), 0, 0, 0, "pvpl",
    215 	    &pmap_pv_page_allocator, IPL_NONE);
    216 	pool_setlowat(&__pmap_pv_pool, 16);
    217 
    218 #ifdef SH4
    219 	if (SH_HAS_VIRTUAL_ALIAS) {
    220 		/*
    221 		 * XXX
    222 		 * Disable sosend_loan() in src/sys/kern/uipc_socket.c
    223 		 * on SH4 to avoid possible virtual cache aliases and
    224 		 * unnecessary map/unmap thrashing in __pmap_pv_enter().
    225 		 * (also see comments in __pmap_pv_enter())
    226 		 *
    227 		 * Ideally, read only shared mapping won't cause aliases
    228 		 * so __pmap_pv_enter() should handle any shared read only
    229 		 * mappings like ARM pmap.
    230 		 */
    231 		sock_loan_thresh = -1;
    232 	}
    233 #endif
    234 }
    235 
    236 pmap_t
    237 pmap_create(void)
    238 {
    239 	pmap_t pmap;
    240 
    241 	pmap = pool_get(&__pmap_pmap_pool, PR_WAITOK);
    242 	memset(pmap, 0, sizeof(struct pmap));
    243 	pmap->pm_asid = -1;
    244 	pmap->pm_refcnt = 1;
    245 	/* Allocate page table page holder (512 slot) */
    246 	pmap->pm_ptp = (pt_entry_t **)
    247 	    SH3_PHYS_TO_P1SEG(VM_PAGE_TO_PHYS(
    248 		    uvm_pagealloc(NULL, 0, NULL,
    249 			UVM_PGA_USERESERVE | UVM_PGA_ZERO)));
    250 
    251 	return pmap;
    252 }
    253 
    254 void
    255 pmap_destroy(pmap_t pmap)
    256 {
    257 	int i;
    258 
    259 	if (--pmap->pm_refcnt > 0)
    260 		return;
    261 
    262 	/* Deallocate all page table page */
    263 	for (i = 0; i < __PMAP_PTP_N; i++) {
    264 		vaddr_t va = (vaddr_t)pmap->pm_ptp[i];
    265 		if (va == 0)
    266 			continue;
    267 #ifdef DEBUG	/* Check no mapping exists. */
    268 		{
    269 			int j;
    270 			pt_entry_t *pte = (pt_entry_t *)va;
    271 			for (j = 0; j < __PMAP_PTP_PG_N; j++, pte++)
    272 				KDASSERT(*pte == 0);
    273 		}
    274 #endif
    275 		/* Purge cache entry for next use of this page. */
    276 		if (SH_HAS_VIRTUAL_ALIAS)
    277 			sh_dcache_inv_range(va, PAGE_SIZE);
    278 		/* Free page table */
    279 		uvm_pagefree(PHYS_TO_VM_PAGE(SH3_P1SEG_TO_PHYS(va)));
    280 	}
    281 	/* Deallocate page table page holder */
    282 	if (SH_HAS_VIRTUAL_ALIAS)
    283 		sh_dcache_inv_range((vaddr_t)pmap->pm_ptp, PAGE_SIZE);
    284 	uvm_pagefree(PHYS_TO_VM_PAGE(SH3_P1SEG_TO_PHYS((vaddr_t)pmap->pm_ptp)));
    285 
    286 	/* Free ASID */
    287 	__pmap_asid_free(pmap->pm_asid);
    288 
    289 	pool_put(&__pmap_pmap_pool, pmap);
    290 }
    291 
    292 void
    293 pmap_reference(pmap_t pmap)
    294 {
    295 
    296 	pmap->pm_refcnt++;
    297 }
    298 
    299 void
    300 pmap_activate(struct lwp *l)
    301 {
    302 	pmap_t pmap = l->l_proc->p_vmspace->vm_map.pmap;
    303 
    304 	if (pmap->pm_asid == -1)
    305 		pmap->pm_asid = __pmap_asid_alloc();
    306 
    307 	KDASSERT(pmap->pm_asid >=0 && pmap->pm_asid < 256);
    308 
    309 	sh_tlb_set_asid(pmap->pm_asid);
    310 	curptd = pmap->pm_ptp;
    311 }
    312 
    313 void
    314 pmap_deactivate(struct lwp *l)
    315 {
    316 
    317 	/* Nothing to do */
    318 }
    319 
    320 int
    321 pmap_enter(pmap_t pmap, vaddr_t va, paddr_t pa, vm_prot_t prot, u_int flags)
    322 {
    323 	struct vm_page *pg;
    324 	struct vm_page_md *pvh;
    325 	pt_entry_t entry, *pte;
    326 	bool kva = pmap == pmap_kernel();
    327 
    328 	/* "flags" never exceed "prot" */
    329 	KDASSERT(prot != 0 && ((flags & VM_PROT_ALL) & ~prot) == 0);
    330 
    331 	pg = PHYS_TO_VM_PAGE(pa);
    332 	entry = (pa & PG_PPN) | PG_4K;
    333 	if (flags & PMAP_WIRED)
    334 		entry |= _PG_WIRED;
    335 
    336 	if (pg != NULL) {	/* memory-space */
    337 		pvh = VM_PAGE_TO_MD(pg);
    338 		entry |= PG_C;	/* always cached */
    339 
    340 		/* Seed modified/reference tracking */
    341 		if (flags & VM_PROT_WRITE) {
    342 			entry |= PG_V | PG_D;
    343 			pvh->pvh_flags |= PVH_MODIFIED | PVH_REFERENCED;
    344 		} else if (flags & VM_PROT_ALL) {
    345 			entry |= PG_V;
    346 			pvh->pvh_flags |= PVH_REFERENCED;
    347 		}
    348 
    349 		/* Protection */
    350 		if ((prot & VM_PROT_WRITE) && (pvh->pvh_flags & PVH_MODIFIED)) {
    351 			if (kva)
    352 				entry |= PG_PR_KRW | PG_SH;
    353 			else
    354 				entry |= PG_PR_URW;
    355 		} else {
    356 			/* RO or COW page */
    357 			if (kva)
    358 				entry |= PG_PR_KRO | PG_SH;
    359 			else
    360 				entry |= PG_PR_URO;
    361 		}
    362 
    363 		/* Check for existing mapping */
    364 		if (__pmap_map_change(pmap, va, pa, prot, entry))
    365 			return 0;
    366 
    367 		/* Add to physical-virtual map list of this page */
    368 		if (__pmap_pv_enter(pmap, pg, va)) {
    369 			if (flags & PMAP_CANFAIL)
    370 				return ENOMEM;
    371 			panic("%s: cannot allocate pv", __func__);
    372 		}
    373 	} else {	/* bus-space (always uncached map) */
    374 		if (kva) {
    375 			entry |= PG_V | PG_SH |
    376 			    ((prot & VM_PROT_WRITE) ?
    377 			    (PG_PR_KRW | PG_D) : PG_PR_KRO);
    378 		} else {
    379 			entry |= PG_V |
    380 			    ((prot & VM_PROT_WRITE) ?
    381 			    (PG_PR_URW | PG_D) : PG_PR_URO);
    382 		}
    383 	}
    384 
    385 	/* Register to page table */
    386 	if (kva)
    387 		pte = __pmap_kpte_lookup(va);
    388 	else {
    389 		pte = __pmap_pte_alloc(pmap, va);
    390 		if (pte == NULL) {
    391 			if (flags & PMAP_CANFAIL) {
    392 				if (pg != NULL)
    393 					__pmap_pv_remove(pmap, pg, va);
    394 				return ENOMEM;
    395 			}
    396 			panic("%s: cannot allocate pte", __func__);
    397 		}
    398 	}
    399 
    400 	*pte = entry;
    401 
    402 	if (pmap->pm_asid != -1)
    403 		sh_tlb_update(pmap->pm_asid, va, entry);
    404 
    405 	if (!SH_HAS_UNIFIED_CACHE &&
    406 	    (prot == (VM_PROT_READ | VM_PROT_EXECUTE)))
    407 		sh_icache_sync_range_index(va, PAGE_SIZE);
    408 
    409 	if (entry & _PG_WIRED)
    410 		pmap->pm_stats.wired_count++;
    411 	pmap->pm_stats.resident_count++;
    412 
    413 	return 0;
    414 }
    415 
    416 /*
    417  * bool __pmap_map_change(pmap_t pmap, vaddr_t va, paddr_t pa,
    418  *     vm_prot_t prot, pt_entry_t entry):
    419  *	Handle the situation that pmap_enter() is called to enter a
    420  *	mapping at a virtual address for which a mapping already
    421  *	exists.
    422  */
    423 bool
    424 __pmap_map_change(pmap_t pmap, vaddr_t va, paddr_t pa, vm_prot_t prot,
    425     pt_entry_t entry)
    426 {
    427 	pt_entry_t *pte, oentry;
    428 	vaddr_t eva = va + PAGE_SIZE;
    429 
    430 	if ((pte = __pmap_pte_lookup(pmap, va)) == NULL ||
    431 	    (oentry = *pte) == 0)
    432 		return false;		/* no mapping exists. */
    433 
    434 	if (pa != (oentry & PG_PPN)) {
    435 		/* Enter a mapping at a mapping to another physical page. */
    436 		pmap_remove(pmap, va, eva);
    437 		return false;
    438 	}
    439 
    440 	/* Pre-existing mapping */
    441 
    442 	/* Protection change. */
    443 	if ((oentry & PG_PR_MASK) != (entry & PG_PR_MASK))
    444 		pmap_protect(pmap, va, eva, prot);
    445 
    446 	/* Wired change */
    447 	if (oentry & _PG_WIRED) {
    448 		if (!(entry & _PG_WIRED)) {
    449 			/* wired -> unwired */
    450 			*pte = entry;
    451 			/* "wired" is software bits. no need to update TLB */
    452 			pmap->pm_stats.wired_count--;
    453 		}
    454 	} else if (entry & _PG_WIRED) {
    455 		/* unwired -> wired. make sure to reflect "flags" */
    456 		pmap_remove(pmap, va, eva);
    457 		return false;
    458 	}
    459 
    460 	return true;	/* mapping was changed. */
    461 }
    462 
    463 /*
    464  * int __pmap_pv_enter(pmap_t pmap, struct vm_page *pg, vaddr_t vaddr):
    465  *	Insert physical-virtual map to vm_page.
    466  *	Assume pre-existed mapping is already removed.
    467  */
    468 int
    469 __pmap_pv_enter(pmap_t pmap, struct vm_page *pg, vaddr_t va)
    470 {
    471 	struct vm_page_md *pvh;
    472 	struct pv_entry *pv;
    473 	int s;
    474 
    475 	s = splvm();
    476 	if (SH_HAS_VIRTUAL_ALIAS) {
    477 		/*
    478 		 * Remove all other mappings on this physical page
    479 		 * which have different virtual cache indexes to
    480 		 * avoid virtual cache aliases.
    481 		 *
    482 		 * XXX We should also handle shared mappings which
    483 		 * XXX have different virtual cache indexes by
    484 		 * XXX mapping them uncached (like arm and mips do).
    485 		 */
    486  again:
    487 		pvh = VM_PAGE_TO_MD(pg);
    488 		SLIST_FOREACH(pv, &pvh->pvh_head, pv_link) {
    489 			if (sh_cache_indexof(va) !=
    490 			    sh_cache_indexof(pv->pv_va)) {
    491 				pmap_remove(pv->pv_pmap, pv->pv_va,
    492 				    pv->pv_va + PAGE_SIZE);
    493 				goto again;
    494 			}
    495 		}
    496 	}
    497 
    498 	/* Register pv map */
    499 	pvh = VM_PAGE_TO_MD(pg);
    500 	pv = __pmap_pv_alloc();
    501 	if (pv == NULL) {
    502 		splx(s);
    503 		return ENOMEM;
    504 	}
    505 	pv->pv_pmap = pmap;
    506 	pv->pv_va = va;
    507 
    508 	SLIST_INSERT_HEAD(&pvh->pvh_head, pv, pv_link);
    509 	splx(s);
    510 	return 0;
    511 }
    512 
    513 void
    514 pmap_remove(pmap_t pmap, vaddr_t sva, vaddr_t eva)
    515 {
    516 	struct vm_page *pg;
    517 	pt_entry_t *pte, entry;
    518 	vaddr_t va;
    519 
    520 	KDASSERT((sva & PGOFSET) == 0);
    521 
    522 	for (va = sva; va < eva; va += PAGE_SIZE) {
    523 		if ((pte = __pmap_pte_lookup(pmap, va)) == NULL ||
    524 		    (entry = *pte) == 0)
    525 			continue;
    526 
    527 		if ((pg = PHYS_TO_VM_PAGE(entry & PG_PPN)) != NULL)
    528 			__pmap_pv_remove(pmap, pg, va);
    529 
    530 		if (entry & _PG_WIRED)
    531 			pmap->pm_stats.wired_count--;
    532 		pmap->pm_stats.resident_count--;
    533 		*pte = 0;
    534 
    535 		/*
    536 		 * When pmap->pm_asid == -1 (invalid ASID), old entry attribute
    537 		 * to this pmap is already removed by pmap_activate().
    538 		 */
    539 		if (pmap->pm_asid != -1)
    540 			sh_tlb_invalidate_addr(pmap->pm_asid, va);
    541 	}
    542 }
    543 
    544 /*
    545  * void __pmap_pv_remove(pmap_t pmap, struct vm_page *pg, vaddr_t vaddr):
    546  *	Remove physical-virtual map from vm_page.
    547  */
    548 void
    549 __pmap_pv_remove(pmap_t pmap, struct vm_page *pg, vaddr_t vaddr)
    550 {
    551 	struct vm_page_md *pvh;
    552 	struct pv_entry *pv;
    553 	int s;
    554 
    555 	s = splvm();
    556 	pvh = VM_PAGE_TO_MD(pg);
    557 	SLIST_FOREACH(pv, &pvh->pvh_head, pv_link) {
    558 		if (pv->pv_pmap == pmap && pv->pv_va == vaddr) {
    559 			if (SH_HAS_VIRTUAL_ALIAS ||
    560 			    (SH_HAS_WRITEBACK_CACHE &&
    561 				(pvh->pvh_flags & PVH_MODIFIED))) {
    562 				/*
    563 				 * Always use index ops. since I don't want to
    564 				 * worry about address space.
    565 				 */
    566 				sh_dcache_wbinv_range_index
    567 				    (pv->pv_va, PAGE_SIZE);
    568 			}
    569 
    570 			SLIST_REMOVE(&pvh->pvh_head, pv, pv_entry, pv_link);
    571 			__pmap_pv_free(pv);
    572 			break;
    573 		}
    574 	}
    575 #ifdef DEBUG
    576 	/* Check duplicated map. */
    577 	SLIST_FOREACH(pv, &pvh->pvh_head, pv_link)
    578 		KDASSERT(!(pv->pv_pmap == pmap && pv->pv_va == vaddr));
    579 #endif
    580 	splx(s);
    581 }
    582 
    583 void
    584 pmap_kenter_pa(vaddr_t va, paddr_t pa, vm_prot_t prot, u_int flags)
    585 {
    586 	pt_entry_t *pte, entry;
    587 
    588 	KDASSERT((va & PGOFSET) == 0);
    589 	KDASSERT(va >= VM_MIN_KERNEL_ADDRESS && va < VM_MAX_KERNEL_ADDRESS);
    590 
    591 	entry = (pa & PG_PPN) | PG_V | PG_SH | PG_4K;
    592 	if (prot & VM_PROT_WRITE)
    593 		entry |= (PG_PR_KRW | PG_D);
    594 	else
    595 		entry |= PG_PR_KRO;
    596 
    597 	if (PHYS_TO_VM_PAGE(pa))
    598 		entry |= PG_C;
    599 
    600 	pte = __pmap_kpte_lookup(va);
    601 
    602 	KDASSERT(*pte == 0);
    603 	*pte = entry;
    604 
    605 	sh_tlb_update(0, va, entry);
    606 }
    607 
    608 void
    609 pmap_kremove(vaddr_t va, vsize_t len)
    610 {
    611 	pt_entry_t *pte;
    612 	vaddr_t eva = va + len;
    613 
    614 	KDASSERT((va & PGOFSET) == 0);
    615 	KDASSERT((len & PGOFSET) == 0);
    616 	KDASSERT(va >= VM_MIN_KERNEL_ADDRESS && eva <= VM_MAX_KERNEL_ADDRESS);
    617 
    618 	for (; va < eva; va += PAGE_SIZE) {
    619 		pte = __pmap_kpte_lookup(va);
    620 		KDASSERT(pte != NULL);
    621 		if (*pte == 0)
    622 			continue;
    623 
    624 		if (SH_HAS_VIRTUAL_ALIAS && PHYS_TO_VM_PAGE(*pte & PG_PPN))
    625 			sh_dcache_wbinv_range(va, PAGE_SIZE);
    626 		*pte = 0;
    627 
    628 		sh_tlb_invalidate_addr(0, va);
    629 	}
    630 }
    631 
    632 bool
    633 pmap_extract(pmap_t pmap, vaddr_t va, paddr_t *pap)
    634 {
    635 	pt_entry_t *pte;
    636 
    637 	/* handle P1 and P2 specially: va == pa */
    638 	if (pmap == pmap_kernel() && (va >> 30) == 2) {
    639 		if (pap != NULL)
    640 			*pap = va & SH3_PHYS_MASK;
    641 		return true;
    642 	}
    643 
    644 	pte = __pmap_pte_lookup(pmap, va);
    645 	if (pte == NULL || *pte == 0)
    646 		return false;
    647 
    648 	if (pap != NULL)
    649 		*pap = (*pte & PG_PPN) | (va & PGOFSET);
    650 
    651 	return true;
    652 }
    653 
    654 void
    655 pmap_protect(pmap_t pmap, vaddr_t sva, vaddr_t eva, vm_prot_t prot)
    656 {
    657 	bool kernel = pmap == pmap_kernel();
    658 	pt_entry_t *pte, entry, protbits;
    659 	vaddr_t va;
    660 
    661 	sva = trunc_page(sva);
    662 
    663 	if ((prot & VM_PROT_READ) == VM_PROT_NONE) {
    664 		pmap_remove(pmap, sva, eva);
    665 		return;
    666 	}
    667 
    668 	switch (prot) {
    669 	default:
    670 		panic("%s: invalid protection mode %x", __func__, prot);
    671 		/* NOTREACHED */
    672 	case VM_PROT_READ:
    673 	case VM_PROT_READ | VM_PROT_EXECUTE:
    674 		protbits = kernel ? PG_PR_KRO : PG_PR_URO;
    675 		break;
    676 	case VM_PROT_READ | VM_PROT_WRITE:
    677 	case VM_PROT_ALL:
    678 		protbits = kernel ? PG_PR_KRW : PG_PR_URW;
    679 		break;
    680 	}
    681 
    682 	for (va = sva; va < eva; va += PAGE_SIZE) {
    683 		if ((pte = __pmap_pte_lookup(pmap, va)) == NULL ||
    684 		    (entry = *pte) == 0)
    685 			continue;
    686 
    687 		if (SH_HAS_VIRTUAL_ALIAS && (entry & PG_D)) {
    688 			if (!SH_HAS_UNIFIED_CACHE && (prot & VM_PROT_EXECUTE))
    689 				sh_icache_sync_range_index(va, PAGE_SIZE);
    690 			else
    691 				sh_dcache_wbinv_range_index(va, PAGE_SIZE);
    692 		}
    693 
    694 		entry = (entry & ~PG_PR_MASK) | protbits;
    695 		*pte = entry;
    696 
    697 		if (pmap->pm_asid != -1)
    698 			sh_tlb_update(pmap->pm_asid, va, entry);
    699 	}
    700 }
    701 
    702 void
    703 pmap_page_protect(struct vm_page *pg, vm_prot_t prot)
    704 {
    705 	struct vm_page_md *pvh = VM_PAGE_TO_MD(pg);
    706 	struct pv_entry *pv;
    707 	struct pmap *pmap;
    708 	vaddr_t va;
    709 	int s;
    710 
    711 	switch (prot) {
    712 	case VM_PROT_READ | VM_PROT_WRITE:
    713 	case VM_PROT_ALL:
    714 		break;
    715 
    716 	case VM_PROT_READ:
    717 	case VM_PROT_READ | VM_PROT_EXECUTE:
    718 		s = splvm();
    719 		SLIST_FOREACH(pv, &pvh->pvh_head, pv_link) {
    720 			pmap = pv->pv_pmap;
    721 			va = pv->pv_va;
    722 
    723 			KDASSERT(pmap);
    724 			pmap_protect(pmap, va, va + PAGE_SIZE, prot);
    725 		}
    726 		splx(s);
    727 		break;
    728 
    729 	default:
    730 		/* Remove all */
    731 		s = splvm();
    732 		while ((pv = SLIST_FIRST(&pvh->pvh_head)) != NULL) {
    733 			pmap = pv->pv_pmap;
    734 			va = pv->pv_va;
    735 #ifdef DEBUG
    736 			pt_entry_t *pte = __pmap_pte_lookup(pmap, va);
    737 			KDASSERT(pte != NULL);
    738 			KDASSERT(*pte != 0);
    739 #endif
    740 			pmap_remove(pmap, va, va + PAGE_SIZE);
    741 		}
    742 		splx(s);
    743 	}
    744 }
    745 
    746 void
    747 pmap_unwire(pmap_t pmap, vaddr_t va)
    748 {
    749 	pt_entry_t *pte, entry;
    750 
    751 	pte = __pmap_pte_lookup(pmap, va);
    752 	if (pte == NULL)
    753 		return;
    754 
    755 	entry = *pte;
    756 	if ((entry & _PG_WIRED) == 0)
    757 		return;
    758 
    759 	*pte = entry & ~_PG_WIRED;
    760 	pmap->pm_stats.wired_count--;
    761 }
    762 
    763 void
    764 pmap_procwr(struct proc	*p, vaddr_t va, size_t len)
    765 {
    766 
    767 	if (!SH_HAS_UNIFIED_CACHE)
    768 		sh_icache_sync_range_index(va, len);
    769 }
    770 
    771 void
    772 pmap_zero_page(paddr_t phys)
    773 {
    774 
    775 	if (SH_HAS_VIRTUAL_ALIAS) {	/* don't polute cache */
    776 		/* sync cache since we access via P2. */
    777 		sh_dcache_wbinv_all();
    778 		memset((void *)SH3_PHYS_TO_P2SEG(phys), 0, PAGE_SIZE);
    779 	} else
    780 		memset((void *)SH3_PHYS_TO_P1SEG(phys), 0, PAGE_SIZE);
    781 }
    782 
    783 void
    784 pmap_copy_page(paddr_t src, paddr_t dst)
    785 {
    786 
    787 	if (SH_HAS_VIRTUAL_ALIAS) {	/* don't polute cache */
    788 		/* sync cache since we access via P2. */
    789 		sh_dcache_wbinv_all();
    790 		memcpy((void *)SH3_PHYS_TO_P2SEG(dst),
    791 		    (void *)SH3_PHYS_TO_P2SEG(src), PAGE_SIZE);
    792 	} else {
    793 		memcpy((void *)SH3_PHYS_TO_P1SEG(dst),
    794 		    (void *)SH3_PHYS_TO_P1SEG(src), PAGE_SIZE);
    795 	}
    796 }
    797 
    798 bool
    799 pmap_is_referenced(struct vm_page *pg)
    800 {
    801 	struct vm_page_md *pvh = VM_PAGE_TO_MD(pg);
    802 
    803 	return (pvh->pvh_flags & PVH_REFERENCED) ? true : false;
    804 }
    805 
    806 bool
    807 pmap_clear_reference(struct vm_page *pg)
    808 {
    809 	struct vm_page_md *pvh = VM_PAGE_TO_MD(pg);
    810 	struct pv_entry *pv;
    811 	pt_entry_t *pte;
    812 	pmap_t pmap;
    813 	vaddr_t va;
    814 	int s;
    815 
    816 	if ((pvh->pvh_flags & PVH_REFERENCED) == 0)
    817 		return false;
    818 
    819 	pvh->pvh_flags &= ~PVH_REFERENCED;
    820 
    821 	s = splvm();
    822 	/* Restart reference bit emulation */
    823 	SLIST_FOREACH(pv, &pvh->pvh_head, pv_link) {
    824 		pmap = pv->pv_pmap;
    825 		va = pv->pv_va;
    826 
    827 		if ((pte = __pmap_pte_lookup(pmap, va)) == NULL)
    828 			continue;
    829 		if ((*pte & PG_V) == 0)
    830 			continue;
    831 		*pte &= ~PG_V;
    832 
    833 		if (pmap->pm_asid != -1)
    834 			sh_tlb_invalidate_addr(pmap->pm_asid, va);
    835 	}
    836 	splx(s);
    837 
    838 	return true;
    839 }
    840 
    841 bool
    842 pmap_is_modified(struct vm_page *pg)
    843 {
    844 	struct vm_page_md *pvh = VM_PAGE_TO_MD(pg);
    845 
    846 	return (pvh->pvh_flags & PVH_MODIFIED) ? true : false;
    847 }
    848 
    849 bool
    850 pmap_clear_modify(struct vm_page *pg)
    851 {
    852 	struct vm_page_md *pvh = VM_PAGE_TO_MD(pg);
    853 	struct pv_entry *pv;
    854 	struct pmap *pmap;
    855 	pt_entry_t *pte, entry;
    856 	bool modified;
    857 	vaddr_t va;
    858 	int s;
    859 
    860 	modified = pvh->pvh_flags & PVH_MODIFIED;
    861 	if (!modified)
    862 		return false;
    863 
    864 	pvh->pvh_flags &= ~PVH_MODIFIED;
    865 
    866 	s = splvm();
    867 	if (SLIST_EMPTY(&pvh->pvh_head)) {/* no map on this page */
    868 		splx(s);
    869 		return true;
    870 	}
    871 
    872 	/* Write-back and invalidate TLB entry */
    873 	if (!SH_HAS_VIRTUAL_ALIAS && SH_HAS_WRITEBACK_CACHE)
    874 		sh_dcache_wbinv_all();
    875 
    876 	SLIST_FOREACH(pv, &pvh->pvh_head, pv_link) {
    877 		pmap = pv->pv_pmap;
    878 		va = pv->pv_va;
    879 		if ((pte = __pmap_pte_lookup(pmap, va)) == NULL)
    880 			continue;
    881 		entry = *pte;
    882 		if ((entry & PG_D) == 0)
    883 			continue;
    884 
    885 		if (SH_HAS_VIRTUAL_ALIAS)
    886 			sh_dcache_wbinv_range_index(va, PAGE_SIZE);
    887 
    888 		*pte = entry & ~PG_D;
    889 		if (pmap->pm_asid != -1)
    890 			sh_tlb_invalidate_addr(pmap->pm_asid, va);
    891 	}
    892 	splx(s);
    893 
    894 	return true;
    895 }
    896 
    897 paddr_t
    898 pmap_phys_address(paddr_t cookie)
    899 {
    900 
    901 	return sh3_ptob(cookie);
    902 }
    903 
    904 #ifdef SH4
    905 /*
    906  * pmap_prefer(vaddr_t foff, vaddr_t *vap)
    907  *
    908  * Find first virtual address >= *vap that doesn't cause
    909  * a virtual cache alias against vaddr_t foff.
    910  */
    911 void
    912 pmap_prefer(vaddr_t foff, vaddr_t *vap, int td)
    913 {
    914 	if (!SH_HAS_VIRTUAL_ALIAS)
    915 		return;
    916 
    917 	vaddr_t va = *vap;
    918 	vsize_t d = (foff - va) & sh_cache_prefer_mask;
    919 
    920 	if (d == 0)
    921 		return;
    922 
    923 	if (td)
    924 		*vap = va - ((-d) & sh_cache_prefer_mask);
    925 	else
    926 		*vap = va + d;
    927 }
    928 #endif /* SH4 */
    929 
    930 /*
    931  * pv_entry pool allocator:
    932  *	void *__pmap_pv_page_alloc(struct pool *pool, int flags):
    933  *	void __pmap_pv_page_free(struct pool *pool, void *v):
    934  */
    935 void *
    936 __pmap_pv_page_alloc(struct pool *pool, int flags)
    937 {
    938 	struct vm_page *pg;
    939 
    940 	pg = uvm_pagealloc(NULL, 0, NULL, UVM_PGA_USERESERVE);
    941 	if (pg == NULL)
    942 		return NULL;
    943 
    944 	return (void *)SH3_PHYS_TO_P1SEG(VM_PAGE_TO_PHYS(pg));
    945 }
    946 
    947 void
    948 __pmap_pv_page_free(struct pool *pool, void *v)
    949 {
    950 	vaddr_t va = (vaddr_t)v;
    951 
    952 	/* Invalidate cache for next use of this page */
    953 	if (SH_HAS_VIRTUAL_ALIAS)
    954 		sh_icache_sync_range_index(va, PAGE_SIZE);
    955 	uvm_pagefree(PHYS_TO_VM_PAGE(SH3_P1SEG_TO_PHYS(va)));
    956 }
    957 
    958 /*
    959  * pt_entry_t __pmap_pte_alloc(pmap_t pmap, vaddr_t va):
    960  *	lookup page table entry. if found returns it, else allocate it.
    961  *	page table is accessed via P1.
    962  */
    963 pt_entry_t *
    964 __pmap_pte_alloc(pmap_t pmap, vaddr_t va)
    965 {
    966 	struct vm_page *pg;
    967 	pt_entry_t *ptp, *pte;
    968 
    969 	if ((pte = __pmap_pte_lookup(pmap, va)) != NULL)
    970 		return pte;
    971 
    972 	/* Allocate page table (not managed page) */
    973 	pg = uvm_pagealloc(NULL, 0, NULL, UVM_PGA_USERESERVE | UVM_PGA_ZERO);
    974 	if (pg == NULL)
    975 		return NULL;
    976 
    977 	ptp = (pt_entry_t *)SH3_PHYS_TO_P1SEG(VM_PAGE_TO_PHYS(pg));
    978 	pmap->pm_ptp[__PMAP_PTP_INDEX(va)] = ptp;
    979 
    980 	return ptp + __PMAP_PTP_OFSET(va);
    981 }
    982 
    983 /*
    984  * pt_entry_t *__pmap_pte_lookup(pmap_t pmap, vaddr_t va):
    985  *	lookup page table entry, if not allocated, returns NULL.
    986  */
    987 pt_entry_t *
    988 __pmap_pte_lookup(pmap_t pmap, vaddr_t va)
    989 {
    990 	pt_entry_t *ptp;
    991 
    992 	if (pmap == pmap_kernel())
    993 		return __pmap_kpte_lookup(va);
    994 
    995 	/* Lookup page table page */
    996 	ptp = pmap->pm_ptp[__PMAP_PTP_INDEX(va)];
    997 	if (ptp == NULL)
    998 		return NULL;
    999 
   1000 	return ptp + __PMAP_PTP_OFSET(va);
   1001 }
   1002 
   1003 /*
   1004  * pt_entry_t *__pmap_kpte_lookup(vaddr_t va):
   1005  *	kernel virtual only version of __pmap_pte_lookup().
   1006  */
   1007 pt_entry_t *
   1008 __pmap_kpte_lookup(vaddr_t va)
   1009 {
   1010 	pt_entry_t *ptp;
   1011 
   1012 	ptp = __pmap_kernel.pm_ptp[__PMAP_PTP_INDEX(va-VM_MIN_KERNEL_ADDRESS)];
   1013 	if (ptp == NULL)
   1014 		return NULL;
   1015 
   1016 	return ptp + __PMAP_PTP_OFSET(va);
   1017 }
   1018 
   1019 /*
   1020  * bool __pmap_pte_load(pmap_t pmap, vaddr_t va, int flags):
   1021  *	lookup page table entry, if found it, load to TLB.
   1022  *	flags specify do emulate reference and/or modified bit or not.
   1023  */
   1024 bool
   1025 __pmap_pte_load(pmap_t pmap, vaddr_t va, int flags)
   1026 {
   1027 	struct vm_page *pg;
   1028 	pt_entry_t *pte;
   1029 	pt_entry_t entry;
   1030 
   1031 	KDASSERT(((intptr_t)va < 0 && pmap == pmap_kernel()) ||
   1032 	    ((intptr_t)va >= 0 && pmap != pmap_kernel()));
   1033 
   1034 	/* Lookup page table entry */
   1035 	if ((pte = __pmap_pte_lookup(pmap, va)) == NULL ||
   1036 	    (entry = *pte) == 0)
   1037 		return false;
   1038 
   1039 	KDASSERT(va != 0);
   1040 
   1041 	/* Emulate reference/modified tracking for managed page. */
   1042 	if (flags != 0 && (pg = PHYS_TO_VM_PAGE(entry & PG_PPN)) != NULL) {
   1043 		struct vm_page_md *pvh = VM_PAGE_TO_MD(pg);
   1044 
   1045 		if (flags & PVH_REFERENCED) {
   1046 			pvh->pvh_flags |= PVH_REFERENCED;
   1047 			entry |= PG_V;
   1048 		}
   1049 		if (flags & PVH_MODIFIED) {
   1050 			pvh->pvh_flags |= PVH_MODIFIED;
   1051 			entry |= PG_D;
   1052 		}
   1053 		*pte = entry;
   1054 	}
   1055 
   1056 	/* When pmap has valid ASID, register to TLB */
   1057 	if (pmap->pm_asid != -1)
   1058 		sh_tlb_update(pmap->pm_asid, va, entry);
   1059 
   1060 	return true;
   1061 }
   1062 
   1063 /*
   1064  * int __pmap_asid_alloc(void):
   1065  *	Allocate new ASID. if all ASID is used, steal from other process.
   1066  */
   1067 int
   1068 __pmap_asid_alloc(void)
   1069 {
   1070 	struct proc *p;
   1071 	int i, j, k, n, map, asid;
   1072 
   1073 	/* Search free ASID */
   1074 	i = __pmap_asid.hint >> 5;
   1075 	n = i + 8;
   1076 	for (; i < n; i++) {
   1077 		k = i & 0x7;
   1078 		map = __pmap_asid.map[k];
   1079 		for (j = 0; j < 32; j++) {
   1080 			if ((map & (1 << j)) == 0 && (k + j) != 0) {
   1081 				__pmap_asid.map[k] |= (1 << j);
   1082 				__pmap_asid.hint = (k << 5) + j;
   1083 				return __pmap_asid.hint;
   1084 			}
   1085 		}
   1086 	}
   1087 
   1088 	/* Steal ASID */
   1089 	LIST_FOREACH(p, &allproc, p_list) {
   1090 		if ((asid = p->p_vmspace->vm_map.pmap->pm_asid) > 0) {
   1091 			pmap_t pmap = p->p_vmspace->vm_map.pmap;
   1092 			pmap->pm_asid = -1;
   1093 			__pmap_asid.hint = asid;
   1094 			/* Invalidate all old ASID entry */
   1095 			sh_tlb_invalidate_asid(pmap->pm_asid);
   1096 
   1097 			return __pmap_asid.hint;
   1098 		}
   1099 	}
   1100 
   1101 	panic("%s: no ASID allocated", __func__);
   1102 	/* NOTREACHED */
   1103 }
   1104 
   1105 /*
   1106  * void __pmap_asid_free(int asid):
   1107  *	Return unused ASID to pool. and remove all TLB entry of ASID.
   1108  */
   1109 void
   1110 __pmap_asid_free(int asid)
   1111 {
   1112 	int i;
   1113 
   1114 	if (asid < 1)	/* Don't invalidate kernel ASID 0 */
   1115 		return;
   1116 
   1117 	sh_tlb_invalidate_asid(asid);
   1118 
   1119 	i = asid >> 5;
   1120 	__pmap_asid.map[i] &= ~(1 << (asid - (i << 5)));
   1121 }
   1122