NetBSD/sys/arch/vax/vax/pmap.c
ragge cf02ad2bc9 Add support for QDSS graphic console. Code originated from 4.4BSD,
ported to NetBSD by Boris Gjenero <bgjenero@undergrad.math.uwaterloo.ca>
1998-03-21 10:02:39 +00:00

856 lines
21 KiB
C

/* $NetBSD: pmap.c,v 1.47 1998/03/21 10:02:41 ragge Exp $ */
/*
* Copyright (c) 1994 Ludd, University of Lule}, Sweden.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed at Ludd, University of Lule}.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/types.h>
#include <sys/param.h>
#include <sys/queue.h>
#include <sys/malloc.h>
#include <sys/proc.h>
#include <sys/user.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <vm/vm.h>
#include <vm/vm_page.h>
#include <vm/vm_kern.h>
#if defined(UVM)
#include <uvm/uvm.h>
#endif
#include <machine/pte.h>
#include <machine/pcb.h>
#include <machine/mtpr.h>
#include <machine/macros.h>
#include <machine/sid.h>
#include <machine/cpu.h>
#include <machine/scb.h>
/* QDSS console mapping hack */
#include "qd.h"
#if NQD > 0
/* Pointer to virtual memory for for mapping QDSS */
void *qvmem[NQD];
/* Pointer to page tables for this virtual memory */
struct pte *QVmap[NQD];
extern void *qd_ubaio;
#endif
#define ISTACK_SIZE (4 * CLBYTES)
/*
* This code uses bitfield operators for most page table entries.
*/
#define PROTSHIFT 27
#define PROT_KW (PG_KW >> PROTSHIFT)
#define PROT_KR (PG_KR >> PROTSHIFT)
#define PROT_RW (PG_RW >> PROTSHIFT)
#define PROT_RO (PG_RO >> PROTSHIFT)
#define PROT_URKW (PG_URKW >> PROTSHIFT)
struct pmap kernel_pmap_store;
struct pv_entry *pv_table; /* array of entries, one per LOGICAL page */
void *scratch;
vm_offset_t ptemapstart, ptemapend;
vm_map_t pte_map;
#if defined(UVM)
struct vm_map pte_map_store;
#endif
extern caddr_t msgbufaddr;
#ifdef PMAPDEBUG
int startpmapdebug = 0;
#endif
static inline void rensa __P((int, struct pte *));
vm_offset_t avail_start, avail_end;
vm_offset_t virtual_avail, virtual_end; /* Available virtual memory */
/*
* pmap_bootstrap().
* Called as part of vm bootstrap, allocates internal pmap structures.
* Assumes that nothing is mapped, and that kernel stack is located
* immediately after end.
*/
void
pmap_bootstrap()
{
unsigned int sysptsize, istack, i;
extern unsigned int etext, proc0paddr;
struct pcb *pcb = (struct pcb *)proc0paddr;
pmap_t pmap = pmap_kernel();
/*
* Machines older than MicroVAX II have their boot blocks
* loaded directly or the boot program loaded from console
* media, so we need to figure out their memory size.
* This is not easily done on MicroVAXen, so we get it from
* VMB instead.
*/
if (avail_end == 0)
while (badaddr((caddr_t)avail_end, 4) == 0)
avail_end += NBPG * 128;
avail_end = TRUNC_PAGE(avail_end); /* be sure */
/*
* Calculation of the System Page Table is somewhat a pain,
* because it must be in contiguous physical memory and all
* size calculations must be done now.
* Remember: sysptsize is in PTEs and nothing else!
*/
/* Kernel alloc area */
sysptsize = (((0x100000 * maxproc) >> PGSHIFT) / 4);
/* reverse mapping struct */
sysptsize += (avail_end >> PGSHIFT) * 2;
/* User Page table area. This may grow big */
#define USRPTSIZE ((MAXTSIZ + MAXDSIZ + MAXSSIZ + MMAPSPACE) / NBPG)
sysptsize += ((USRPTSIZE * 4) / NBPG) * maxproc;
/* Kernel stacks per process */
sysptsize += UPAGES * maxproc;
/*
* Virtual_* and avail_* is used for mapping of system page table.
* The need for kernel virtual memory is linear dependent of the
* amount of physical memory also, therefore sysptsize is
* a variable here that is changed dependent of the physical
* memory size.
*/
virtual_avail = avail_end + KERNBASE;
virtual_end = KERNBASE + sysptsize * NBPG;
blkclr(Sysmap, sysptsize * 4); /* clear SPT before using it */
/*
* The first part of Kernel Virtual memory is the physical
* memory mapped in. This makes some mm routines both simpler
* and faster, but takes ~0.75% more memory.
*/
pmap_map(KERNBASE, 0, avail_end, VM_PROT_READ|VM_PROT_WRITE);
/*
* Kernel code is always readable for user, it must be because
* of the emulation code that is somewhere in there.
* And it doesn't hurt, /netbsd is also public readable.
* There are also a couple of other things that must be in
* physical memory and that isn't managed by the vm system.
*/
for (i = 0; i < ((unsigned)&etext - KERNBASE) >> PGSHIFT; i++)
Sysmap[i].pg_prot = PROT_URKW;
/* Map System Page Table and zero it, Sysmap already set. */
mtpr((unsigned)Sysmap - KERNBASE, PR_SBR);
/* Map Interrupt stack and set red zone */
istack = (unsigned)Sysmap + ROUND_PAGE(sysptsize * 4);
mtpr(istack + ISTACK_SIZE, PR_ISP);
kvtopte(istack)->pg_v = 0;
/* Some scratch pages */
scratch = (void *)istack + ISTACK_SIZE;
/* Physical-to-virtual translation table */
(unsigned)pv_table = scratch + 4 * NBPG;
avail_start = (unsigned)pv_table + (ROUND_PAGE(avail_end >> CLSHIFT)) *
sizeof(struct pv_entry) - KERNBASE;
/* Kernel message buffer */
avail_end -= MSGBUFSIZE;
msgbufaddr = (void *)(avail_end + KERNBASE);
/* zero all mapped physical memory from Sysmap to here */
blkclr((void *)istack, (avail_start + KERNBASE) - istack);
/* Set logical page size */
#if defined(UVM)
uvmexp.pagesize = CLBYTES;
uvm_setpagesize();
#else
PAGE_SIZE = CLBYTES;
vm_set_page_size();
#endif
/* QDSS console mapping hack */
#if NQD > 0
/*
* This allocates some kernel virtual address space. qdcninit
* maps things here
*/
MAPVIRT(qvmem[0], 64 * 1024 * NQD / NBPG);
MAPVIRT(qd_ubaio, 16);
#endif
/*
* We move SCB here from physical address 0 to an address
* somewhere else, so that we can dynamically allocate
* space for interrupt vectors and other machine-specific
* things. We move it here, but the rest of the allocation
* is done in a cpu-specific routine.
* avail_start is modified in the cpu-specific routine.
*/
scb = (struct scb *)(avail_start + KERNBASE);
bcopy(0, (void *)avail_start, NBPG >> 1);
mtpr(avail_start, PR_SCBB);
bzero(0, NBPG >> 1);
(*dep_call->cpu_steal_pages)();
avail_start = ROUND_PAGE(avail_start);
virtual_avail = ROUND_PAGE(virtual_avail);
#ifdef PMAPDEBUG
cninit();
printf("Sysmap %x, istack %x, scratch %x\n",Sysmap,istack,scratch);
printf("etext %x\n", &etext);
printf("SYSPTSIZE %x\n",sysptsize);
printf("pv_table %x, \n", pv_table);
printf("avail_start %x, avail_end %x\n",avail_start,avail_end);
printf("virtual_avail %x,virtual_end %x\n",virtual_avail,virtual_end);
/* printf("faultdebug %x, startsysc %x\n",&faultdebug, &startsysc);*/
printf("startpmapdebug %x\n",&startpmapdebug);
#endif
/* Init kernel pmap */
pmap->pm_p1br = (void *)0x80000000;
pmap->pm_p0br = (void *)0x80000000;
pmap->pm_p1lr = 0x200000;
pmap->pm_p0lr = AST_PCB;
pmap->ref_count = 1;
/* Activate the kernel pmap. */
mtpr(pcb->P1BR = pmap->pm_p1br, PR_P1BR);
mtpr(pcb->P0BR = pmap->pm_p0br, PR_P0BR);
mtpr(pcb->P1LR = pmap->pm_p1lr, PR_P1LR);
mtpr(pcb->P0LR = pmap->pm_p0lr, PR_P0LR);
/*
* Now everything should be complete, start virtual memory.
*/
#if defined(UVM)
uvm_page_physload(avail_start >> CLSHIFT, avail_end >> CLSHIFT,
avail_start >> CLSHIFT, avail_end >> CLSHIFT);
#endif
mtpr(sysptsize, PR_SLR);
mtpr(1, PR_MAPEN);
}
#if defined(UVM)
/*
* How much virtual space does this kernel have?
* (After mapping kernel text, data, etc.)
*/
void
pmap_virtual_space(v_start, v_end)
vm_offset_t *v_start;
vm_offset_t *v_end;
{
*v_start = virtual_avail;
*v_end = virtual_end;
}
#endif
/*
* pmap_init() is called as part of vm init after memory management
* is enabled. It is meant to do machine-specific allocations.
* Here we allocate virtual memory for user page tables.
*/
void
#if defined(UVM)
pmap_init()
#else
pmap_init(start, end)
vm_offset_t start, end;
#endif
{
/* reserve place on SPT for UPT */
#if !defined(UVM)
pte_map = kmem_suballoc(kernel_map, &ptemapstart, &ptemapend,
USRPTSIZE * 4 * maxproc, TRUE);
#else
pte_map = uvm_km_suballoc(kernel_map, &ptemapstart, &ptemapend,
USRPTSIZE * 4 * maxproc, TRUE, FALSE, &pte_map_store);
#endif
}
/*
* pmap_create() creates a pmap for a new task.
* If not already allocated, malloc space for one.
*/
pmap_t
pmap_create(phys_size)
vm_size_t phys_size;
{
pmap_t pmap;
#ifdef PMAPDEBUG
if(startpmapdebug)printf("pmap_create: phys_size %x\n",phys_size);
#endif
if (phys_size)
return NULL;
pmap = (pmap_t) malloc(sizeof(struct pmap), M_VMPMAP, M_WAITOK);
bzero(pmap, sizeof(struct pmap));
pmap_pinit(pmap);
pmap->pm_stack = USRSTACK;
return (pmap);
}
/*
* Initialize a preallocated an zeroed pmap structure,
*/
void
pmap_pinit(pmap)
pmap_t pmap;
{
int bytesiz;
/*
* Allocate PTEs and stash them away in the pmap.
* XXX Ok to use kmem_alloc_wait() here?
*/
bytesiz = USRPTSIZE * sizeof(struct pte);
#if defined(UVM)
pmap->pm_p0br = (void *)uvm_km_valloc_wait(pte_map, bytesiz);
#else
pmap->pm_p0br = (void *)kmem_alloc_wait(pte_map, bytesiz);
#endif
pmap->pm_p0lr = btoc(MAXTSIZ + MAXDSIZ + MMAPSPACE) | AST_PCB;
pmap->pm_p1br = (void *)pmap->pm_p0br + bytesiz - 0x800000;
pmap->pm_p1lr = (0x200000 - btoc(MAXSSIZ));
#ifdef PMAPDEBUG
if(startpmapdebug)
printf("pmap_pinit(%p): p0br=%p p0lr=0x%lx p1br=%p p1lr=0x%lx\n",
pmap, pmap->pm_p0br, pmap->pm_p0lr, pmap->pm_p1br, pmap->pm_p1lr);
#endif
pmap->ref_count = 1;
}
/*
* Release any resources held by the given physical map.
* Called when a pmap initialized by pmap_pinit is being released.
* Should only be called if the map contains no valid mappings.
*/
void
pmap_release(pmap)
struct pmap *pmap;
{
#ifdef PMAPDEBUG
if(startpmapdebug)printf("pmap_release: pmap %x\n",pmap);
#endif
if (pmap->pm_p0br)
#if defined(UVM)
uvm_km_free_wakeup(pte_map, (vm_offset_t)pmap->pm_p0br,
USRPTSIZE * sizeof(struct pte));
#else
kmem_free_wakeup(pte_map, (vm_offset_t)pmap->pm_p0br,
USRPTSIZE * sizeof(struct pte));
#endif
}
/*
* pmap_destroy(pmap): Remove a reference from the pmap.
* If the pmap is NULL then just return else decrese pm_count.
* If this was the last reference we call's pmap_relaese to release this pmap.
* OBS! remember to set pm_lock
*/
void
pmap_destroy(pmap)
pmap_t pmap;
{
int count;
#ifdef PMAPDEBUG
if(startpmapdebug)printf("pmap_destroy: pmap %x\n",pmap);
#endif
if (pmap == NULL)
return;
simple_lock(&pmap->pm_lock);
count = --pmap->ref_count;
simple_unlock(&pmap->pm_lock);
if (count == 0) {
pmap_release(pmap);
free((caddr_t)pmap, M_VMPMAP);
}
}
void
pmap_enter(pmap, v, p, prot, wired)
register pmap_t pmap;
vm_offset_t v;
vm_offset_t p;
vm_prot_t prot;
boolean_t wired;
{
struct pv_entry *pv, *tmp;
int i, s, nypte, *patch;
#ifdef PMAPDEBUG
if(startpmapdebug)
printf("pmap_enter: pmap: %x,virt %x, phys %x, prot %x w %x\n",
pmap,v,p,prot, wired);
#endif
if (pmap == 0)
return;
if (v < 0x40000000) {
patch = (int *)pmap->pm_p0br;
i = (v >> PGSHIFT);
if (i >= (pmap->pm_p0lr & ~AST_MASK))
panic("P0 too small in pmap_enter");
patch = (int *)pmap->pm_p0br;
nypte = PG_V|(p>>PGSHIFT)|(prot&VM_PROT_WRITE?PG_RW:PG_RO);
} else if (v & KERNBASE) {
patch = (int *)Sysmap;
i = (v - KERNBASE) >> PGSHIFT;
nypte = PG_V|(p>>PGSHIFT)|(prot&VM_PROT_WRITE?PG_KW:PG_KR);
} else {
patch = (int *)pmap->pm_p1br;
i = (v - 0x40000000) >> PGSHIFT;
if (i < pmap->pm_p1lr)
panic("pmap_enter: must expand P1");
if (v < pmap->pm_stack)
pmap->pm_stack = v;
nypte = PG_V|(p>>PGSHIFT)|(prot&VM_PROT_WRITE?PG_RW:PG_RO);
}
if ((patch[i] & ~PG_M) == nypte)
return;
if ((patch[i] & PG_FRAME) &&
((patch[i] & PG_FRAME) != (nypte & PG_FRAME)))
#if defined(UVM)
pmap_page_protect((patch[i] & PG_FRAME) << PGSHIFT, 0);
#else
panic("pmap_enter: mapping onto old map");
#endif
/*
* If we map in a new physical page we also must add it
* in the pv_table.
*/
if ((patch[i] & PG_FRAME) != (nypte & PG_FRAME)) {
pv = pv_table + (p >> CLSHIFT);
s = splimp();
if (pv->pv_pte == 0) {
pv->pv_pte = (struct pte *)&patch[i];
} else {
MALLOC(tmp, struct pv_entry *, sizeof(struct pv_entry),
M_VMPVENT, M_NOWAIT);
#ifdef DIAGNOSTIC
if (tmp == 0)
panic("pmap_enter: cannot alloc pv_entry");
#endif
tmp->pv_pte = (struct pte *)&patch[i];
tmp->pv_next = pv->pv_next;
pv->pv_next = tmp;
}
splx(s);
}
patch[i] = nypte;
patch[i+1] = nypte+1;
if (v > KERNBASE && v < ptemapend) { /* If we're playing with PTEs */
mtpr(0, PR_TBIA);
} else {
mtpr(v, PR_TBIS);
mtpr(v + NBPG, PR_TBIS);
}
}
void *
pmap_bootstrap_alloc(size)
int size;
{
void *mem;
#ifdef PMAPDEBUG
if(startpmapdebug)
printf("pmap_bootstrap_alloc: size 0x %x\n",size);
#endif
size = round_page(size);
mem = (void *)avail_start + KERNBASE;
avail_start += size;
blkclr(mem, size);
return (mem);
}
vm_offset_t
pmap_map(virtuell, pstart, pend, prot)
vm_offset_t virtuell, pstart, pend;
int prot;
{
vm_offset_t count;
int *pentry;
#ifdef PMAPDEBUG
if(startpmapdebug)
printf("pmap_map: virt %x, pstart %x, pend %x, Sysmap %x\n",
virtuell, pstart, pend, Sysmap);
#endif
pstart=(uint)pstart &0x7fffffff;
pend=(uint)pend &0x7fffffff;
virtuell=(uint)virtuell &0x7fffffff;
(uint)pentry= (((uint)(virtuell)>>PGSHIFT)*4)+(uint)Sysmap;
for(count=pstart;count<pend;count+=NBPG){
*pentry++ = (count>>PGSHIFT)|PG_V|
(prot & VM_PROT_WRITE ? PG_KW : PG_KR);
}
mtpr(0,PR_TBIA);
return(virtuell+(count-pstart)+0x80000000);
}
#define POFF(x) (((unsigned)(x) & 0x3fffffff) >> PGSHIFT)
vm_offset_t
pmap_extract(pmap, va)
pmap_t pmap;
vm_offset_t va;
{
struct pte *pte;
#ifdef PMAPDEBUG
if(startpmapdebug)printf("pmap_extract: pmap %x, va %x\n",pmap, va);
#endif
#ifdef DIAGNOSTIC
if (va & PGOFSET)
printf("Warning, pmap_extract va not aligned\n");
#endif
if (va < 0x40000000) {
pte = pmap->pm_p0br;
if ((va >> PGSHIFT) > (pmap->pm_p0lr & ~AST_MASK))
return 0;
} else if (va & KERNBASE) {
pte = Sysmap;
} else {
pte = pmap->pm_p1br;
if (POFF(va) < pmap->pm_p1lr)
return 0;
}
return (pte[POFF(va)].pg_pfn << PGSHIFT);
}
/*
* Rensa is a help routine to remove a pv_entry from the pv list.
* Arguments are physical clustering page and page table entry pointer.
*/
static inline void
rensa(clp, ptp)
int clp;
struct pte *ptp;
{
struct pv_entry *pf, *pv = pv_table + clp;
int s;
s = splimp();
if (pv->pv_pte == ptp) {
pv->pv_pte = 0;
splx(s);
return;
}
for (; pv->pv_next; pv = pv->pv_next) {
if (pv->pv_next->pv_pte == ptp) {
pf = pv->pv_next;
pv->pv_next = pv->pv_next->pv_next;
FREE(pf, M_VMPVENT);
splx(s);
return;
}
}
panic("rensa");
}
/*
* Sets protection for a given region to prot. If prot == none then
* unmap region. pmap_remove is implemented as pmap_protect with
* protection none.
*/
void
pmap_protect(pmap, start, end, prot)
pmap_t pmap;
vm_offset_t start;
vm_offset_t end;
vm_prot_t prot;
{
struct pte *pt, *pts, *ptd;
int pr;
#ifdef PMAPDEBUG
if(startpmapdebug) printf("pmap_protect: pmap %x, start %x, end %x, prot %x\n",
pmap, start, end,prot);
#endif
if (pmap == 0)
return;
if (start & KERNBASE) { /* System space */
pt = Sysmap;
#ifdef DIAGNOSTIC
if (((end & 0x3fffffff) >> PGSHIFT) > mfpr(PR_SLR))
panic("pmap_protect: outside SLR");
#endif
pr = (prot & VM_PROT_WRITE ? PROT_KW : PROT_KR);
} else if (start & 0x40000000) { /* P1 space */
if (end <= pmap->pm_stack)
return;
if (start < pmap->pm_stack)
start = pmap->pm_stack;
pt = pmap->pm_p1br;
#ifdef DIAGNOSTIC
if (((start & 0x3fffffff) >> PGSHIFT) < pmap->pm_p1lr)
panic("pmap_protect: outside P1LR");
#endif
pr = (prot & VM_PROT_WRITE ? PROT_RW : PROT_RO);
} else { /* P0 space */
pt = pmap->pm_p0br;
#ifdef DIAGNOSTIC
if ((end >> PGSHIFT) > (pmap->pm_p0lr & ~AST_MASK))
panic("pmap_protect: outside P0LR");
#endif
pr = (prot & VM_PROT_WRITE ? PROT_RW : PROT_RO);
}
pts = &pt[((start & 0x3fffffff) >> PGSHIFT)];
ptd = &pt[((end & 0x3fffffff) >> PGSHIFT)];
#ifdef DEBUG
if (((int)pts - (int)pt) & 7)
panic("pmap_remove: pts not even");
if (((int)ptd - (int)pt) & 7)
panic("pmap_remove: ptd not even");
#endif
if (prot == VM_PROT_NONE) {
while (pts < ptd) {
if (*(int *)pts) {
rensa(pts->pg_pfn >> CLSIZELOG2, pts);
bzero(pts, sizeof(struct pte) * CLSIZE);
}
pts += CLSIZE;
}
} else {
while (pts < ptd) {
if (*(int *)pts) {
pts[0].pg_prot = pr;
pts[1].pg_prot = pr;
}
pts += CLSIZE;
}
}
mtpr(0,PR_TBIA);
}
/*
* Checks if page is referenced; returns true or false depending on result.
*/
boolean_t
pmap_is_referenced(pa)
vm_offset_t pa;
{
struct pv_entry *pv;
pv = pv_table + (pa >> CLSHIFT);
if (pv->pv_pte)
if ((pv->pv_pte[0].pg_v))
return 1;
while ((pv = pv->pv_next)) {
if ((pv->pv_pte[0].pg_v))
return 1;
}
return 0;
}
/*
* Clears valid bit in all ptes referenced to this physical page.
*/
void
pmap_clear_reference(pa)
vm_offset_t pa;
{
struct pv_entry *pv;
pv = pv_table + (pa >> CLSHIFT);
if (pv->pv_pte)
pv->pv_pte[0].pg_v = pv->pv_pte[1].pg_v = 0;
while ((pv = pv->pv_next))
pv->pv_pte[0].pg_v = pv->pv_pte[1].pg_v = 0;
}
/*
* Checks if page is modified; returns true or false depending on result.
*/
boolean_t
pmap_is_modified(pa)
vm_offset_t pa;
{
struct pv_entry *pv;
pv = pv_table + (pa >> CLSHIFT);
if (pv->pv_pte)
if ((pv->pv_pte[0].pg_m | pv->pv_pte[1].pg_m))
return 1;
while ((pv = pv->pv_next)) {
if ((pv->pv_pte[0].pg_m | pv->pv_pte[1].pg_m))
return 1;
}
return 0;
}
/*
* Clears modify bit in all ptes referenced to this physical page.
*/
void
pmap_clear_modify(pa)
vm_offset_t pa;
{
struct pv_entry *pv;
pv = pv_table + (pa >> CLSHIFT);
if (pv->pv_pte)
pv->pv_pte[0].pg_m = pv->pv_pte[1].pg_m = 0;
while ((pv = pv->pv_next))
pv->pv_pte[0].pg_m = pv->pv_pte[1].pg_m = 0;
}
/*
* Lower the permission for all mappings to a given page.
* Lower permission can only mean setting protection to either read-only
* or none; where none is unmapping of the page.
*/
void
pmap_page_protect(pa, prot)
vm_offset_t pa;
vm_prot_t prot;
{
struct pte *pt;
struct pv_entry *pv, *opv;
int s;
#ifdef PMAPDEBUG
if(startpmapdebug) printf("pmap_page_protect: pa %x, prot %x\n",pa, prot);
#endif
pv = pv_table + (pa >> CLSHIFT);
if (pv->pv_pte == 0 && pv->pv_next == 0)
return;
if (prot == VM_PROT_ALL) /* 'cannot happen' */
return;
if (prot == VM_PROT_NONE) {
pt = pv->pv_pte;
s = splimp();
if (pt)
bzero(pt, sizeof(struct pte) * CLSIZE);
opv = pv;
pv = pv->pv_next;
bzero(opv, sizeof(struct pv_entry));
while (pv) {
pt = pv->pv_pte;
bzero(pt, sizeof(struct pte) * CLSIZE);
opv = pv;
pv = pv->pv_next;
FREE(opv, M_VMPVENT);
}
splx(s);
} else { /* read-only */
do {
pt = pv->pv_pte;
if (pt == 0)
continue;
pt[0].pg_prot = pt[1].pg_prot =
((vm_offset_t)pv->pv_pte < ptemapstart ?
PROT_KR : PROT_RO);
} while ((pv = pv->pv_next));
}
mtpr(0, PR_TBIA);
}
/*
* Activate the address space for the specified process.
* Note that if the process to activate is the current process, then
* the processor internal registers must also be loaded; otherwise
* the current process will have wrong pagetables.
*/
void
pmap_activate(p)
struct proc *p;
{
pmap_t pmap = p->p_vmspace->vm_map.pmap;
struct pcb *pcb = &p->p_addr->u_pcb;
pcb->P0BR = pmap->pm_p0br;
pcb->P0LR = pmap->pm_p0lr;
pcb->P1BR = pmap->pm_p1br;
pcb->P1LR = pmap->pm_p1lr;
if (p == curproc) {
mtpr(pmap->pm_p0br, PR_P0BR);
mtpr(pmap->pm_p0lr, PR_P0LR);
mtpr(pmap->pm_p1br, PR_P1BR);
mtpr(pmap->pm_p1lr, PR_P1LR);
}
mtpr(0, PR_TBIA);
}
/*
* Deactivate the address space for the specified process.
*/
void
pmap_deactivate(p)
struct proc *p;
{
}