Subject: Re: Using different cache modes for r/o vs r/w pages
To: None <port-arm@netbsd.org>
From: Jason R Thorpe <thorpej@wasabisystems.com>
List: port-arm
Date: 02/01/2002 09:39:29
--WYTEVAkct0FjGQmd
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
On Thu, Jan 31, 2002 at 11:40:49AM -0800, Jason R Thorpe wrote:
> Ok, I haven't addressed these issues yet, but I have made all PTE
> construction use boot-time-initialized prototypes. I think the code
> is a lot cleaner now.
In an effort to address some of the efficiency issues, I went ahead
and switched the arm32 pmap to use vm_page_md instead of separate
attrs and pv_head arrays. This is a direction we want to move in
anyway, since it's a lot more efficent in terms of memory usage, cache
footprint, and eliminates unnecessary data lookups.
Now that I am planning on doing is putting the PT_NC attribute into
pg->mdpage.pvh_attrs, rather than having to traverse the pv_entry list
to determine the caching status for a page (IIRC, it must always be
true that if one mapping of a page is NC, *all* mappings of that page
must be NC).
Attached are the current pmap diffs.
--
-- Jason R. Thorpe <thorpej@wasabisystems.com>
--WYTEVAkct0FjGQmd
Content-Type: text/plain; charset=us-ascii
Content-Description: pmap-cache-take5
Content-Disposition: attachment; filename=foo
Index: arm/arm32/pmap.c
===================================================================
RCS file: /cvsroot/syssrc/sys/arch/arm/arm32/pmap.c,v
retrieving revision 1.36
diff -u -p -r1.36 pmap.c
--- arm/arm32/pmap.c 2002/01/25 19:19:25 1.36
+++ arm/arm32/pmap.c 2002/02/01 17:30:57
@@ -1,6 +1,7 @@
/* $NetBSD: pmap.c,v 1.36 2002/01/25 19:19:25 thorpej Exp $ */
/*
+ * Copyright (c) 2002 Wasabi Systems, Inc.
* Copyright (c) 2001 Richard Earnshaw
* Copyright (c) 2001 Christopher Gilbert
* All rights reserved.
@@ -193,6 +194,7 @@ pt_entry_t msgbufpte;
extern caddr_t msgbufaddr;
boolean_t pmap_initialized = FALSE; /* Has pmap_init completed? */
+
/*
* locking data structures
*/
@@ -241,7 +243,7 @@ static struct pv_entry *pmap_alloc_pv __
#define ALLOCPV_TRY 1 /* just try to allocate, don't steal */
#define ALLOCPV_NONEED 2 /* don't need PV, just growing cache */
static struct pv_entry *pmap_alloc_pvpage __P((struct pmap *, int));
-static void pmap_enter_pv __P((struct pv_head *,
+static void pmap_enter_pv __P((struct vm_page *,
struct pv_entry *, struct pmap *,
vaddr_t, struct vm_page *, int));
static void pmap_free_pv __P((struct pmap *, struct pv_entry *));
@@ -249,27 +251,26 @@ static void pmap_free_pvs __P((struct
static void pmap_free_pv_doit __P((struct pv_entry *));
static void pmap_free_pvpage __P((void));
static boolean_t pmap_is_curpmap __P((struct pmap *));
-static struct pv_entry *pmap_remove_pv __P((struct pv_head *, struct pmap *,
+static struct pv_entry *pmap_remove_pv __P((struct vm_page *, struct pmap *,
vaddr_t));
#define PMAP_REMOVE_ALL 0 /* remove all mappings */
#define PMAP_REMOVE_SKIPWIRED 1 /* skip wired mappings */
-static u_int pmap_modify_pv __P((struct pmap *, vaddr_t, struct pv_head *,
+static u_int pmap_modify_pv __P((struct pmap *, vaddr_t, struct vm_page *,
u_int, u_int));
static void pmap_free_l1pt __P((struct l1pt *));
static int pmap_allocpagedir __P((struct pmap *));
static int pmap_clean_page __P((struct pv_entry *, boolean_t));
-static struct pv_head *pmap_find_pvh __P((paddr_t));
-static void pmap_remove_all __P((paddr_t));
+static void pmap_remove_all __P((struct vm_page *));
vsize_t npages;
static struct vm_page *pmap_alloc_ptp __P((struct pmap *, vaddr_t, boolean_t));
static struct vm_page *pmap_get_ptp __P((struct pmap *, vaddr_t, boolean_t));
-__inline static void pmap_clearbit __P((paddr_t, unsigned int));
-__inline static boolean_t pmap_testbit __P((paddr_t, unsigned int));
+__inline static void pmap_clearbit __P((struct vm_page *, unsigned int));
+__inline static boolean_t pmap_testbit __P((struct vm_page *, unsigned int));
extern paddr_t physical_start;
extern paddr_t physical_freestart;
@@ -303,7 +304,7 @@ int l1pt_reuse_count; /* stat - L1's r
/* Local function prototypes (not used outside this file) */
pt_entry_t *pmap_pte __P((struct pmap *pmap, vaddr_t va));
-void pmap_copy_on_write __P((paddr_t pa));
+void pmap_copy_on_write __P((struct vm_page *));
void pmap_pinit __P((struct pmap *));
void pmap_freepagedir __P((struct pmap *));
@@ -318,19 +319,21 @@ static __inline void pmap_map_in_l1 __P(
static pt_entry_t *pmap_map_ptes __P((struct pmap *));
static void pmap_unmap_ptes __P((struct pmap *));
-__inline static void pmap_vac_me_harder __P((struct pmap *, struct pv_head *,
+__inline static void pmap_vac_me_harder __P((struct pmap *, struct vm_page *,
pt_entry_t *, boolean_t));
-static void pmap_vac_me_kpmap __P((struct pmap *, struct pv_head *,
+static void pmap_vac_me_kpmap __P((struct pmap *, struct vm_page *,
pt_entry_t *, boolean_t));
-static void pmap_vac_me_user __P((struct pmap *, struct pv_head *,
+static void pmap_vac_me_user __P((struct pmap *, struct vm_page *,
pt_entry_t *, boolean_t));
/*
- * Cache enable bits in PTE to use on pages that are cacheable.
- * On most machines this is cacheable/bufferable, but on some, eg arm10, we
- * can chose between write-through and write-back cacheing.
+ * Prototype PTE and L1 section descriptor arrays. These are initialized
+ * in pmap_pte_protos_init_*().
*/
-pt_entry_t pte_cache_mode = (PT_C | PT_B);
+pt_entry_t pte_protos[4][8];
+pd_entry_t l1sec_protos[2][8];
+pt_entry_t lpte_protos[2][8];
+pd_entry_t pde_proto;
/*
* real definition of pv_entry.
@@ -799,15 +802,15 @@ pmap_free_pvpage()
/*
* main pv_entry manipulation functions:
- * pmap_enter_pv: enter a mapping onto a pv_head list
- * pmap_remove_pv: remove a mappiing from a pv_head list
+ * pmap_enter_pv: enter a mapping onto a vm_page list
+ * pmap_remove_pv: remove a mappiing from a vm_page list
*
* NOTE: pmap_enter_pv expects to lock the pvh itself
* pmap_remove_pv expects te caller to lock the pvh before calling
*/
/*
- * pmap_enter_pv: enter a mapping onto a pv_head lst
+ * pmap_enter_pv: enter a mapping onto a vm_page lst
*
* => caller should hold the proper lock on pmap_main_lock
* => caller should have pmap locked
@@ -817,8 +820,8 @@ pmap_free_pvpage()
*/
__inline static void
-pmap_enter_pv(pvh, pve, pmap, va, ptp, flags)
- struct pv_head *pvh;
+pmap_enter_pv(pg, pve, pmap, va, ptp, flags)
+ struct vm_page *pg;
struct pv_entry *pve; /* preallocated pve for us to use */
struct pmap *pmap;
vaddr_t va;
@@ -829,10 +832,12 @@ pmap_enter_pv(pvh, pve, pmap, va, ptp, f
pve->pv_va = va;
pve->pv_ptp = ptp; /* NULL for kernel pmap */
pve->pv_flags = flags;
- simple_lock(&pvh->pvh_lock); /* lock pv_head */
- pve->pv_next = pvh->pvh_list; /* add to ... */
- pvh->pvh_list = pve; /* ... locked list */
- simple_unlock(&pvh->pvh_lock); /* unlock, done! */
+
+ simple_lock(&pg->mdpage.pvh_slock); /* lock pv_head */
+ pve->pv_next = pg->mdpage.pvh_list; /* add to ... */
+ pg->mdpage.pvh_list = pve; /* ... locked list */
+ simple_unlock(&pg->mdpage.pvh_slock); /* unlock, done! */
+
if (pve->pv_flags & PT_W)
++pmap->pm_stats.wired_count;
}
@@ -849,14 +854,14 @@ pmap_enter_pv(pvh, pve, pmap, va, ptp, f
*/
__inline static struct pv_entry *
-pmap_remove_pv(pvh, pmap, va)
- struct pv_head *pvh;
+pmap_remove_pv(pg, pmap, va)
+ struct vm_page *pg;
struct pmap *pmap;
vaddr_t va;
{
struct pv_entry *pve, **prevptr;
- prevptr = &pvh->pvh_list; /* previous pv_entry pointer */
+ prevptr = &pg->mdpage.pvh_list; /* previous pv_entry pointer */
pve = *prevptr;
while (pve) {
if (pve->pv_pmap == pmap && pve->pv_va == va) { /* match? */
@@ -872,7 +877,6 @@ pmap_remove_pv(pvh, pmap, va)
}
/*
- *
* pmap_modify_pv: Update pv flags
*
* => caller should hold lock on pv_head [so that attrs can be adjusted]
@@ -886,10 +890,10 @@ pmap_remove_pv(pvh, pmap, va)
/*__inline */
static u_int
-pmap_modify_pv(pmap, va, pvh, bic_mask, eor_mask)
+pmap_modify_pv(pmap, va, pg, bic_mask, eor_mask)
struct pmap *pmap;
vaddr_t va;
- struct pv_head *pvh;
+ struct vm_page *pg;
u_int bic_mask;
u_int eor_mask;
{
@@ -900,7 +904,7 @@ pmap_modify_pv(pmap, va, pvh, bic_mask,
* There is at least one VA mapping this page.
*/
- for (npv = pvh->pvh_list; npv; npv = npv->pv_next) {
+ for (npv = pg->mdpage.pvh_list; npv; npv = npv->pv_next) {
if (pmap == npv->pv_pmap && va == npv->pv_va) {
oflags = npv->pv_flags;
npv->pv_flags = flags =
@@ -933,22 +937,27 @@ pmap_map_in_l1(pmap, va, l2pa, selfref)
/* Calculate the index into the L1 page table. */
ptva = (va >> PDSHIFT) & ~3;
- PDEBUG(0, printf("wiring %08lx in to pd%p pte0x%lx va0x%lx\n", l2pa,
- pmap->pm_pdir, L1_PTE(l2pa), ptva));
+ PDEBUG(0, printf("wiring %08lx in to pd=%p pte=0x%lx va=0x%lx\n",
+ l2pa, pmap->pm_pdir, l2pa | pde_proto, ptva));
/* Map page table into the L1. */
- pmap->pm_pdir[ptva + 0] = L1_PTE(l2pa + 0x000);
- pmap->pm_pdir[ptva + 1] = L1_PTE(l2pa + 0x400);
- pmap->pm_pdir[ptva + 2] = L1_PTE(l2pa + 0x800);
- pmap->pm_pdir[ptva + 3] = L1_PTE(l2pa + 0xc00);
+ pmap->pm_pdir[ptva + 0] = (l2pa + 0x000) | pde_proto;
+ pmap->pm_pdir[ptva + 1] = (l2pa + 0x400) | pde_proto;
+ pmap->pm_pdir[ptva + 2] = (l2pa + 0x800) | pde_proto;
+ pmap->pm_pdir[ptva + 3] = (l2pa + 0xc00) | pde_proto;
PDEBUG(0, printf("pt self reference %lx in %lx\n",
- L2_PTE_NC_NB(l2pa, AP_KRW), pmap->pm_vptpt));
+ l2pa | pmap_pte_proto(pmap_kernel(),
+ VM_PROT_READ|VM_PROT_WRITE,
+ PTE_PROTO_NOCACHE),
+ pmap->pm_vptpt));
/* Map the page table into the page table area. */
if (selfref) {
*((pt_entry_t *)(pmap->pm_vptpt + ptva)) =
- L2_PTE_NC_NB(l2pa, AP_KRW);
+ l2pa | pmap_pte_proto(pmap_kernel(),
+ VM_PROT_READ|VM_PROT_WRITE,
+ PTE_PROTO_NOCACHE);
}
/* XXX should be a purge */
/* cpu_tlb_flushD();*/
@@ -1146,26 +1155,6 @@ pmap_bootstrap(kernel_l1pt, kernel_ptpt)
TAILQ_INIT(&pv_unusedpgs);
/*
- * compute the number of pages we have and then allocate RAM
- * for each pages' pv_head and saved attributes.
- */
- {
- int npages, lcv;
- vsize_t s;
-
- npages = 0;
- for (lcv = 0 ; lcv < vm_nphysseg ; lcv++)
- npages += (vm_physmem[lcv].end - vm_physmem[lcv].start);
- s = (vsize_t) (sizeof(struct pv_head) * npages +
- sizeof(char) * npages);
- s = round_page(s); /* round up */
- boot_head = (char *)uvm_pageboot_alloc(s);
- bzero((char *)boot_head, s);
- if (boot_head == 0)
- panic("pmap_init: unable to allocate pv_heads");
- }
-
- /*
* initialize the pmap pool.
*/
@@ -1188,11 +1177,6 @@ extern int physmem;
void
pmap_init()
{
- int lcv, i;
-
-#ifdef MYCROFT_HACK
- printf("physmem = %d\n", physmem);
-#endif
/*
* Set the available memory vars - These do not map to real memory
@@ -1204,25 +1188,6 @@ pmap_init()
avail_start = 0;
avail_end = physmem * NBPG;
- /* allocate pv_head stuff first */
- for (lcv = 0 ; lcv < vm_nphysseg ; lcv++) {
- vm_physmem[lcv].pmseg.pvhead = (struct pv_head *)boot_head;
- boot_head = (char *)(vaddr_t)(vm_physmem[lcv].pmseg.pvhead +
- (vm_physmem[lcv].end - vm_physmem[lcv].start));
- for (i = 0;
- i < (vm_physmem[lcv].end - vm_physmem[lcv].start); i++) {
- simple_lock_init(
- &vm_physmem[lcv].pmseg.pvhead[i].pvh_lock);
- }
- }
-
- /* now allocate attrs */
- for (lcv = 0 ; lcv < vm_nphysseg ; lcv++) {
- vm_physmem[lcv].pmseg.attrs = (char *) boot_head;
- boot_head = (char *)(vaddr_t)(vm_physmem[lcv].pmseg.attrs +
- (vm_physmem[lcv].end - vm_physmem[lcv].start));
- }
-
/*
* now we need to free enough pv_entry structures to allow us to get
* the kmem_map/kmem_object allocated and inited (done after this
@@ -1238,14 +1203,6 @@ pmap_init()
pv_nfpvents = 0;
(void) pmap_add_pvpage(pv_initpage, FALSE);
-#ifdef MYCROFT_HACK
- for (lcv = 0 ; lcv < vm_nphysseg ; lcv++) {
- printf("physseg[%d] pvent=%p attrs=%p start=%ld end=%ld\n",
- lcv,
- vm_physmem[lcv].pmseg.pvent, vm_physmem[lcv].pmseg.attrs,
- vm_physmem[lcv].start, vm_physmem[lcv].end);
- }
-#endif
pmap_initialized = TRUE;
/* Initialise our L1 page table queues and counters */
@@ -1392,7 +1349,11 @@ pmap_alloc_l1pt(void)
/* Revoke cacheability and bufferability */
/* XXX should be done better than this */
- ptes[arm_byte_to_page(va)] &= ~(PT_C | PT_B);
+ ptes[arm_byte_to_page(va)] =
+ (ptes[arm_byte_to_page(va)] & PG_FRAME) |
+ pmap_pte_proto(pmap_kernel(),
+ VM_PROT_READ|VM_PROT_WRITE,
+ PTE_PROTO_NOCACHE);
va += NBPG;
m = m->pageq.tqe_next;
@@ -1506,7 +1467,9 @@ pmap_allocpagedir(pmap)
/* Revoke cacheability and bufferability */
/* XXX should be done better than this */
pte = pmap_pte(pmap_kernel(), pmap->pm_vptpt);
- *pte = *pte & ~(PT_C | PT_B);
+ *pte = (*pte & PG_FRAME) | pmap_pte_proto(pmap_kernel(),
+ VM_PROT_READ|VM_PROT_WRITE,
+ PTE_PROTO_NOCACHE);
/* Wire in this page table */
pmap_map_in_l1(pmap, PROCESS_PAGE_TBLS_BASE, pmap->pm_pptpt, TRUE);
@@ -1836,25 +1799,6 @@ pmap_clean_page(pv, is_src)
}
/*
- * pmap_find_pv()
- *
- * This is a local function that finds a PV head for a given physical page.
- * This is a common op, and this function removes loads of ifdefs in the code.
- */
-static __inline struct pv_head *
-pmap_find_pvh(phys)
- paddr_t phys;
-{
- int bank, off;
- struct pv_head *pvh;
-
- if ((bank = vm_physseg_find(atop(phys), &off)) == -1)
- panic("pmap_find_pv: not a real page, phys=%lx\n", phys);
- pvh = &vm_physmem[bank].pmseg.pvhead[off];
- return (pvh);
-}
-
-/*
* pmap_zero_page()
*
* Zero a given physical page by mapping it at a page hook point.
@@ -1866,22 +1810,29 @@ void
pmap_zero_page(phys)
paddr_t phys;
{
- struct pv_head *pvh;
+ struct vm_page *pg;
/* Get an entry for this page, and clean it it. */
- pvh = pmap_find_pvh(phys);
- simple_lock(&pvh->pvh_lock);
- pmap_clean_page(pvh->pvh_list, FALSE);
- simple_unlock(&pvh->pvh_lock);
+ pg = PHYS_TO_VM_PAGE(phys);
+ simple_lock(&pg->mdpage.pvh_slock);
+ pmap_clean_page(pg->mdpage.pvh_list, FALSE);
+ simple_unlock(&pg->mdpage.pvh_slock);
/*
* Hook in the page, zero it, and purge the cache for that
* zeroed page. Invalidate the TLB as needed.
*/
- *page_hook0.pte = L2_PTE(phys & PG_FRAME, AP_KRW);
+ KDASSERT((phys & PG_FRAME) == phys);
+ *page_hook0.pte = phys |
+ pmap_pte_proto(pmap_kernel(),
+ VM_PROT_READ|VM_PROT_WRITE,
+ PTE_PROTO_CACHE);
cpu_tlb_flushD_SE(page_hook0.va);
+
cpu_cpwait();
+
bzero_page(page_hook0.va);
+
cpu_dcache_wbinv_range(page_hook0.va, NBPG);
}
@@ -1899,10 +1850,10 @@ pmap_pageidlezero(phys)
boolean_t rv = TRUE;
#ifdef DIAGNOSTIC
- struct pv_head *pvh;
+ struct vm_page *pg;
- pvh = pmap_find_pvh(phys);
- if (pvh->pvh_list != NULL)
+ pg = PHYS_TO_VM_PAGE(phys);
+ if (pg->mdpage.pvh_list != NULL)
panic("pmap_pageidlezero: zeroing mapped page\n");
#endif
@@ -1910,7 +1861,11 @@ pmap_pageidlezero(phys)
* Hook in the page, zero it, and purge the cache for that
* zeroed page. Invalidate the TLB as needed.
*/
- *page_hook0.pte = L2_PTE(phys & PG_FRAME, AP_KRW);
+ KDASSERT((phys & PG_FRAME) == phys);
+ *page_hook0.pte = phys |
+ pmap_pte_proto(pmap_kernel(),
+ VM_PROT_READ|VM_PROT_WRITE,
+ PTE_PROTO_CACHE);
cpu_tlb_flushD_SE(page_hook0.va);
cpu_cpwait();
@@ -1950,33 +1905,45 @@ pmap_copy_page(src, dest)
paddr_t src;
paddr_t dest;
{
- struct pv_head *src_pvh, *dest_pvh;
+ struct vm_page *src_pg, *dest_pg;
boolean_t cleanedcache;
/* Get PV entries for the pages, and clean them if needed. */
- src_pvh = pmap_find_pvh(src);
+ src_pg = PHYS_TO_VM_PAGE(src);
- simple_lock(&src_pvh->pvh_lock);
- cleanedcache = pmap_clean_page(src_pvh->pvh_list, TRUE);
- simple_unlock(&src_pvh->pvh_lock);
+ simple_lock(&src_pg->mdpage.pvh_slock);
+ cleanedcache = pmap_clean_page(src_pg->mdpage.pvh_list, TRUE);
+ simple_unlock(&src_pg->mdpage.pvh_slock);
if (cleanedcache == 0) {
- dest_pvh = pmap_find_pvh(dest);
- simple_lock(&dest_pvh->pvh_lock);
- pmap_clean_page(dest_pvh->pvh_list, FALSE);
- simple_unlock(&dest_pvh->pvh_lock);
+ dest_pg = PHYS_TO_VM_PAGE(dest);
+ simple_lock(&dest_pg->mdpage.pvh_slock);
+ pmap_clean_page(dest_pg->mdpage.pvh_list, FALSE);
+ simple_unlock(&dest_pg->mdpage.pvh_slock);
}
/*
* Map the pages into the page hook points, copy them, and purge
* the cache for the appropriate page. Invalidate the TLB
* as required.
*/
- *page_hook0.pte = L2_PTE(src & PG_FRAME, AP_KRW);
- *page_hook1.pte = L2_PTE(dest & PG_FRAME, AP_KRW);
+ KDASSERT((src & PG_FRAME) == src);
+ *page_hook0.pte = src | /* XXX should be r/o */
+ pmap_pte_proto(pmap_kernel(),
+ VM_PROT_READ|VM_PROT_WRITE,
+ PTE_PROTO_CACHE);
cpu_tlb_flushD_SE(page_hook0.va);
+
+ KDASSERT((dst & PG_FRAME) == dst);
+ *page_hook1.pte = dest |
+ pmap_pte_proto(pmap_kernel(),
+ VM_PROT_READ|VM_PROT_WRITE,
+ PTE_PROTO_CACHE);
cpu_tlb_flushD_SE(page_hook1.va);
+
cpu_cpwait();
+
bcopy_page(page_hook0.va, page_hook1.va);
+
cpu_dcache_wbinv_range(page_hook0.va, NBPG);
cpu_dcache_wbinv_range(page_hook1.va, NBPG);
}
@@ -2069,17 +2036,17 @@ pmap_pte_delref(pmap, va)
* Note that the pmap must have it's ptes mapped in, and passed with ptes.
*/
__inline static void
-pmap_vac_me_harder(struct pmap *pmap, struct pv_head *pvh, pt_entry_t *ptes,
+pmap_vac_me_harder(struct pmap *pmap, struct vm_page *pg, pt_entry_t *ptes,
boolean_t clear_cache)
{
if (pmap == pmap_kernel())
- pmap_vac_me_kpmap(pmap, pvh, ptes, clear_cache);
+ pmap_vac_me_kpmap(pmap, pg, ptes, clear_cache);
else
- pmap_vac_me_user(pmap, pvh, ptes, clear_cache);
+ pmap_vac_me_user(pmap, pg, ptes, clear_cache);
}
static void
-pmap_vac_me_kpmap(struct pmap *pmap, struct pv_head *pvh, pt_entry_t *ptes,
+pmap_vac_me_kpmap(struct pmap *pmap, struct vm_page *pg, pt_entry_t *ptes,
boolean_t clear_cache)
{
int user_entries = 0;
@@ -2101,7 +2068,7 @@ pmap_vac_me_kpmap(struct pmap *pmap, str
* this page. Calculate whether there are user-writable or
* kernel-writable pages.
*/
- for (pv = pvh->pvh_list; pv != NULL; pv = pv->pv_next) {
+ for (pv = pg->mdpage.pvh_list; pv != NULL; pv = pv->pv_next) {
if (pv->pv_pmap != pmap) {
user_entries++;
if (pv->pv_flags & PT_Wr)
@@ -2132,7 +2099,7 @@ pmap_vac_me_kpmap(struct pmap *pmap, str
* might not be set correctly, call pmap_vac_me_user
* to recalculate the settings.
*/
- for (pv = pvh->pvh_list; pv; pv = pv->pv_next) {
+ for (pv = pg->mdpage.pvh_list; pv; pv = pv->pv_next) {
/*
* We know kernel mappings will get set
* correctly in other calls. We also know
@@ -2167,7 +2134,7 @@ pmap_vac_me_kpmap(struct pmap *pmap, str
pmap_unmap_ptes(last_pmap);
last_pmap = pv->pv_pmap;
ptes = pmap_map_ptes(last_pmap);
- pmap_vac_me_user(last_pmap, pvh, ptes,
+ pmap_vac_me_user(last_pmap, pg, ptes,
pmap_is_curpmap(last_pmap));
}
/* Restore the pte mapping that was passed to us. */
@@ -2179,12 +2146,11 @@ pmap_vac_me_kpmap(struct pmap *pmap, str
return;
}
- pmap_vac_me_user(pmap, pvh, ptes, clear_cache);
- return;
+ pmap_vac_me_user(pmap, pg, ptes, clear_cache);
}
static void
-pmap_vac_me_user(struct pmap *pmap, struct pv_head *pvh, pt_entry_t *ptes,
+pmap_vac_me_user(struct pmap *pmap, struct vm_page *pg, pt_entry_t *ptes,
boolean_t clear_cache)
{
struct pmap *kpmap = pmap_kernel();
@@ -2194,8 +2160,9 @@ pmap_vac_me_user(struct pmap *pmap, stru
int cacheable_entries = 0;
int kern_cacheable = 0;
int other_writable = 0;
+ int prot;
- pv = pvh->pvh_list;
+ pv = pg->mdpage.pvh_list;
KASSERT(ptes != NULL);
/*
@@ -2237,12 +2204,12 @@ pmap_vac_me_user(struct pmap *pmap, stru
if (cacheable_entries == 0)
return;
for (npv = pv; npv; npv = npv->pv_next) {
- if ((pmap == npv->pv_pmap
- || kpmap == npv->pv_pmap) &&
+ if ((pmap == npv->pv_pmap ||
+ kpmap == npv->pv_pmap) &&
(npv->pv_flags & PT_NC) == 0) {
- ptes[arm_byte_to_page(npv->pv_va)] &=
- ~(PT_C | PT_B);
- npv->pv_flags |= PT_NC;
+ prot = (npv->pv_flags & PT_Wr) ?
+ VM_PROT_READ | VM_PROT_WRITE :
+ VM_PROT_READ;
/*
* If this page needs flushing from the
* cache, and we aren't going to do it
@@ -2256,6 +2223,11 @@ pmap_vac_me_user(struct pmap *pmap, stru
NBPG);
cpu_tlb_flushID_SE(npv->pv_va);
}
+ ptes[arm_byte_to_page(npv->pv_va)] =
+ ptes[arm_byte_to_page(npv->pv_va)] |
+ pmap_pte_proto(npv->pv_pmap, prot,
+ PTE_PROTO_NOCACHE);
+ npv->pv_flags |= PT_NC;
}
}
if ((clear_cache && cacheable_entries >= 4) ||
@@ -2273,8 +2245,13 @@ pmap_vac_me_user(struct pmap *pmap, stru
if ((pmap == npv->pv_pmap ||
(kpmap == npv->pv_pmap && other_writable == 0)) &&
(npv->pv_flags & PT_NC)) {
- ptes[arm_byte_to_page(npv->pv_va)] |=
- pte_cache_mode;
+ prot = (npv->pv_flags & PT_Wr) ?
+ VM_PROT_READ | VM_PROT_WRITE :
+ VM_PROT_READ;
+ ptes[arm_byte_to_page(npv->pv_va)] =
+ ptes[arm_byte_to_page(npv->pv_va)] |
+ pmap_pte_proto(npv->pv_pmap, prot,
+ PTE_PROTO_CACHE);
npv->pv_flags &= ~PT_NC;
}
}
@@ -2315,7 +2292,7 @@ pmap_remove(pmap, sva, eva)
pt_entry_t *pte = 0, *ptes;
paddr_t pa;
int pmap_active;
- struct pv_head *pvh;
+ struct vm_page *pg;
/* Exit quick if there is no pmap */
if (!pmap)
@@ -2359,8 +2336,6 @@ pmap_remove(pmap, sva, eva)
/* We've found a valid PTE, so this page of PTEs has to go. */
if (pmap_pte_v(pte)) {
- int bank, off;
-
/* Update statistics */
--pmap->pm_stats.resident_count;
@@ -2417,14 +2392,14 @@ pmap_remove(pmap, sva, eva)
* we could cluster a lot of these and do a
* number of sequential pages in one go.
*/
- if ((bank = vm_physseg_find(atop(pa), &off)) != -1) {
+ if ((pg = PHYS_TO_VM_PAGE(pa)) != NULL) {
struct pv_entry *pve;
- pvh = &vm_physmem[bank].pmseg.pvhead[off];
- simple_lock(&pvh->pvh_lock);
- pve = pmap_remove_pv(pvh, pmap, sva);
+
+ simple_lock(&pg->mdpage.pvh_slock);
+ pve = pmap_remove_pv(pg, pmap, sva);
pmap_free_pv(pmap, pve);
- pmap_vac_me_harder(pmap, pvh, ptes, FALSE);
- simple_unlock(&pvh->pvh_lock);
+ pmap_vac_me_harder(pmap, pg, ptes, FALSE);
+ simple_unlock(&pg->mdpage.pvh_slock);
}
}
sva += NBPG;
@@ -2462,29 +2437,26 @@ pmap_remove(pmap, sva, eva)
*/
static void
-pmap_remove_all(pa)
- paddr_t pa;
+pmap_remove_all(pg)
+ struct vm_page *pg;
{
struct pv_entry *pv, *npv;
- struct pv_head *pvh;
struct pmap *pmap;
pt_entry_t *pte, *ptes;
- PDEBUG(0, printf("pmap_remove_all: pa=%lx ", pa));
+ PDEBUG(0, printf("pmap_remove_all: pa=%lx ", VM_PAGE_TO_PHYS(pg)));
/* set pv_head => pmap locking */
PMAP_HEAD_TO_MAP_LOCK();
- pvh = pmap_find_pvh(pa);
- simple_lock(&pvh->pvh_lock);
-
- pv = pvh->pvh_list;
- if (pv == NULL)
- {
- PDEBUG(0, printf("free page\n"));
- simple_unlock(&pvh->pvh_lock);
- PMAP_HEAD_TO_MAP_UNLOCK();
- return;
+ simple_lock(&pg->mdpage.pvh_slock);
+
+ pv = pg->mdpage.pvh_list;
+ if (pv == NULL) {
+ PDEBUG(0, printf("free page\n"));
+ simple_unlock(&pg->mdpage.pvh_slock);
+ PMAP_HEAD_TO_MAP_UNLOCK();
+ return;
}
pmap_clean_page(pv, FALSE);
@@ -2528,8 +2500,8 @@ reduce wiring count on page table pages
pv = npv;
pmap_unmap_ptes(pmap);
}
- pvh->pvh_list = NULL;
- simple_unlock(&pvh->pvh_lock);
+ pg->mdpage.pvh_list = NULL;
+ simple_unlock(&pg->mdpage.pvh_slock);
PMAP_HEAD_TO_MAP_UNLOCK();
PDEBUG(0, printf("done\n"));
@@ -2553,8 +2525,7 @@ pmap_protect(pmap, sva, eva, prot)
int armprot;
int flush = 0;
paddr_t pa;
- int bank, off;
- struct pv_head *pvh;
+ struct vm_page *pg;
PDEBUG(0, printf("pmap_protect: pmap=%p %08lx->%08lx %x\n",
pmap, sva, eva, prot));
@@ -2621,12 +2592,11 @@ pmap_protect(pmap, sva, eva, prot)
/* Get the physical page index */
/* Clear write flag */
- if ((bank = vm_physseg_find(atop(pa), &off)) != -1) {
- pvh = &vm_physmem[bank].pmseg.pvhead[off];
- simple_lock(&pvh->pvh_lock);
- (void) pmap_modify_pv(pmap, sva, pvh, PT_Wr, 0);
- pmap_vac_me_harder(pmap, pvh, ptes, FALSE);
- simple_unlock(&pvh->pvh_lock);
+ if ((pg = PHYS_TO_VM_PAGE(pa)) != NULL) {
+ simple_lock(&pg->mdpage.pvh_slock);
+ (void) pmap_modify_pv(pmap, sva, pg, PT_Wr, 0);
+ pmap_vac_me_harder(pmap, pg, ptes, FALSE);
+ simple_unlock(&pg->mdpage.pvh_slock);
}
next:
@@ -2665,12 +2635,11 @@ pmap_enter(pmap, va, pa, prot, flags)
{
pt_entry_t *pte, *ptes;
u_int npte;
- int bank, off;
paddr_t opa;
int nflags;
boolean_t wired = (flags & PMAP_WIRED) != 0;
struct pv_entry *pve;
- struct pv_head *pvh;
+ struct vm_page *pg;
int error;
PDEBUG(5, printf("pmap_enter: V%08lx P%08lx in pmap %p prot=%08x, wired = %d\n",
@@ -2690,6 +2659,13 @@ pmap_enter(pmap, va, pa, prot, flags)
panic("pmap_enter: entering PT page");
}
#endif
+
+ /*
+ * Get pointer to the page. Later on in this function, we
+ * test for a managed page by checking pg != NULL.
+ */
+ pg = PHYS_TO_VM_PAGE(pa);
+
/* get lock */
PMAP_MAP_TO_HEAD_LOCK();
/*
@@ -2746,14 +2722,11 @@ pmap_enter(pmap, va, pa, prot, flags)
va, pa));
/* Has the wiring changed ? */
- if ((bank = vm_physseg_find(atop(pa), &off)) != -1) {
- pvh = &vm_physmem[bank].pmseg.pvhead[off];
- simple_lock(&pvh->pvh_lock);
- (void) pmap_modify_pv(pmap, va, pvh,
+ if (pg != NULL) {
+ simple_lock(&pg->mdpage.pvh_slock);
+ (void) pmap_modify_pv(pmap, va, pg,
PT_Wr | PT_W, nflags);
- simple_unlock(&pvh->pvh_lock);
- } else {
- pvh = NULL;
+ simple_unlock(&pg->mdpage.pvh_slock);
}
} else {
/* We are replacing the page with a new one. */
@@ -2766,11 +2739,10 @@ pmap_enter(pmap, va, pa, prot, flags)
* If it is part of our managed memory then we
* must remove it from the PV list
*/
- if ((bank = vm_physseg_find(atop(opa), &off)) != -1) {
- pvh = &vm_physmem[bank].pmseg.pvhead[off];
- simple_lock(&pvh->pvh_lock);
- pve = pmap_remove_pv(pvh, pmap, va);
- simple_unlock(&pvh->pvh_lock);
+ if (pg != NULL) {
+ simple_lock(&pg->mdpage.pvh_slock);
+ pve = pmap_remove_pv(pg, pmap, va);
+ simple_unlock(&pg->mdpage.pvh_slock);
} else {
pve = NULL;
}
@@ -2789,10 +2761,7 @@ pmap_enter(pmap, va, pa, prot, flags)
/*
* Enter on the PV list if part of our managed memory
*/
- bank = vm_physseg_find(atop(pa), &off);
-
- if (pmap_initialized && (bank != -1)) {
- pvh = &vm_physmem[bank].pmseg.pvhead[off];
+ if (pmap_initialized && pg != NULL) {
if (pve == NULL) {
pve = pmap_alloc_pv(pmap, ALLOCPV_NEED);
if (pve == NULL) {
@@ -2804,11 +2773,9 @@ pmap_enter(pmap, va, pa, prot, flags)
}
}
/* enter_pv locks pvh when adding */
- pmap_enter_pv(pvh, pve, pmap, va, NULL, nflags);
- } else {
- pvh = NULL;
- if (pve != NULL)
- pmap_free_pv(pmap, pve);
+ pmap_enter_pv(pg, pve, pmap, va, NULL, nflags);
+ } else if (pve != NULL) {
+ pmap_free_pv(pmap, pve);
}
}
@@ -2818,33 +2785,46 @@ pmap_enter(pmap, va, pa, prot, flags)
#endif
/* Construct the pte, giving the correct access. */
- npte = (pa & PG_FRAME);
+ KDASSERT((pa & PG_FRAME) == pa);
+ npte = pa;
- /* VA 0 is magic. */
- if (pmap != pmap_kernel() && va != 0)
- npte |= PT_AP(AP_U);
-
- if (pmap_initialized && bank != -1) {
+ /*
+ * VA 0 is magic; that's where the vector page is. User pmaps
+ * always need to see an un-cached view of this page (which they
+ * would anyway, since it's not in the managed page pool, so there
+ * is no need to check for it).
+ */
+ if (pmap_initialized && pg != NULL) {
+ KDASSERT(va != 0);
#ifdef DIAGNOSTIC
if ((flags & VM_PROT_ALL) & ~prot)
panic("pmap_enter: access_type exceeds prot");
#endif
- npte |= pte_cache_mode;
+ /*
+ * XXXJRT -- consider optimization potential.
+ * C.f. Alpha pmap.
+ */
if (flags & VM_PROT_WRITE) {
- npte |= L2_SPAGE | PT_AP(AP_W);
- vm_physmem[bank].pmseg.attrs[off] |= PT_H | PT_M;
+ npte |= pmap_pte_proto(pmap,
+ VM_PROT_READ|VM_PROT_WRITE,
+ PTE_PROTO_CACHE);
+ pg->mdpage.pvh_attrs |= PT_H | PT_M;
} else if (flags & VM_PROT_ALL) {
- npte |= L2_SPAGE;
- vm_physmem[bank].pmseg.attrs[off] |= PT_H;
- } else
- npte |= L2_INVAL;
+ npte |= pmap_pte_proto(pmap,
+ VM_PROT_READ,
+ PTE_PROTO_CACHE);
+ pg->mdpage.pvh_attrs |= PT_H;
+ }
+ /*
+ * ...else we want to take a fault, so don't do anything
+ * to the PTE here.
+ */
} else {
- if (prot & VM_PROT_WRITE)
- npte |= L2_SPAGE | PT_AP(AP_W);
- else if (prot & VM_PROT_ALL)
- npte |= L2_SPAGE;
- else
- npte |= L2_INVAL;
+ /*
+ * Non-managed pages entered via this interface
+ * are implicitly un-cached.
+ */
+ npte |= pmap_pte_proto(pmap, prot, PTE_PROTO_NOCACHE);
}
#ifdef MYCROFT_HACK
@@ -2854,19 +2834,19 @@ pmap_enter(pmap, va, pa, prot, flags)
*pte = npte;
- if (pmap_initialized && bank != -1)
- {
+ if (pmap_initialized && pg != NULL) {
boolean_t pmap_active = FALSE;
- /* XXX this will change once the whole of pmap_enter uses
+ /*
+ * XXX this will change once the whole of pmap_enter uses
* map_ptes
*/
ptes = pmap_map_ptes(pmap);
if ((curproc && curproc->p_vmspace->vm_map.pmap == pmap)
|| (pmap == pmap_kernel()))
pmap_active = TRUE;
- simple_lock(&pvh->pvh_lock);
- pmap_vac_me_harder(pmap, pvh, ptes, pmap_active);
- simple_unlock(&pvh->pvh_lock);
+ simple_lock(&pg->mdpage.pvh_slock);
+ pmap_vac_me_harder(pmap, pg, ptes, pmap_active);
+ simple_unlock(&pg->mdpage.pvh_slock);
pmap_unmap_ptes(pmap);
}
@@ -2905,7 +2885,7 @@ pmap_kenter_pa(va, pa, prot)
*/
/* must lock the pmap */
- simple_lock(&(pmap_kernel()->pm_obj.vmobjlock));
+ simple_lock(&pmap->pm_obj.vmobjlock);
/* Allocate a page table */
pg = uvm_pagealloc(&(pmap_kernel()->pm_obj), 0, NULL,
UVM_PGA_USERESERVE | UVM_PGA_ZERO);
@@ -2916,11 +2896,18 @@ pmap_kenter_pa(va, pa, prot)
/* Wire this page table into the L1. */
pmap_map_in_l1(pmap, va, VM_PAGE_TO_PHYS(pg), TRUE);
- simple_unlock(&(pmap_kernel()->pm_obj.vmobjlock));
+ simple_unlock(&pmap->pm_obj.vmobjlock);
}
pte = vtopte(va);
KASSERT(!pmap_pte_v(pte));
- *pte = L2_PTE(pa, AP_KRW);
+#if 1 /* XXX */
+ *pte = pa | pmap_pte_proto(pmap_kernel(),
+ VM_PROT_READ|VM_PROT_WRITE,
+ PTE_PROTO_CACHE);
+#else
+ *pte = pa | pmap_pte_proto(pmap_kernel(), prot,
+ PTE_PROTO_CACHE);
+#endif
}
void
@@ -2956,9 +2943,9 @@ pmap_page_protect(pg, prot)
struct vm_page *pg;
vm_prot_t prot;
{
- paddr_t pa = VM_PAGE_TO_PHYS(pg);
- PDEBUG(0, printf("pmap_page_protect(pa=%lx, prot=%d)\n", pa, prot));
+ PDEBUG(0, printf("pmap_page_protect(pa=%lx, prot=%d)\n",
+ VM_PAGE_TO_PHYS(pg), prot));
switch(prot) {
case VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE:
@@ -2967,11 +2954,11 @@ pmap_page_protect(pg, prot)
case VM_PROT_READ:
case VM_PROT_READ|VM_PROT_EXECUTE:
- pmap_copy_on_write(pa);
+ pmap_copy_on_write(pg);
break;
default:
- pmap_remove_all(pa);
+ pmap_remove_all(pg);
break;
}
}
@@ -2992,8 +2979,7 @@ pmap_unwire(pmap, va)
{
pt_entry_t *pte;
paddr_t pa;
- int bank, off;
- struct pv_head *pvh;
+ struct vm_page *pg;
/*
* Make sure pmap is valid. -dct
@@ -3009,13 +2995,13 @@ pmap_unwire(pmap, va)
/* Extract the physical address of the page */
pa = pmap_pte_pa(pte);
- if ((bank = vm_physseg_find(atop(pa), &off)) == -1)
+ if ((pg = PHYS_TO_VM_PAGE(pa)) == NULL)
return;
- pvh = &vm_physmem[bank].pmseg.pvhead[off];
- simple_lock(&pvh->pvh_lock);
+
/* Update the wired bit in the pv entry for this page. */
- (void) pmap_modify_pv(pmap, va, pvh, PT_W, 0);
- simple_unlock(&pvh->pvh_lock);
+ simple_lock(&pg->mdpage.pvh_slock);
+ (void) pmap_modify_pv(pmap, va, pg, PT_W, 0);
+ simple_unlock(&pg->mdpage.pvh_slock);
}
/*
@@ -3200,54 +3186,44 @@ pmap_copy(dst_pmap, src_pmap, dst_addr,
#if defined(PMAP_DEBUG)
void
-pmap_dump_pvlist(phys, m)
- vaddr_t phys;
+pmap_dump_pvlist(pg, m)
+ struct vm_page *pg;
char *m;
{
- struct pv_head *pvh;
struct pv_entry *pv;
- int bank, off;
- if ((bank = vm_physseg_find(atop(phys), &off)) == -1) {
- printf("INVALID PA\n");
- return;
- }
- pvh = &vm_physmem[bank].pmseg.pvhead[off];
- simple_lock(&pvh->pvh_lock);
- printf("%s %08lx:", m, phys);
- if (pvh->pvh_list == NULL) {
+ simple_lock(&pg->mdpage.pvh_slock);
+ printf("%s %08lx:", m, VM_PAGE_TO_PHYS(pg));
+ if (pg->mdpage.pvh_list == NULL) {
printf(" no mappings\n");
return;
}
- for (pv = pvh->pvh_list; pv; pv = pv->pv_next)
+ for (pv = pg->mdpage.pvh_list; pv; pv = pv->pv_next)
printf(" pmap %p va %08lx flags %08x", pv->pv_pmap,
pv->pv_va, pv->pv_flags);
printf("\n");
- simple_unlock(&pvh->pvh_lock);
+ simple_unlock(&pg->mdpage.pvh_slock);
}
#endif /* PMAP_DEBUG */
__inline static boolean_t
-pmap_testbit(pa, setbits)
- paddr_t pa;
+pmap_testbit(pg, setbits)
+ struct vm_page *pg;
unsigned int setbits;
{
- int bank, off;
-
- PDEBUG(1, printf("pmap_testbit: pa=%08lx set=%08x\n", pa, setbits));
- if ((bank = vm_physseg_find(atop(pa), &off)) == -1)
- return(FALSE);
+ PDEBUG(1, printf("pmap_testbit: pa=%08lx set=%08x\n",
+ VM_PAGE_TO_PHYS(pg), setbits));
/*
* Check saved info only
*/
- if (vm_physmem[bank].pmseg.attrs[off] & setbits) {
+ if (pg->mdpage.pvh_attrs & setbits) {
PDEBUG(0, printf("pmap_attributes = %02x\n",
- vm_physmem[bank].pmseg.attrs[off]));
+ pg->mdpage.pvh_attrs));
return(TRUE);
}
@@ -3316,34 +3292,30 @@ pmap_unmap_ptes(pmap)
*/
static void
-pmap_clearbit(pa, maskbits)
- paddr_t pa;
+pmap_clearbit(pg, maskbits)
+ struct vm_page *pg;
unsigned int maskbits;
{
struct pv_entry *pv;
- struct pv_head *pvh;
pt_entry_t *pte;
vaddr_t va;
- int bank, off, tlbentry;
+ int tlbentry;
PDEBUG(1, printf("pmap_clearbit: pa=%08lx mask=%08x\n",
- pa, maskbits));
+ VM_PAGE_TO_PHYS(pg), maskbits));
tlbentry = 0;
- if ((bank = vm_physseg_find(atop(pa), &off)) == -1)
- return;
PMAP_HEAD_TO_MAP_LOCK();
- pvh = &vm_physmem[bank].pmseg.pvhead[off];
- simple_lock(&pvh->pvh_lock);
+ simple_lock(&pg->mdpage.pvh_slock);
/*
* Clear saved attributes (modify, reference)
*/
- vm_physmem[bank].pmseg.attrs[off] &= ~maskbits;
+ pg->mdpage.pvh_attrs &= ~maskbits;
- if (pvh->pvh_list == NULL) {
- simple_unlock(&pvh->pvh_lock);
+ if (pg->mdpage.pvh_list == NULL) {
+ simple_unlock(&pg->mdpage.pvh_slock);
PMAP_HEAD_TO_MAP_UNLOCK();
return;
}
@@ -3351,13 +3323,13 @@ pmap_clearbit(pa, maskbits)
/*
* Loop over all current mappings setting/clearing as appropos
*/
- for (pv = pvh->pvh_list; pv; pv = pv->pv_next) {
+ for (pv = pg->mdpage.pvh_list; pv; pv = pv->pv_next) {
va = pv->pv_va;
pv->pv_flags &= ~maskbits;
pte = pmap_pte(pv->pv_pmap, va);
KASSERT(pte != NULL);
if (maskbits & (PT_Wr|PT_M)) {
- if ((pv->pv_flags & PT_NC)) {
+ if (pv->pv_flags & PT_NC) {
/*
* Entry is not cacheable: reenable
* the cache, nothing to flush
@@ -3375,36 +3347,56 @@ pmap_clearbit(pa, maskbits)
*
*/
if (maskbits & PT_Wr) {
- *pte |= pte_cache_mode;
+ /*
+ * Clear the NC bit in the pv
+ * entry; we'll update the PTE
+ * below.
+ */
pv->pv_flags &= ~PT_NC;
}
- } else if (pmap_is_curpmap(pv->pv_pmap))
- /*
+ } else if (pmap_is_curpmap(pv->pv_pmap)) {
+ /*
* Entry is cacheable: check if pmap is
- * current if it is flush it,
- * otherwise it won't be in the cache
+ * current, and if it is, flush it,
+ * otherwise it won't be in the cache.
*/
cpu_idcache_wbinv_range(pv->pv_va, NBPG);
+ }
- /* make the pte read only */
- *pte &= ~PT_AP(AP_W);
+ /* Make the PTE read-only. */
+ *pte = (*pte & PG_FRAME) |
+ pmap_pte_proto(pv->pv_pmap, VM_PROT_READ,
+ (pv->pv_flags & PT_NC) ?
+ PTE_PROTO_NOCACHE :
+ PTE_PROTO_CACHE);
}
- if (maskbits & PT_H)
- *pte = (*pte & ~L2_MASK) | L2_INVAL;
+ if (maskbits & PT_H) {
+ /*
+ * We are going to revoke the mapping for this
+ * page. If it is writable, make sure to flush
+ * it from the cache.
+ *
+ * XXXJRT This flush might be redundant!
+ */
+ if ((pv->pv_flags & PT_Wr) != 0 &&
+ pmap_is_curpmap(pv->pv_pmap))
+ cpu_idcache_wbinv_range(pv->pv_va, NBPG);
- if (pmap_is_curpmap(pv->pv_pmap))
+ *pte = *pte & PG_FRAME;
+ }
+
+ if (pmap_is_curpmap(pv->pv_pmap)) {
/*
- * if we had cacheable pte's we'd clean the
- * pte out to memory here
- *
- * flush tlb entry as it's in the current pmap
+ * The PTE has been modifed, and it's in the
+ * current pmap, invalidate the TLB entry.
*/
cpu_tlb_flushID_SE(pv->pv_va);
+ }
}
cpu_cpwait();
- simple_unlock(&pvh->pvh_lock);
+ simple_unlock(&pg->mdpage.pvh_slock);
PMAP_HEAD_TO_MAP_UNLOCK();
}
@@ -3413,12 +3405,11 @@ boolean_t
pmap_clear_modify(pg)
struct vm_page *pg;
{
- paddr_t pa = VM_PAGE_TO_PHYS(pg);
boolean_t rv;
- PDEBUG(0, printf("pmap_clear_modify pa=%08lx\n", pa));
- rv = pmap_testbit(pa, PT_M);
- pmap_clearbit(pa, PT_M);
+ PDEBUG(0, printf("pmap_clear_modify pa=%08lx\n", VM_PAGE_TO_PHYS(pg)));
+ rv = pmap_testbit(pg, PT_M);
+ pmap_clearbit(pg, PT_M);
return rv;
}
@@ -3427,22 +3418,23 @@ boolean_t
pmap_clear_reference(pg)
struct vm_page *pg;
{
- paddr_t pa = VM_PAGE_TO_PHYS(pg);
boolean_t rv;
- PDEBUG(0, printf("pmap_clear_reference pa=%08lx\n", pa));
- rv = pmap_testbit(pa, PT_H);
- pmap_clearbit(pa, PT_H);
+ PDEBUG(0, printf("pmap_clear_reference pa=%08lx\n",
+ VM_PAGE_TO_PHYS(pg)));
+ rv = pmap_testbit(pg, PT_H);
+ pmap_clearbit(pg, PT_H);
return rv;
}
void
-pmap_copy_on_write(pa)
- paddr_t pa;
+pmap_copy_on_write(pg)
+ struct vm_page *pg;
{
- PDEBUG(0, printf("pmap_copy_on_write pa=%08lx\n", pa));
- pmap_clearbit(pa, PT_Wr);
+ PDEBUG(0, printf("pmap_copy_on_write pa=%08lx\n",
+ VM_PAGE_TO_PHYS(pg)));
+ pmap_clearbit(pg, PT_Wr);
}
@@ -3450,11 +3442,11 @@ boolean_t
pmap_is_modified(pg)
struct vm_page *pg;
{
- paddr_t pa = VM_PAGE_TO_PHYS(pg);
boolean_t result;
- result = pmap_testbit(pa, PT_M);
- PDEBUG(1, printf("pmap_is_modified pa=%08lx %x\n", pa, result));
+ result = pmap_testbit(pg, PT_M);
+ PDEBUG(1, printf("pmap_is_modified pa=%08lx %x\n",
+ VM_PAGE_TO_PHYS(pg), result));
return (result);
}
@@ -3463,11 +3455,11 @@ boolean_t
pmap_is_referenced(pg)
struct vm_page *pg;
{
- paddr_t pa = VM_PAGE_TO_PHYS(pg);
boolean_t result;
- result = pmap_testbit(pa, PT_H);
- PDEBUG(0, printf("pmap_is_referenced pa=%08lx %x\n", pa, result));
+ result = pmap_testbit(pg, PT_H);
+ PDEBUG(0, printf("pmap_is_referenced pa=%08lx %x\n",
+ VM_PAGE_TO_PHYS(pg), result));
return (result);
}
@@ -3479,8 +3471,7 @@ pmap_modified_emulation(pmap, va)
{
pt_entry_t *pte;
paddr_t pa;
- int bank, off;
- struct pv_head *pvh;
+ struct vm_page *pg;
u_int flags;
PDEBUG(2, printf("pmap_modified_emulation\n"));
@@ -3499,21 +3490,19 @@ pmap_modified_emulation(pmap, va)
return(0);
/* This can happen if user code tries to access kernel memory. */
+ /* XXXJRT Use address-based check. C.f. Alpha pmap. */
if ((*pte & PT_AP(AP_W)) != 0)
return (0);
/* Extract the physical address of the page */
pa = pmap_pte_pa(pte);
- if ((bank = vm_physseg_find(atop(pa), &off)) == -1)
+ if ((pg = PHYS_TO_VM_PAGE(pa)) == NULL)
return(0);
PMAP_HEAD_TO_MAP_LOCK();
- /* Get the current flags for this page. */
- pvh = &vm_physmem[bank].pmseg.pvhead[off];
- /* XXX: needed if we hold head->map lock? */
- simple_lock(&pvh->pvh_lock);
+ simple_lock(&pg->mdpage.pvh_slock);
- flags = pmap_modify_pv(pmap, va, pvh, 0, 0);
+ flags = pmap_modify_pv(pmap, va, pg, 0, 0);
PDEBUG(2, printf("pmap_modified_emulation: flags = %08x\n", flags));
/*
@@ -3524,14 +3513,14 @@ pmap_modified_emulation(pmap, va)
* modified bit
*/
if (~flags & PT_Wr) {
- simple_unlock(&pvh->pvh_lock);
+ simple_unlock(&pg->mdpage.pvh_slock);
PMAP_HEAD_TO_MAP_UNLOCK();
return(0);
}
PDEBUG(0, printf("pmap_modified_emulation: Got a hit va=%08lx, pte = %p (%08x)\n",
va, pte, *pte));
- vm_physmem[bank].pmseg.attrs[off] |= PT_H | PT_M;
+ pg->mdpage.pvh_attrs |= PT_H | PT_M;
/*
* Re-enable write permissions for the page. No need to call
@@ -3540,14 +3529,18 @@ pmap_modified_emulation(pmap, va)
* already set the cacheable bits based on the assumption that we
* can write to this page.
*/
- *pte = (*pte & ~L2_MASK) | L2_SPAGE | PT_AP(AP_W);
+ *pte = (*pte & PG_FRAME) |
+ pmap_pte_proto(pmap, VM_PROT_READ|VM_PROT_WRITE,
+ (flags & PT_NC) ? PTE_PROTO_NOCACHE
+ : PTE_PROTO_CACHE);
PDEBUG(0, printf("->(%08x)\n", *pte));
- simple_unlock(&pvh->pvh_lock);
+ simple_unlock(&pg->mdpage.pvh_slock);
PMAP_HEAD_TO_MAP_UNLOCK();
- /* Return, indicating the problem has been dealt with */
+
cpu_tlb_flushID_SE(va);
cpu_cpwait();
+
return(1);
}
@@ -3558,8 +3551,9 @@ pmap_handled_emulation(pmap, va)
vaddr_t va;
{
pt_entry_t *pte;
+ struct vm_page *pg;
paddr_t pa;
- int bank, off;
+ int flags;
PDEBUG(2, printf("pmap_handled_emulation\n"));
@@ -3582,27 +3576,43 @@ pmap_handled_emulation(pmap, va)
/* Extract the physical address of the page */
pa = pmap_pte_pa(pte);
- if ((bank = vm_physseg_find(atop(pa), &off)) == -1)
- return(0);
+ if ((pg = PHYS_TO_VM_PAGE(pa)) == NULL)
+ return (0);
+
+ PMAP_HEAD_TO_MAP_LOCK();
+ simple_lock(&pg->mdpage.pvh_slock);
+
/*
- * Ok we just enable the pte and mark the attibs as handled
+ * XXXJRT Get the cacheable/non-cacheable state for this
+ * XXXJRT mapping. This should die, in favor of stuffing
+ * XXXJRT these bits into the vm_page.
*/
+ flags = pmap_modify_pv(pmap, va, pg, 0, 0);
+
+ /*
+ * Ok we just enable the pte and mark the attribs as handled
+ */
PDEBUG(0, printf("pmap_handled_emulation: Got a hit va=%08lx pte = %p (%08x)\n",
va, pte, *pte));
- vm_physmem[bank].pmseg.attrs[off] |= PT_H;
- *pte = (*pte & ~L2_MASK) | L2_SPAGE;
+ pg->mdpage.pvh_attrs |= PT_H;
+ *pte = (*pte & PG_FRAME) | pmap_pte_proto(pmap,
+ VM_PROT_READ,
+ (flags & PT_NC) ?
+ PTE_PROTO_NOCACHE :
+ PTE_PROTO_CACHE);
PDEBUG(0, printf("->(%08x)\n", *pte));
+
+ simple_unlock(&pg->mdpage.pvh_slock);
+ PMAP_HEAD_TO_MAP_UNLOCK();
- /* Return, indicating the problem has been dealt with */
cpu_tlb_flushID_SE(va);
cpu_cpwait();
+
return(1);
}
-
-
/*
* pmap_collect: free resources held by a pmap
*
@@ -3719,5 +3729,411 @@ pmap_alloc_ptp(struct pmap *pmap, vaddr_
// pmap->pm_ptphint = ptp;
return (ptp);
}
+
+/************************ Bootstrapping routines ****************************/
+
+/*
+ * pmap_map_section:
+ *
+ * Create a single section mapping.
+ */
+void
+pmap_map_section(vaddr_t l1pt, vaddr_t va, paddr_t pa, int prot, int cache)
+{
+ pd_entry_t *pde = (pd_entry_t *) l1pt;
+
+ KASSERT(((va | pa) & (L1_SEC_SIZE - 1)) == 0);
+
+ pde[va >> PDSHIFT] = pa | l1sec_proto(prot, cache);
+}
-/* End of pmap.c */
+/*
+ * pmap_map_entry:
+ *
+ * Create a single page mapping.
+ */
+void
+pmap_map_entry(vaddr_t l2pt, vaddr_t va, paddr_t pa, int prot, int cache)
+{
+ pt_entry_t *pte = (pt_entry_t *) l2pt;
+
+#ifndef cats
+ pte[(va >> PGSHIFT) & 0x3ff] =
+ pa | pte_proto(PTE_PROTO_KERNEL, prot, cache);
+#else
+ pte[(va >> PGSHIFT) & 0x7ff] =
+ pa | pte_proto(PTE_PROTO_KERNEL, prot, cache);
+#endif /* cats */
+}
+
+/*
+ * pmap_map_l2pt:
+ *
+ * Map L2 page table at the specified physical address
+ * into the slot for the specified virtual address in
+ * the L1 table.
+ */
+void
+pmap_map_l2pt(vaddr_t l1pt, vaddr_t va, paddr_t pa)
+{
+ pd_entry_t *pde = (pd_entry_t *) l1pt;
+
+ KASSERT((pa & PG_FRAME) == pa);
+
+ pde[(va >> PDSHIFT) + 0] = (pa + 0x000) | pde_proto;
+ pde[(va >> PDSHIFT) + 1] = (pa + 0x400) | pde_proto;
+ pde[(va >> PDSHIFT) + 2] = (pa + 0x800) | pde_proto;
+ pde[(va >> PDSHIFT) + 3] = (pa + 0xc00) | pde_proto;
+}
+
+/*
+ * pmap_map_chunk:
+ *
+ * Map a chunk of memory using the most efficient mappings
+ * possible (section, large page, small page) into the
+ * provided L1 and L2 tables at the specified virtual address.
+ */
+vsize_t
+pmap_map_chunk(vaddr_t l1pt, vaddr_t l2pt, vaddr_t va, paddr_t pa,
+ vsize_t size, int prot, int cache)
+{
+ pd_entry_t *pde = (pd_entry_t *) l1pt;
+ pt_entry_t *pte = (pt_entry_t *) l2pt;
+ vsize_t resid;
+ int i;
+
+ resid = (size + (NBPG - 1)) & ~(NBPG - 1);
+
+#ifdef VERBOSE_INIT_ARM
+ printf("pmap_map_chunk: pa=0x%lx va=0x%lx size=0x%lx resid=0x%lx "
+ "prot=0x%x cache=%d\n", pa, va, size, resid, prot, cache);
+#endif
+
+ size = resid;
+
+ while (resid > 0) {
+ /* See if we can use a section mapping. */
+ if (l1pt &&
+ ((pa | va) & (L1_SEC_SIZE - 1)) == 0 &&
+ resid >= L1_SEC_SIZE) {
+#ifdef VERBOSE_INIT_ARM
+ printf("S");
+#endif
+ pde[va >> PDSHIFT] = pa | l1sec_proto(prot, cache);
+ va += L1_SEC_SIZE;
+ pa += L1_SEC_SIZE;
+ resid -= L1_SEC_SIZE;
+ continue;
+ }
+
+ /* See if we can use a L2 large page mapping. */
+ if (((pa | va) & (L2_LPAGE_SIZE - 1)) == 0 &&
+ resid >= L2_LPAGE_SIZE) {
+#ifdef VERBOSE_INIT_ARM
+ printf("L");
+#endif
+ for (i = 0; i < 16; i++) {
+#ifndef cats /* XXXJRT */
+ pte[((va >> PGSHIFT) & 0x3f0) + i] = pa |
+ lpte_proto(prot, cache);
+#else
+ pte[((va >> PGSHIFT) & 0x7f0) + i] = pa |
+ lpte_proto(prot, cache);
+#endif /* cats */
+ }
+ va += L2_LPAGE_SIZE;
+ pa += L2_LPAGE_SIZE;
+ resid -= L2_LPAGE_SIZE;
+ continue;
+ }
+
+ /* Use a small page mapping. */
+#ifdef VERBOSE_INIT_ARM
+ printf("P");
+#endif
+#ifndef cats /* XXXJRT */
+ pte[(va >> PGSHIFT) & 0x3ff] = pa |
+ pte_proto(PTE_PROTO_KERNEL, prot, cache);
+#else
+ pte[(va >> PGSHIFT) & 0x7ff] = pa |
+ pte_proto(PTE_PROTO_KERNEL, prot, cache);
+#endif /* cats */
+ va += NBPG;
+ pa += NBPG;
+ resid -= NBPG;
+ }
+#ifdef VERBOSE_INIT_ARM
+ printf("\n");
+#endif
+ return (size);
+}
+
+/*
+ * pmap_pte_protos_init:
+ *
+ * Initialize the prototype PTE arrays. This is done very
+ * early, right after the cpufunc vector is selected.
+ */
+#if defined(CPU_ARM6) || defined(CPU_ARM7) || defined(CPU_ARM7TDMI) || \
+ defined(CPU_ARM8) || defined(CPU_SA110)
+void
+pmap_pte_protos_init_arm678(void)
+{
+ int prot;
+
+ /*
+ * NOTE: For all ARM6, ARM7, and ARM8 CPUs, bit 4 (the
+ * implementation defined bit) of L1 descriptors should
+ * be set to 1.
+ */
+
+ pde_proto = L1_PAGE | PT_U;
+
+#define CACHE (PT_B|PT_C)
+
+ for (prot = 0; prot < 8; prot++) {
+ if (prot & VM_PROT_WRITE) {
+ pte_proto(PTE_PROTO_KERNEL, prot,
+ PTE_PROTO_CACHE) =
+ L2_SPAGE | PT_AP(AP_KRW) | CACHE;
+
+ pte_proto(PTE_PROTO_KERNEL, prot,
+ PTE_PROTO_NOCACHE) =
+ L2_SPAGE | PT_AP(AP_KRW);
+
+ pte_proto(PTE_PROTO_USER, prot,
+ PTE_PROTO_CACHE) =
+ L2_SPAGE | PT_AP(AP_KRWURW) | CACHE;
+
+ pte_proto(PTE_PROTO_USER, prot,
+ PTE_PROTO_NOCACHE) =
+ L2_SPAGE | PT_AP(AP_KRWURW);
+
+ l1sec_proto(prot, PTE_PROTO_CACHE) =
+ (AP_KRW << AP_SECTION_SHIFT) |
+ L1_SECTION | PT_U | CACHE;
+
+ l1sec_proto(prot, PTE_PROTO_NOCACHE) =
+ (AP_KRW << AP_SECTION_SHIFT) |
+ L1_SECTION | PT_U;
+
+ lpte_proto(prot, PTE_PROTO_CACHE) =
+ L2_LPAGE | PT_AP(AP_KRW) | CACHE;
+
+ lpte_proto(prot, PTE_PROTO_NOCACHE) =
+ L2_LPAGE | PT_AP(AP_KRW);
+ } else if (prot & VM_PROT_ALL) {
+ pte_proto(PTE_PROTO_KERNEL, prot,
+ PTE_PROTO_CACHE) =
+ L2_SPAGE | PT_AP(AP_KR) | CACHE;
+
+ pte_proto(PTE_PROTO_KERNEL, prot,
+ PTE_PROTO_NOCACHE) =
+ L2_SPAGE | PT_AP(AP_KR);
+
+ pte_proto(PTE_PROTO_USER, prot,
+ PTE_PROTO_CACHE) =
+ L2_SPAGE | PT_AP(AP_KRWUR) | CACHE;
+
+ pte_proto(PTE_PROTO_USER, prot,
+ PTE_PROTO_NOCACHE) =
+ L2_SPAGE | PT_AP(AP_KRWUR);
+
+ l1sec_proto(prot, PTE_PROTO_CACHE) =
+ (AP_KR << AP_SECTION_SHIFT) |
+ L1_SECTION | PT_U | CACHE;
+
+ l1sec_proto(prot, PTE_PROTO_NOCACHE) =
+ (AP_KR << AP_SECTION_SHIFT) |
+ L1_SECTION | PT_U;
+
+ lpte_proto(prot, PTE_PROTO_CACHE) =
+ L2_LPAGE | PT_AP(AP_KR) | CACHE;
+
+ lpte_proto(prot, PTE_PROTO_NOCACHE) =
+ L2_LPAGE | PT_AP(AP_KR);
+ }
+ }
+#undef CACHE
+}
+#endif /* CPU_ARM6 || CPU_ARM7 || CPU_ARM7TDMI || CPU_ARM8 || CPU_SA110 */
+
+#if defined(CPU_ARM9)
+void
+pmap_pte_protos_init_arm9(void)
+{
+ int prot;
+
+ /*
+ * NOTE: For all ARM9 CPUs, bit 4 (the implementation defined
+ * bit) of L1 descriptors should be set to 1.
+ */
+
+ pde_proto = L1_PAGE | PT_U;
+
+/* Use the cache in write-through mode for now. */
+#define CACHE (PT_C)
+
+ for (prot = 0; prot < 8; prot++) {
+ if (prot & VM_PROT_WRITE) {
+ pte_proto(PTE_PROTO_KERNEL, prot,
+ PTE_PROTO_CACHE) =
+ L2_SPAGE | PT_AP(AP_KRW) | CACHE;
+
+ pte_proto(PTE_PROTO_KERNEL, prot,
+ PTE_PROTO_NOCACHE) =
+ L2_SPAGE | PT_AP(AP_KRW);
+
+ pte_proto(PTE_PROTO_USER, prot,
+ PTE_PROTO_CACHE) =
+ L2_SPAGE | PT_AP(AP_KRWURW) | CACHE;
+
+ pte_proto(PTE_PROTO_USER, prot,
+ PTE_PROTO_NOCACHE) =
+ L2_SPAGE | PT_AP(AP_KRWURW);
+
+ l1sec_proto(prot, PTE_PROTO_CACHE) =
+ (AP_KRW << AP_SECTION_SHIFT) |
+ L1_SECTION | PT_U | CACHE;
+
+ l1sec_proto(prot, PTE_PROTO_NOCACHE) =
+ (AP_KRW << AP_SECTION_SHIFT) |
+ L1_SECTION | PT_U;
+
+ lpte_proto(prot, PTE_PROTO_CACHE) =
+ L2_LPAGE | PT_AP(AP_KRW) | CACHE;
+
+ lpte_proto(prot, PTE_PROTO_NOCACHE) =
+ L2_LPAGE | PT_AP(AP_KRW);
+ } else if (prot & VM_PROT_ALL) {
+ pte_proto(PTE_PROTO_KERNEL, prot,
+ PTE_PROTO_CACHE) =
+ L2_SPAGE | PT_AP(AP_KR) | CACHE;
+
+ pte_proto(PTE_PROTO_KERNEL, prot,
+ PTE_PROTO_NOCACHE) =
+ L2_SPAGE | PT_AP(AP_KR);
+
+ pte_proto(PTE_PROTO_USER, prot,
+ PTE_PROTO_CACHE) =
+ L2_SPAGE | PT_AP(AP_KRWUR) | CACHE;
+
+ pte_proto(PTE_PROTO_USER, prot,
+ PTE_PROTO_NOCACHE) =
+ L2_SPAGE | PT_AP(AP_KRWUR);
+
+ l1sec_proto(prot, PTE_PROTO_CACHE) =
+ (AP_KR << AP_SECTION_SHIFT) |
+ L1_SECTION | PT_U | CACHE;
+
+ l1sec_proto(prot, PTE_PROTO_NOCACHE) =
+ (AP_KR << AP_SECTION_SHIFT) |
+ L1_SECTION | PT_U;
+
+ lpte_proto(prot, PTE_PROTO_CACHE) =
+ L2_LPAGE | PT_AP(AP_KR) | CACHE;
+
+ lpte_proto(prot, PTE_PROTO_NOCACHE) =
+ L2_LPAGE | PT_AP(AP_KR);
+ }
+ }
+#undef CACHE
+}
+#endif /* CPU_ARM9 */
+
+#if defined(CPU_XSCALE)
+void
+pmap_pte_protos_init_xscale(void)
+{
+ int prot;
+
+/*
+ * i80200 errata item #40: Store to cacheable memory,
+ * interrupted by an exception, may inadvertently
+ * write to memory.
+ *
+ * This can have an adverse affect on copy-on-write
+ * operation.
+ *
+ * Work-around: Non-writable mappings should have
+ * a cache mode of write-through (this avoids the
+ * problem). This has no adverse performance affect,
+ * since the mappings are read-only.
+ */
+#define CACHE_WT (PT_C)
+#define CACHE_WB (PT_C) /* XXX for now */
+
+ /*
+ * NOTE: For all XScale CPUs, bit 4 (the implementation defined
+ * bit) of L1 descriptors should be set to 0.
+ */
+
+ pde_proto = L1_PAGE;
+
+ for (prot = 0; prot < 8; prot++) {
+ if (prot & VM_PROT_WRITE) {
+ pte_proto(PTE_PROTO_KERNEL, prot,
+ PTE_PROTO_CACHE) =
+ L2_SPAGE | PT_AP(AP_KRW) | CACHE_WB;
+
+ pte_proto(PTE_PROTO_KERNEL, prot,
+ PTE_PROTO_NOCACHE) =
+ L2_SPAGE | PT_AP(AP_KRW);
+
+ pte_proto(PTE_PROTO_USER, prot,
+ PTE_PROTO_CACHE) =
+ L2_SPAGE | PT_AP(AP_KRWURW) | CACHE_WB;
+
+ pte_proto(PTE_PROTO_USER, prot,
+ PTE_PROTO_NOCACHE) =
+ L2_SPAGE | PT_AP(AP_KRWURW);
+
+ l1sec_proto(prot, PTE_PROTO_CACHE) =
+ (AP_KRW << AP_SECTION_SHIFT) |
+ L1_SECTION | CACHE_WB;
+
+ l1sec_proto(prot, PTE_PROTO_NOCACHE) =
+ (AP_KRW << AP_SECTION_SHIFT) |
+ L1_SECTION;
+
+ lpte_proto(prot, PTE_PROTO_CACHE) =
+ L2_LPAGE | PT_AP(AP_KRW) | CACHE_WB;
+
+ lpte_proto(prot, PTE_PROTO_NOCACHE) =
+ L2_LPAGE | PT_AP(AP_KRW);
+ } else if (prot & VM_PROT_ALL) {
+ pte_proto(PTE_PROTO_KERNEL, prot,
+ PTE_PROTO_CACHE) =
+ L2_SPAGE | PT_AP(AP_KR) | CACHE_WT;
+
+ pte_proto(PTE_PROTO_KERNEL, prot,
+ PTE_PROTO_NOCACHE) =
+ L2_SPAGE | PT_AP(AP_KR);
+
+ pte_proto(PTE_PROTO_USER, prot,
+ PTE_PROTO_CACHE) =
+ L2_SPAGE | PT_AP(AP_KRWUR) | CACHE_WT;
+
+ pte_proto(PTE_PROTO_USER, prot,
+ PTE_PROTO_NOCACHE) =
+ L2_SPAGE | PT_AP(AP_KRWUR);
+
+ l1sec_proto(prot, PTE_PROTO_CACHE) =
+ (AP_KRW << AP_SECTION_SHIFT) |
+ L1_SECTION | CACHE_WT;
+
+ l1sec_proto(prot, PTE_PROTO_NOCACHE) =
+ (AP_KRW << AP_SECTION_SHIFT) |
+ L1_SECTION;
+
+ lpte_proto(prot, PTE_PROTO_CACHE) =
+ L2_LPAGE | PT_AP(AP_KR) | CACHE_WT;
+
+ lpte_proto(prot, PTE_PROTO_NOCACHE) =
+ L2_LPAGE | PT_AP(AP_KR);
+ }
+ }
+#undef CACHE_WT
+#undef CACHE_WB
+}
+#endif /* CPU_XSCALE */
Index: arm/include/arm32/pmap.h
===================================================================
RCS file: /cvsroot/syssrc/sys/arch/arm/include/arm32/pmap.h,v
retrieving revision 1.20
diff -u -p -r1.20 pmap.h
--- arm/include/arm32/pmap.h 2002/01/19 16:55:22 1.20
+++ arm/include/arm32/pmap.h 2002/02/01 17:31:02
@@ -99,24 +99,6 @@ struct pmap {
typedef struct pmap *pmap_t;
/*
- * for each managed physical page we maintain a list of <PMAP,VA>'s
- * which it is mapped at. the list is headed by a pv_head structure.
- * there is one pv_head per managed phys page (allocated at boot time).
- * the pv_head structure points to a list of pv_entry structures (each
- * describes one mapping).
- *
- * pv_entry's are only visible within pmap.c, so only provide a placeholder
- * here
- */
-
-struct pv_entry;
-
-struct pv_head {
- struct simplelock pvh_lock; /* locks every pv on this list */
- struct pv_entry *pvh_list; /* head of list (locked by pvh_lock) */
-};
-
-/*
* Page hooks. I'll eliminate these sometime soon :-)
*
* For speed we store the both the virtual address and the page table
@@ -138,10 +120,35 @@ typedef struct {
} pv_addr_t;
/*
- * _KERNEL specific macros, functions and prototypes
+ * Prototype PTE bits for each VM protection code, both cached
+ * and un-cached, kernel and userland.
*/
-
-#ifdef _KERNEL
+extern pt_entry_t pte_protos[4][8];
+extern pd_entry_t l1sec_protos[2][8];
+extern pt_entry_t lpte_protos[2][8];
+extern pd_entry_t pde_proto;
+
+#define PTE_PROTO_KERNEL 0
+#define PTE_PROTO_USER 1
+#define PTE_PROTO_NOCACHE 0
+#define PTE_PROTO_CACHE 1
+
+#define pte_proto(ku, prot, cache) \
+ pte_protos[(ku) + ((cache) << 1)][(prot)]
+
+#define l1sec_proto(prot, cache) \
+ l1sec_protos[(cache)][(prot)]
+
+#define lpte_proto(prot, cache) \
+ lpte_protos[(cache)][(prot)]
+
+#define pmap_pte_proto(pm, prot, cache) \
+ pte_proto((pm == pmap_kernel()) ? PTE_PROTO_KERNEL \
+ : PTE_PROTO_USER, (prot), (cache))
+
+void pmap_pte_protos_init_arm678(void);
+void pmap_pte_protos_init_arm9(void);
+void pmap_pte_protos_init_xscale(void);
/*
* Commonly referenced structures
@@ -176,13 +183,17 @@ int pmap_modified_emulation __P((struct
void pmap_postinit __P((void));
pt_entry_t *pmap_pte __P((struct pmap *, vaddr_t));
+/* Bootstrapping routines. */
+void pmap_map_section(vaddr_t, vaddr_t, paddr_t, int, int);
+void pmap_map_entry(vaddr_t, vaddr_t, paddr_t, int, int);
+void pmap_map_l2pt(vaddr_t, vaddr_t, paddr_t);
+vsize_t pmap_map_chunk(vaddr_t, vaddr_t, vaddr_t, paddr_t, vsize_t, int, int);
+
/*
* Special page zero routine for use by the idle loop (no cache cleans).
*/
boolean_t pmap_pageidlezero __P((paddr_t));
#define PMAP_PAGEIDLEZERO(pa) pmap_pageidlezero((pa))
-
-#endif /* _KERNEL */
/*
* Useful macros and constants
Index: arm/include/arm32/pte.h
===================================================================
RCS file: /cvsroot/syssrc/sys/arch/arm/include/arm32/pte.h,v
retrieving revision 1.1
diff -u -p -r1.1 pte.h
--- arm/include/arm32/pte.h 2001/11/23 17:39:04 1.1
+++ arm/include/arm32/pte.h 2002/02/01 17:31:04
@@ -74,12 +74,6 @@ typedef int pt_entry_t; /* page table e
#define PT_C 0x08 /* Phys - Cacheable */
#define PT_U 0x10 /* Phys - Updateable */
-#ifndef _LOCORE
-extern pt_entry_t pte_cache_mode;
-
-#define PT_CACHEABLE (pte_cache_mode)
-#endif
-
/* Page R/M attributes (in pmseg.attrs). */
#define PT_M 0x01 /* Virt - Modified */
#define PT_H 0x02 /* Virt - Handled (Used) */
@@ -103,18 +97,6 @@ extern pt_entry_t pte_cache_mode;
#define L2_SPAGE 0x02 /* L2 small page (4KB) */
#define L2_MASK 0x03 /* Mask for L2 entry type */
#define L2_INVAL 0x00 /* L2 invalid type */
-
-/* PTE construction macros */
-#define L2_LPTE(p, a, f) ((p) | PT_AP(a) | L2_LPAGE | (f))
-#define L2_SPTE(p, a, f) ((p) | PT_AP(a) | L2_SPAGE | (f))
-#define L2_PTE(p, a) L2_SPTE((p), (a), PT_CACHEABLE)
-#define L2_PTE_NC(p, a) L2_SPTE((p), (a), PT_B)
-#define L2_PTE_NC_NB(p, a) L2_SPTE((p), (a), 0)
-#define L1_SECPTE(p, a, f) ((p) | ((a) << AP_SECTION_SHIFT) | (f) \
- | L1_SECTION | PT_U)
-
-#define L1_PTE(p) ((p) | 0x00 | L1_PAGE | PT_U)
-#define L1_SEC(p, c) L1_SECPTE((p), AP_KRW, (c))
#define L1_SEC_SIZE (1 << PDSHIFT)
#define L2_LPAGE_SIZE (NBPG * 16)
Index: arm/include/arm32/vmparam.h
===================================================================
RCS file: /cvsroot/syssrc/sys/arch/arm/include/arm32/vmparam.h,v
retrieving revision 1.3
diff -u -p -r1.3 vmparam.h
--- arm/include/arm32/vmparam.h 2001/11/23 18:16:10 1.3
+++ arm/include/arm32/vmparam.h 2002/02/01 17:31:07
@@ -1,7 +1,7 @@
/* $NetBSD: vmparam.h,v 1.3 2001/11/23 18:16:10 thorpej Exp $ */
/*
- * Copyright (c) 2001 Wasabi Systems, Inc.
+ * Copyright (c) 2001, 2002 Wasabi Systems, Inc.
* All rights reserved.
*
* Written by Jason R. Thorpe for Wasabi Systems, Inc.
@@ -44,8 +44,8 @@
* Virtual Memory parameters common to all arm32 platforms.
*/
-/* for pt_entry_t definition */
-#include <arm/arm32/pte.h>
+#include <sys/lock.h> /* struct simplelock */
+#include <arm/arm32/pte.h> /* pt_entry_t */
#define USRTEXT VM_MIN_ADDRESS
#define USRSTACK VM_MAXUSER_ADDRESS
@@ -106,16 +106,21 @@
#define VM_MAX_KERNEL_ADDRESS ((vaddr_t) 0xffffffff)
/*
- * define structure pmap_physseg: there is one of these structures
- * for each chunk of noncontig RAM you have.
+ * pmap-specific data store in the vm_page structure.
*/
-
-#define __HAVE_PMAP_PHYSSEG
-
-struct pmap_physseg {
- struct pv_head *pvhead; /* pv_entry array */
- char *attrs; /* attrs array */
+#define __HAVE_VM_PAGE_MD
+struct vm_page_md {
+ struct pv_entry *pvh_list; /* pv_entry list */
+ struct simplelock pvh_slock; /* lock on this head */
+ int pvh_attrs; /* page attributes */
};
+
+#define VM_MDPAGE_INIT(pg) \
+do { \
+ (pg)->mdpage.pvh_list = NULL; \
+ simple_lock_init(&(pg)->mdpage.pvh_slock); \
+ (pg)->mdpage.pvh_attrs = 0; \
+} while (/*CONSTCOND*/0)
#endif /* _KERNEL */
--WYTEVAkct0FjGQmd--