PERFORCE change 32741 for review
Juli Mallett
jmallett at FreeBSD.org
Sat Jun 7 04:35:09 PDT 2003
http://perforce.freebsd.org/chv.cgi?CH=32741
Change 32741 by jmallett at jmallett_dalek on 2003/06/07 04:34:36
Move out a fair bit of code to tlb.c, and cripple a few things
along the way. Easier this way for now...
Affected files ...
.. //depot/projects/mips/sys/mips/mips/pmap.c#16 edit
Differences ...
==== //depot/projects/mips/sys/mips/mips/pmap.c#16 (text+ko) ====
@@ -113,15 +113,8 @@
#include <machine/locore.h>
#include <machine/md_var.h>
+#include <machine/tlb.h>
-/*
- * The joy of indexing.
- *
- * User addresses don't have the bits set that XKSEG has, best way to
- * index the page table is to remove those bits, and get a page number.
- */
-#define pmap_index(va) (((va) & ~VM_MIN_KERNEL_ADDRESS) >> PAGE_SHIFT)
-
#ifndef PMAP_SHPGPERPROC
#define PMAP_SHPGPERPROC 200
#endif
@@ -153,7 +146,6 @@
#define pmap_pte_pa(pte) MIPS_PTE_TO_PA(*(pte))
#define pmap_pte_prot(pte) (*(pte) & PG_PROT)
-#define pmap_pte_set_w(pte, v) ((v)?(*pte |= PG_W):(*pte &= ~PG_W))
#define pmap_pte_set_prot(pte, v) ((*pte &= ~PG_PROT), (*pte |= (v)))
/*
@@ -189,9 +181,6 @@
*/
#define pmap_k0seg_to_pte(va) MIPS_PA_TO_PFN(pmap_k0seg_to_pfn(va))
-pt_entry_t *kptmap;
-vm_size_t kptsize;
-
/*
* Statically allocated kernel pmap
*/
@@ -228,7 +217,6 @@
static pv_entry_t get_pv_entry(void);
static int pmap_remove_pte(pmap_t pmap, pt_entry_t* ptq, vm_offset_t sva);
-static void pmap_remove_page(struct pmap *pmap, vm_offset_t va);
static int pmap_remove_entry(struct pmap *pmap, vm_page_t m, vm_offset_t va);
static void pmap_insert_entry(pmap_t pmap, vm_offset_t va,
vm_page_t mpte, vm_page_t m);
@@ -245,7 +233,7 @@
{
if (pmap == NULL || pmap->pm_lev1 == NULL)
return NULL;
- return &pmap->pm_lev1[pmap_index(va)];
+ return tlb_pte_find(pmap->pm_lev1, va);
}
@@ -292,36 +280,23 @@
* Bootstrap the system enough to run with virtual memory.
*
* This sets up the ASID generator, message buffer, and page
- * table. XXX Probably want to move page table and related to
- * a TLB-specific file. It also sets up some very important
- * values for MI VM code to run.
+ * table.
*/
void
pmap_bootstrap(void)
{
- pt_entry_t *pte;
int i;
/*
- * Setup ASIDs. PCPU_GET(next_asid) and PCPU_GET(current_asidgen) are set
- * up already.
- */
- pmap_maxasid = MIPS3_TLB_NUM_ASIDS;
-
- /*
* Steal the message buffer from the beginning of memory.
*/
msgbufp = (struct msgbuf *) pmap_steal_memory(MSGBUF_SIZE);
msgbufinit(msgbufp, MSGBUF_SIZE);
/*
- * Set up kernel page table.
+ * Initialise TLB management, and have it allocate page tables.
*/
- kptsize = physsz >> PAGE_SHIFT;
- printf("Kernel page table indexes %ld %dK pages.\n",
- kptsize, PAGE_SIZE / 1024);
- kptmap = (pt_entry_t *)
- pmap_steal_memory(kptsize * sizeof (pt_entry_t));
+ tlb_bootstrap(physsz >> PAGE_SHIFT, pmap_steal_memory);
avail_start = phys_avail[0];
for (i = 0; phys_avail[i+2]; i+= 2) ;
@@ -345,20 +320,6 @@
*/
LIST_INIT(&allpmaps);
LIST_INSERT_HEAD(&allpmaps, kernel_pmap, pm_list);
-
- /*
- * Lock in the current ASID, and set the global bit on each PTE.
- */
- mips_wr_entryhi(kernel_pmap->pm_asid);
- for (i = 0; i < kptsize; i++) {
- pte = &kptmap[i];
- *pte = PG_G;
- }
-
- /*
- * Clear the TLB.
- */
- MIPS_TBIAP();
}
/*
@@ -616,48 +577,35 @@
***************************************************/
/*
- * Add a list of wired pages to the kva
- * this routine is only used for temporary
- * kernel mappings that do not need to have
- * page modification or references recorded.
- * Note that old mappings are simply written
- * over. The page *must* be wired.
+ * Map a list of wired pages into kernel virtual address space. This is
+ * intended for temporary mappings which do not need page modification or
+ * references recorded. Existing mappings in the region are overwritten.
*/
void
-pmap_qenter(vm_offset_t va, vm_page_t *m, int count)
+pmap_qenter(vm_offset_t sva, vm_page_t *m, int count)
{
- int i;
- pt_entry_t *pte;
+ vm_offset_t va;
- for (i = 0; i < count; i++) {
- vm_offset_t tva = va + i * PAGE_SIZE;
- pt_entry_t npte = pmap_phys_to_pte(VM_PAGE_TO_PHYS(m[i]))
- | PG_V;
- pt_entry_t opte;
- pte = pmap_pte(kernel_pmap, tva);
- opte = *pte;
- *pte = npte;
- if (opte & PG_V)
- pmap_invalidate_page(kernel_pmap, tva);
+ va = sva;
+ while (count-- > 0) {
+ pmap_kenter(va, *m);
+ va += PAGE_SIZE;
+ m++;
}
}
/*
- * this routine jerks page mappings from the
- * kernel -- it is meant only for temporary mappings.
+ * Remove page mappings from kernel virtual address space. Intended for
+ * temporary mappings entered by pmap_qenter.
*/
void
-pmap_qremove(va, count)
+pmap_qremove(vm_offset_t sva, int count)
+{
vm_offset_t va;
- int count;
-{
- int i;
- register pt_entry_t *pte;
- for (i = 0; i < count; i++) {
- pte = pmap_pte(kernel_pmap, va);
- *pte = 0;
- pmap_invalidate_page(kernel_pmap, va);
+ va = sva;
+ while (count-- > 0) {
+ pmap_kremove(va);
va += PAGE_SIZE;
}
}
@@ -670,16 +618,8 @@
PMAP_INLINE void
pmap_kenter(vm_offset_t va, vm_offset_t pa)
{
- pt_entry_t *pte;
- pt_entry_t npte, opte;
- npte = pmap_phys_to_pte(pa) | PG_V;
- pte = pmap_pte(kernel_pmap, va);
- opte = *pte;
- *pte = npte;
- if (opte & PG_V)
- pmap_invalidate_page(kernel_pmap, va);
- MachTLBUpdate(va & ~PAGE_MASK, npte);
+ tlb_enter(kernel_pmap, va, pa, PG_V | PG_W);
}
/*
@@ -688,11 +628,8 @@
PMAP_INLINE void
pmap_kremove(vm_offset_t va)
{
- register pt_entry_t *pte;
- pte = pmap_pte(kernel_pmap, va);
- *pte = 0;
- pmap_invalidate_page(kernel_pmap, va);
+ tlb_remove(kernel_pmap, va);
}
/*
@@ -813,18 +750,16 @@
vm_object_t ksobj;
vm_offset_t ks;
vm_page_t m;
- pt_entry_t *ptek;
pages = td->td_kstack_pages;
ksobj = td->td_kstack_obj;
ks = td->td_kstack;
- ptek = pmap_pte(kernel_pmap, ks);
+
+ tlb_remove_pages(kernel_pmap, ks, pages);
for (i = 0; i < pages; i++) {
m = vm_page_lookup(ksobj, i);
if (m == NULL)
panic("pmap_dispose_thread: kstack already missing?");
- ptek[i] = 0;
- pmap_invalidate_page(kernel_pmap, ks + i * PAGE_SIZE);
vm_page_lock_queues();
vm_page_busy(m);
vm_page_unwire(m, 0);
@@ -1217,31 +1152,6 @@
}
/*
- * Remove a single page from a process address space
- */
-static void
-pmap_remove_page(pmap_t pmap, vm_offset_t va)
-{
- register pt_entry_t *ptq;
-
- ptq = pmap_pte(pmap, va);
-
- /*
- * if there is no pte for this address, just skip it!!!
- */
- if (!ptq || !pmap_pte_v(ptq))
- return;
-
- /*
- * get a local va for mappings for this pmap.
- */
- (void) pmap_remove_pte(pmap, ptq, va);
- pmap_invalidate_page(pmap, va);
-
- return;
-}
-
-/*
* Remove the given range of addresses from the specified map.
*
* It is assumed that the start and end are properly
@@ -1250,7 +1160,6 @@
void
pmap_remove(pmap_t pmap, vm_offset_t sva, vm_offset_t eva)
{
- vm_offset_t va, nva;
if (pmap == NULL)
return;
@@ -1258,20 +1167,7 @@
if (pmap->pm_stats.resident_count == 0)
return;
- /*
- * special handling of removing one page. a very
- * common operation and easy to short circuit some
- * code.
- */
- if (sva + PAGE_SIZE == eva) {
- pmap_remove_page(pmap, sva);
- return;
- }
-
- for (va = sva; va < eva; va = nva) {
- pmap_remove_page(pmap, va);
- nva = va + PAGE_SIZE;
- }
+ tlb_remove_range(pmap, sva, eva);
}
/*
@@ -1371,7 +1267,7 @@
while (sva < eva) {
/*
- * If level pte is invalid, skip this page
+ * If pte is invalid, skip this page
*/
pte = pmap_pte(pmap, sva);
if (!pmap_pte_v(pte)) {
@@ -1421,9 +1317,7 @@
vm_offset_t pa;
pt_entry_t *pte;
vm_offset_t opa;
- pt_entry_t origpte, newpte;
vm_page_t mpte;
- int managed;
if (pmap == NULL)
return;
@@ -1452,59 +1346,38 @@
panic("pmap_enter: invalid kernel page tables pmap=%p, va=0x%lx\n", pmap, va);
}
- origpte = *pte;
pa = VM_PAGE_TO_PHYS(m) & ~PAGE_MASK;
- managed = 0;
- opa = pmap_pte_pa(pte);
- /*
- * Mapping has not changed, must be protection or wiring change.
- */
- if (origpte & PG_V && (opa == pa)) {
+ if (pte_valid(pte) && (opa = MIPS_PTE_TO_PA(*pte)) == pa) {
+ if (pte_wired(pte)) {
+ if (!wired)
+ pmap->pm_stats.wired_count--;
+ } else {
+ if (wired)
+ pmap->pm_stats.wired_count++;
+ }
+ if (pte_dirty(pte)) {
+ /*
+ * If it's not read-only, is managed, and modified, dirty it.
+ */
+ if (pte_managed(pte) && !pte_ro(pte) && pte_dirty(pte)) {
+ KASSERT(pmap_track_modified(va), ("pmap modified"));
+ vm_page_dirty(PHYS_TO_VM_PAGE(opa));
+ }
+ }
+ } else {
/*
- * Wiring change, just update stats. We don't worry about
- * wiring PT pages as they remain resident as long as there
- * are valid mappings in them. Hence, if a user page is wired,
- * the PT page will be also.
+ * Valid but not the same page, we need to change the mapping.
*/
- if (wired && ((origpte & PG_W) == 0))
- pmap->pm_stats.wired_count++;
- else if (!wired && (origpte & PG_W))
- pmap->pm_stats.wired_count--;
+ if (pte_valid(pte)) {
+ int err;
- /*
- * Remove extra pte reference
- */
- if (mpte)
- mpte->hold_count--;
-
- /*
- * We might be turning off write access to the page,
- * so we go ahead and sense modify status.
- */
- if (pmap_pte_managed(&origpte)) {
- if ((origpte & PG_RO) != PG_RO
- && pmap_track_modified(va)) {
- vm_page_t om;
- om = PHYS_TO_VM_PAGE(opa);
- vm_page_dirty(om);
- }
- managed = 1;
+ vm_page_lock_queues();
+ err = pmap_remove_pte(pmap, pte, va);
+ vm_page_unlock_queues();
+ if (err)
+ panic("pmap_enter: pte vanished, va: 0x%lx", va);
}
-
- goto validate;
- }
- /*
- * Mapping has changed, invalidate old range and fall through to
- * handle validating new mapping.
- */
- if (opa) {
- int err;
- vm_page_lock_queues();
- err = pmap_remove_pte(pmap, pte, va);
- vm_page_unlock_queues();
- if (err)
- panic("pmap_enter: pte vanished, va: 0x%lx", va);
}
/*
@@ -1514,7 +1387,6 @@
*/
if (pmap_initialized && (m->flags & PG_FICTITIOUS) == 0) {
pmap_insert_entry(pmap, va, mpte, m);
- managed |= PG_M;
}
/*
@@ -1524,39 +1396,7 @@
if (wired)
pmap->pm_stats.wired_count++;
-validate:
- /*
- * Now validate mapping with desired protection/wiring.
- */
- newpte = pmap_phys_to_pte(pa) | pte_prot(pmap, prot) | PG_V | managed;
-
- if (managed) {
- /*
- * Set up referenced/modified emulation for the new
- * mapping. Any old referenced/modified emulation
- * results for the old mapping will have been recorded
- * either in pmap_remove_pte() or above in the code
- * which handles protection and/or wiring changes.
- */
- newpte |= (PG_RO | PG_D);
- }
-
- if (wired)
- newpte |= PG_W;
-
- /*
- * if the mapping or permission bits are different, we need
- * to update the pte.
- */
- if (origpte != newpte) {
- if ((newpte & PG_V) == 0)
- panic("pmap_enter invalid mapping?\n");
- *pte = newpte;
- if (origpte & PG_V)
- pmap_invalidate_page(pmap, va);
- if (prot & VM_PROT_EXECUTE)
- /* XXX invalidate Icache */;
- }
+ tlb_enter(pmap, va, pa, PG_V | (wired ? PG_W : 0));
}
/*
@@ -1617,16 +1457,17 @@
pte = pmap_pte(pmap, va);
- if (wired && !pmap_pte_w(pte))
- pmap->pm_stats.wired_count++;
- else if (!wired && pmap_pte_w(pte))
- pmap->pm_stats.wired_count--;
-
- /*
- * Wiring is not a hardware characteristic so there is no need to
- * invalidate TLB.
- */
- pmap_pte_set_w(pte, wired);
+ if (pte_wired(pte)) {
+ if (!wired)
+ pmap->pm_stats.wired_count--;
+ } else {
+ if (wired)
+ pmap->pm_stats.wired_count++;
+ }
+ if (wired)
+ pte_wire(pte);
+ else
+ pte_unwire(pte);
}
@@ -2146,43 +1987,4 @@
return addr;
}
-/*
- * PTE was not dirty and is being written to. XXX kernel only for now.
- */
-void
-pmap_tlb_modified(void *badvaddr)
-{
- pt_entry_t *pte, entry;
- vm_offset_t va;
- va = (vm_offset_t) badvaddr;
- pte = pmap_pte(kernel_pmap, va);
- /*
- * Do we really want to dirty this page?
- */
-#if 0 /* XXX ? */
- if (!pmap_pte_managed(pte))
- panic("tlb modified unmanaged page");
-#endif
- if (!pmap_pte_v(pte))
- panic("tlb modified invalid page");
- if (pmap_pte_ro(pte))
- panic("write to ro page");
- if (*pte & PG_D)
- panic("dirty page caused a TLBMod");
- /*
- * Mark the page dirty.
- */
- *pte |= PG_D;
-
- /*
- * Make a PTE purely to insert into the TLB.
- */
- entry = *pte & MIPS_PFN_MASK;
- entry |= *pte & 0x07; /* XXX PG_??? */
-
- /*
- * Lock in the TLB entry for this page.
- */
- MachTLBUpdate(va & ~PAGE_MASK, *pte);
-}
More information about the p4-projects
mailing list