Subject: 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: 01/29/2002 20:53:08
--+Yg8W10oK6rlW0RR
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

Hi folks...

To work around some errata in current XScale CPUs, I need to use
different cache modes for r/o vs r/w pages.  In particular, I need
to use write-back for r/w pages and write-though for r/o pages (if
r/o pages have a write-back cache mode in the PTE, a write-fault
to the page doesn't always cancel the store to memory, causing
obvious problems).

I've more-or-less implemented this, but there are some problems.  I
seem to have memory corruption when e.g. forks occur (i.e. transitioning
pages from write-back to write-though when they are made r/o for COW).
All works "fine" with I use write-through for both r/o and r/w pages.

Diff of arch/arm and arch/evbarm is attached (I've actually modified all
of the relevant code in all the ports, but I have ommitted them for the
sake of brevity).

The patch essentially does:

	* Replace PT_CACHEABLE with a pte_cache_mode[] array, indexed
	  by protection code (e.g. VM_PROT_READ, VM_PROT_READ|VM_PROT_WRITE,
	  etc.)  Replace all uses of PT_CACHEABLE with an access of the
	  array.

	* Replace uses of (PT_B | PT_C) when clearing cache bits from a
	  PTE with a new global pte_cache_bits.  This will be more
	  important for a future change, which will make the kernel
	  use the extended cache modes available on the XScale.

	* When changing permission on a page, clear the existing
	  cache bits in the PTE and set new cache bits based on the
	  new page protection.  This requires a Wb cache operation
	  on the page.  (I certainly hope it doesn't require a
	  WbInv.)

I would like someone to review my changes to see if I've missed anything
really obvious.  In particular, someone who's actually hacked on the
cache stuff inside the pmap (Richard?)

Thanks.

-- 
        -- Jason R. Thorpe <thorpej@wasabisystems.com>

--+Yg8W10oK6rlW0RR
Content-Type: text/plain; charset=us-ascii
Content-Description: pmap-cache-diff
Content-Disposition: attachment; filename=foo

Index: arm/arm/cpufunc.c
===================================================================
RCS file: /cvsroot/syssrc/sys/arch/arm/arm/cpufunc.c,v
retrieving revision 1.29
diff -c -r1.29 cpufunc.c
*** arm/arm/cpufunc.c	2002/01/30 00:37:18	1.29
--- arm/arm/cpufunc.c	2002/01/30 04:25:58
***************
*** 53,58 ****
--- 53,61 ----
  #include <sys/types.h>
  #include <sys/param.h>
  #include <sys/systm.h>
+ 
+ #include <uvm/uvm_extern.h>
+ 
  #include <machine/cpu.h>
  #include <machine/bootconfig.h>
  #include <arch/arm/arm/disassem.h>
***************
*** 650,655 ****
--- 653,659 ----
  		cpu_reset_needs_v4_MMU_disable = 0;
  		/* XXX Cache info? */
  		arm_dcache_align_mask = -1;
+ 		pmap_pte_protos_init_arm678();
  		return 0;
  	}
  #endif	/* CPU_ARM6 */
***************
*** 661,666 ****
--- 665,671 ----
  		cpu_reset_needs_v4_MMU_disable = 0;
  		/* XXX Cache info? */
  		arm_dcache_align_mask = -1;
+ 		pmap_pte_protos_init_arm678();
  		return 0;
  	}
  #endif	/* CPU_ARM7 */
***************
*** 671,676 ****
--- 676,682 ----
  		cpufuncs = arm7tdmi_cpufuncs;
  		cpu_reset_needs_v4_MMU_disable = 0;
  		get_cachetype();
+ 		pmap_pte_protos_init_arm678();
  		return 0;
  	}
  #endif	
***************
*** 680,694 ****
  		cpufuncs = arm8_cpufuncs;
  		cpu_reset_needs_v4_MMU_disable = 0;	/* XXX correct? */
  		get_cachetype();
  		return 0;
  	}
  #endif	/* CPU_ARM8 */
  #ifdef CPU_ARM9
  	if (cputype == CPU_ID_ARM920T) {
- 		pte_cache_mode = PT_C;	/* Select write-through cacheing. */
  		cpufuncs = arm9_cpufuncs;
  		cpu_reset_needs_v4_MMU_disable = 1;	/* V4 or higher */
  		get_cachetype();
  		return 0;
  	}
  #endif /* CPU_ARM9 */
--- 686,701 ----
  		cpufuncs = arm8_cpufuncs;
  		cpu_reset_needs_v4_MMU_disable = 0;	/* XXX correct? */
  		get_cachetype();
+ 		pmap_pte_protos_init_arm678();
  		return 0;
  	}
  #endif	/* CPU_ARM8 */
  #ifdef CPU_ARM9
  	if (cputype == CPU_ID_ARM920T) {
  		cpufuncs = arm9_cpufuncs;
  		cpu_reset_needs_v4_MMU_disable = 1;	/* V4 or higher */
  		get_cachetype();
+ 		pmap_pte_protos_init_arm9();
  		return 0;
  	}
  #endif /* CPU_ARM9 */
***************
*** 698,703 ****
--- 705,711 ----
  		cpufuncs = sa110_cpufuncs;
  		cpu_reset_needs_v4_MMU_disable = 1;	/* SA needs it */
  		get_cachetype();
+ 		pmap_pte_protos_init_arm678();		/* XXX */
  		/*
  		 * Enable the right variant of sleeping.
  		 */
***************
*** 743,749 ****
  			:
  			: "r" (BCUCTL_E0|BCUCTL_E1|BCUCTL_EV));
  
- 		pte_cache_mode = PT_C;	/* Select write-through cacheing. */
  		cpufuncs = xscale_cpufuncs;
  
  		/*
--- 751,756 ----
***************
*** 758,763 ****
--- 765,771 ----
  
  		cpu_reset_needs_v4_MMU_disable = 1;	/* XScale needs it */
  		get_cachetype();
+ 		pmap_pte_protos_init_xscale();
  		return 0;
  	}
  #endif /* CPU_XSCALE */
Index: arm/arm32/arm32_machdep.c
===================================================================
RCS file: /cvsroot/syssrc/sys/arch/arm/arm32/arm32_machdep.c,v
retrieving revision 1.11
diff -c -r1.11 arm32_machdep.c
*** arm/arm32/arm32_machdep.c	2002/01/20 03:41:47	1.11
--- arm/arm32/arm32_machdep.c	2002/01/30 04:25:58
***************
*** 168,174 ****
  
  	if (cacheable)
  		((u_int *)pagetable)[(va >> PDSHIFT)] =
! 		    L1_SEC((pa & PD_MASK), pte_cache_mode);
  	else
  		((u_int *)pagetable)[(va >> PDSHIFT)] =
  		    L1_SEC((pa & PD_MASK), 0);
--- 168,175 ----
  
  	if (cacheable)
  		((u_int *)pagetable)[(va >> PDSHIFT)] =
! 		    L1_SEC((pa & PD_MASK),
! 		    pte_cache_mode[VM_PROT_READ|VM_PROT_WRITE]);
  	else
  		((u_int *)pagetable)[(va >> PDSHIFT)] =
  		    L1_SEC((pa & PD_MASK), 0);
***************
*** 280,289 ****
  {
  #ifndef cats
  	((pt_entry_t *)pagetable)[((va >> PGSHIFT) & 0x000003ff)] =
! 	    L2_PTE((pa & PG_FRAME), AP_KRW);
  #else
  	((pt_entry_t *)pagetable)[((va >> PGSHIFT) & 0x000007ff)] =
! 	    L2_PTE((pa & PG_FRAME), AP_KRW);
  #endif	
  }
  
--- 281,292 ----
  {
  #ifndef cats
  	((pt_entry_t *)pagetable)[((va >> PGSHIFT) & 0x000003ff)] =
! 	    L2_SPTE((pa & PG_FRAME), AP_KRW,
! 	    pte_cache_mode[VM_PROT_READ|VM_PROT_WRITE]);
  #else
  	((pt_entry_t *)pagetable)[((va >> PGSHIFT) & 0x000007ff)] =
! 	    L2_SPTE((pa & PG_FRAME), AP_KRW,
! 	    pte_cache_mode[VM_PROT_READ|VM_PROT_WRITE]);
  #endif	
  }
  
***************
*** 296,305 ****
  {
  #ifndef cats
  	((pt_entry_t *)pagetable)[((va >> PGSHIFT) & 0x000003ff)] =
! 	    L2_PTE_NC_NB((pa & PG_FRAME), AP_KRW);
  #else
  	((pt_entry_t *)pagetable)[((va >> PGSHIFT) & 0x000007ff)] =
! 	    L2_PTE_NC_NB((pa & PG_FRAME), AP_KRW);
  #endif
  }
  
--- 299,308 ----
  {
  #ifndef cats
  	((pt_entry_t *)pagetable)[((va >> PGSHIFT) & 0x000003ff)] =
! 	    L2_SPTE((pa & PG_FRAME), AP_KRW, 0);
  #else
  	((pt_entry_t *)pagetable)[((va >> PGSHIFT) & 0x000007ff)] =
! 	    L2_SPTE((pa & PG_FRAME), AP_KRW, 0);
  #endif
  }
  
***************
*** 312,321 ****
  {
  #ifndef cats
  	((pt_entry_t *)pagetable)[((va >> PGSHIFT) & 0x000003ff)] =
! 	    L2_PTE((pa & PG_FRAME), AP_KR);
  #else
  	((pt_entry_t *)pagetable)[((va >> PGSHIFT) & 0x000007ff)] =
! 	    L2_PTE((pa & PG_FRAME), AP_KR);
  #endif
  }
  
--- 315,326 ----
  {
  #ifndef cats
  	((pt_entry_t *)pagetable)[((va >> PGSHIFT) & 0x000003ff)] =
! 	    L2_SPTE((pa & PG_FRAME), AP_KR,
! 	    pte_cache_mode[VM_PROT_READ]);
  #else
  	((pt_entry_t *)pagetable)[((va >> PGSHIFT) & 0x000007ff)] =
! 	    L2_SPTE((pa & PG_FRAME), AP_KR,
! 	    pte_cache_mode[VM_PROT_READ]);
  #endif
  }
  
***************
*** 487,493 ****
  zero_page_readonly()
  {
  	WriteWord(PROCESS_PAGE_TBLS_BASE + 0,
! 	    L2_PTE((systempage.pv_pa & PG_FRAME), AP_KR));
  	cpu_tlb_flushID_SE(0x00000000);
  }
  
--- 492,499 ----
  zero_page_readonly()
  {
  	WriteWord(PROCESS_PAGE_TBLS_BASE + 0,
! 	    L2_SPTE((systempage.pv_pa & PG_FRAME), AP_KR,
! 	    pte_cache_mode[VM_PROT_READ]));
  	cpu_tlb_flushID_SE(0x00000000);
  }
  
***************
*** 503,509 ****
  zero_page_readwrite()
  {
  	WriteWord(PROCESS_PAGE_TBLS_BASE + 0,
! 	    L2_PTE((systempage.pv_pa & PG_FRAME), AP_KRW));
  	cpu_tlb_flushID_SE(0x00000000);
  }
  
--- 509,516 ----
  zero_page_readwrite()
  {
  	WriteWord(PROCESS_PAGE_TBLS_BASE + 0,
! 	    L2_SPTE((systempage.pv_pa & PG_FRAME), AP_KRW,
! 	    pte_cache_mode[VM_PROT_READ|VM_PROT_WRITE]));
  	cpu_tlb_flushID_SE(0x00000000);
  }
  
Index: arm/arm32/bus_dma.c
===================================================================
RCS file: /cvsroot/syssrc/sys/arch/arm/arm32/bus_dma.c,v
retrieving revision 1.8
diff -c -r1.8 bus_dma.c
*** arm/arm32/bus_dma.c	2002/01/25 20:57:41	1.8
--- arm/arm32/bus_dma.c	2002/01/30 04:25:59
***************
*** 547,553 ****
  				cpu_dcache_wbinv_range(va, NBPG);
  				cpu_drain_writebuf();
  				ptep = vtopte(va);
! 				*ptep = ((*ptep) & (~PT_C | PT_B));
  				tlb_flush();
  			}
  #ifdef DEBUG_DMA
--- 547,553 ----
  				cpu_dcache_wbinv_range(va, NBPG);
  				cpu_drain_writebuf();
  				ptep = vtopte(va);
! 				*ptep = *ptep & ~pte_cache_bits;
  				tlb_flush();
  			}
  #ifdef DEBUG_DMA
Index: arm/arm32/pmap.c
===================================================================
RCS file: /cvsroot/syssrc/sys/arch/arm/arm32/pmap.c,v
retrieving revision 1.36
diff -c -r1.36 pmap.c
*** arm/arm32/pmap.c	2002/01/25 19:19:25	1.36
--- arm/arm32/pmap.c	2002/01/30 04:26:03
***************
*** 193,198 ****
--- 193,199 ----
  extern caddr_t msgbufaddr;
  
  boolean_t pmap_initialized = FALSE;	/* Has pmap_init completed? */
+ 
  /*
   * locking data structures
   */
***************
*** 326,336 ****
      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.
   */
! pt_entry_t pte_cache_mode = (PT_C | PT_B);
  
  /*
   * real definition of pv_entry.
--- 327,336 ----
      pt_entry_t *, boolean_t));
  
  /*
!  * PTE cache mode array.
   */
! pt_entry_t pte_cache_mode[8];
! pt_entry_t pte_cache_bits;
  
  /*
   * real definition of pv_entry.
***************
*** 943,954 ****
  	pmap->pm_pdir[ptva + 3] = L1_PTE(l2pa + 0xc00);
  
  	PDEBUG(0, printf("pt self reference %lx in %lx\n",
! 	    L2_PTE_NC_NB(l2pa, AP_KRW), 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);
  	}
  	/* XXX should be a purge */
  /*	cpu_tlb_flushD();*/
--- 943,954 ----
  	pmap->pm_pdir[ptva + 3] = L1_PTE(l2pa + 0xc00);
  
  	PDEBUG(0, printf("pt self reference %lx in %lx\n",
! 	    L2_SPTE(l2pa, AP_KRW, 0), pmap->pm_vptpt));
  
  	/* Map the page table into the page table area. */
  	if (selfref) {
  		*((pt_entry_t *)(pmap->pm_vptpt + ptva)) =
! 			L2_SPTE(l2pa, AP_KRW, 0);
  	}
  	/* XXX should be a purge */
  /*	cpu_tlb_flushD();*/
***************
*** 1392,1398 ****
  
  		/* Revoke cacheability and bufferability */
  		/* XXX should be done better than this */
! 		ptes[arm_byte_to_page(va)] &= ~(PT_C | PT_B);
  
  		va += NBPG;
  		m = m->pageq.tqe_next;
--- 1392,1398 ----
  
  		/* Revoke cacheability and bufferability */
  		/* XXX should be done better than this */
! 		ptes[arm_byte_to_page(va)] &= ~pte_cache_bits;
  
  		va += NBPG;
  		m = m->pageq.tqe_next;
***************
*** 1506,1512 ****
  	/* 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);
  
  	/* Wire in this page table */
  	pmap_map_in_l1(pmap, PROCESS_PAGE_TBLS_BASE, pmap->pm_pptpt, TRUE);
--- 1506,1512 ----
  	/* Revoke cacheability and bufferability */
  	/* XXX should be done better than this */
  	pte = pmap_pte(pmap_kernel(), pmap->pm_vptpt);
! 	*pte = *pte & ~pte_cache_bits;
  
  	/* Wire in this page table */
  	pmap_map_in_l1(pmap, PROCESS_PAGE_TBLS_BASE, pmap->pm_pptpt, TRUE);
***************
*** 1878,1884 ****
  	 * 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);
  	cpu_tlb_flushD_SE(page_hook0.va);
  	cpu_cpwait();
  	bzero_page(page_hook0.va);
--- 1878,1885 ----
  	 * Hook in the page, zero it, and purge the cache for that
  	 * zeroed page. Invalidate the TLB as needed.
  	 */
! 	*page_hook0.pte = L2_SPTE(phys & PG_FRAME, AP_KRW,
! 	    pte_cache_mode[VM_PROT_READ|VM_PROT_WRITE]);
  	cpu_tlb_flushD_SE(page_hook0.va);
  	cpu_cpwait();
  	bzero_page(page_hook0.va);
***************
*** 1910,1916 ****
  	 * 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);
  	cpu_tlb_flushD_SE(page_hook0.va);
  	cpu_cpwait();
  
--- 1911,1918 ----
  	 * Hook in the page, zero it, and purge the cache for that
  	 * zeroed page. Invalidate the TLB as needed.
  	 */
! 	*page_hook0.pte = L2_SPTE(phys & PG_FRAME, AP_KRW,
! 	    pte_cache_mode[VM_PROT_READ|VM_PROT_WRITE]);
  	cpu_tlb_flushD_SE(page_hook0.va);
  	cpu_cpwait();
  
***************
*** 1971,1978 ****
  	 * 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);
  	cpu_tlb_flushD_SE(page_hook0.va);
  	cpu_tlb_flushD_SE(page_hook1.va);
  	cpu_cpwait();
--- 1973,1982 ----
  	 * the cache for the appropriate page. Invalidate the TLB
  	 * as required.
  	 */
! 	*page_hook0.pte = L2_SPTE(src & PG_FRAME, AP_KRW,
! 	    pte_cache_mode[VM_PROT_READ|VM_PROT_WRITE]);
! 	*page_hook1.pte = L2_SPTE(dest & PG_FRAME, AP_KRW,
! 	    pte_cache_mode[VM_PROT_READ|VM_PROT_WRITE]);
  	cpu_tlb_flushD_SE(page_hook0.va);
  	cpu_tlb_flushD_SE(page_hook1.va);
  	cpu_cpwait();
***************
*** 2194,2199 ****
--- 2198,2204 ----
  	int cacheable_entries = 0;
  	int kern_cacheable = 0;
  	int other_writable = 0;
+ 	int prot;
  
  	pv = pvh->pvh_list;
  	KASSERT(ptes != NULL);
***************
*** 2237,2247 ****
  		if (cacheable_entries == 0)
  		    return;
  		for (npv = pv; npv; npv = npv->pv_next) {
! 			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;
  				/*
  				 * If this page needs flushing from the
--- 2242,2252 ----
  		if (cacheable_entries == 0)
  		    return;
  		for (npv = pv; npv; npv = npv->pv_next) {
! 			if ((pmap == npv->pv_pmap ||
! 			     kpmap == npv->pv_pmap) && 
  			    (npv->pv_flags & PT_NC) == 0) {
  				ptes[arm_byte_to_page(npv->pv_va)] &= 
! 				    ~pte_cache_bits;
   				npv->pv_flags |= PT_NC;
  				/*
  				 * If this page needs flushing from the
***************
*** 2273,2280 ****
  			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;
  				npv->pv_flags &= ~PT_NC;
  			}
  		}
--- 2278,2288 ----
  			if ((pmap == npv->pv_pmap ||
  			    (kpmap == npv->pv_pmap && other_writable == 0)) && 
  			    (npv->pv_flags & PT_NC)) {
+ 				prot = (npv->pv_flags & PT_Wr) ?
+ 				    VM_PROT_READ | VM_PROT_WRITE :
+ 				    VM_PROT_READ;
  				ptes[arm_byte_to_page(npv->pv_va)] |=
! 				    pte_cache_mode[prot];
  				npv->pv_flags &= ~PT_NC;
  			}
  		}
***************
*** 2829,2844 ****
  		if ((flags & VM_PROT_ALL) & ~prot)
  			panic("pmap_enter: access_type exceeds prot");
  #endif
- 		npte |= pte_cache_mode;
  		if (flags & VM_PROT_WRITE) {
! 			npte |= L2_SPAGE | PT_AP(AP_W);
  			vm_physmem[bank].pmseg.attrs[off] |= 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;
  	} else {
  		if (prot & VM_PROT_WRITE)
  			npte |= L2_SPAGE | PT_AP(AP_W);
  		else if (prot & VM_PROT_ALL)
--- 2837,2854 ----
  		if ((flags & VM_PROT_ALL) & ~prot)
  			panic("pmap_enter: access_type exceeds prot");
  #endif
  		if (flags & VM_PROT_WRITE) {
! 			npte |=
! 			    pte_cache_mode[VM_PROT_READ|VM_PROT_WRITE] |
! 			    L2_SPAGE | PT_AP(AP_W);
  			vm_physmem[bank].pmseg.attrs[off] |= PT_H | PT_M;
  		} else if (flags & VM_PROT_ALL) {
! 			npte |= pte_cache_mode[VM_PROT_READ] | L2_SPAGE;
  			vm_physmem[bank].pmseg.attrs[off] |= PT_H;
  		} else
! 			npte |= pte_cache_mode[VM_PROT_READ] | L2_INVAL;
  	} else {
+ 		/* Implicitly un-cached. */
  		if (prot & VM_PROT_WRITE)
  			npte |= L2_SPAGE | PT_AP(AP_W);
  		else if (prot & VM_PROT_ALL)
***************
*** 2920,2926 ****
  	}
  	pte = vtopte(va);
  	KASSERT(!pmap_pte_v(pte));
! 	*pte = L2_PTE(pa, AP_KRW);
  }
  
  void
--- 2930,2942 ----
  	}
  	pte = vtopte(va);
  	KASSERT(!pmap_pte_v(pte));
! #if 1 /* XXX */
! 	*pte =  L2_SPTE(pa, AP_KRW,
! 	    pte_cache_mode[VM_PROT_READ|VM_PROT_WRITE]);
! #else
! 	*pte = L2_SPTE(pa, (prot & VM_PROT_WRITE) ? AP_KRW : AP_KR,
! 	    pte_cache_mode[prot]);
! #endif
  }
  
  void
***************
*** 3357,3363 ****
  		pte = pmap_pte(pv->pv_pmap, va);
  		KASSERT(pte != NULL);
  		if (maskbits & (PT_Wr|PT_M)) {
! 			if ((pv->pv_flags & PT_NC)) {
  				/* 
  				 * Entry is not cacheable: reenable
  				 * the cache, nothing to flush
--- 3373,3379 ----
  		pte = pmap_pte(pv->pv_pmap, va);
  		KASSERT(pte != NULL);
  		if (maskbits & (PT_Wr|PT_M)) {
! 			if (pv->pv_flags & PT_NC) {
  				/* 
  				 * Entry is not cacheable: reenable
  				 * the cache, nothing to flush
***************
*** 3375,3399 ****
  				 *
  				 */
  				if (maskbits & PT_Wr) {
! 					*pte |= pte_cache_mode;
  					pv->pv_flags &= ~PT_NC;
  				}
! 			} 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
  				 */
  				cpu_idcache_wbinv_range(pv->pv_va, NBPG);
  
  			/* make the pte read only */
  			*pte &= ~PT_AP(AP_W);
  		}
  
! 		if (maskbits & PT_H)
! 			*pte = (*pte & ~L2_MASK) | L2_INVAL;
  
! 		if (pmap_is_curpmap(pv->pv_pmap))
  			/* 
  			 * if we had cacheable pte's we'd clean the
  			 * pte out to memory here
--- 3391,3435 ----
  				 *
  				 */
  				if (maskbits & PT_Wr) {
! 					/*
! 					 * 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)) {
! 				/*
  				 * Entry is cacheable: check if pmap is
  				 * current 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);
+ 			if ((pv->pv_flags & PT_NC) == 0)
+ 				*pte = (*pte & ~pte_cache_bits) |
+ 				    pte_cache_mode[VM_PROT_READ];
  		}
  
! 		if (maskbits & PT_H) {
! 			/*
! 			 * We might be going from write-back to write-though,
! 			 * so make sure the cache is flushed.
! 			 *
! 			 * 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);
  
! 			*pte = (*pte & ~(L2_MASK | pte_cache_bits)) |
! 			    L2_INVAL | pte_cache_mode[VM_PROT_READ];
! 		}
! 
! 		if (pmap_is_curpmap(pv->pv_pmap)) {
  			/* 
  			 * if we had cacheable pte's we'd clean the
  			 * pte out to memory here
***************
*** 3401,3406 ****
--- 3437,3443 ----
  			 * flush tlb entry as it's in the current pmap
  			 */
  			cpu_tlb_flushID_SE(pv->pv_va); 
+ 		}
  	}
  	cpu_cpwait();
  
***************
*** 3540,3546 ****
  	 * 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);
  	PDEBUG(0, printf("->(%08x)\n", *pte));
  
  	simple_unlock(&pvh->pvh_lock);
--- 3577,3585 ----
  	 * already set the cacheable bits based on the assumption that we
  	 * can write to this page.
  	 */
! 	*pte = (*pte & ~(L2_MASK | pte_cache_bits)) |
! 	    L2_SPAGE | PT_AP(AP_W) |
! 	    pte_cache_mode[VM_PROT_READ|VM_PROT_WRITE];
  	PDEBUG(0, printf("->(%08x)\n", *pte));
  
  	simple_unlock(&pvh->pvh_lock);
***************
*** 3719,3723 ****
  //	pmap->pm_ptphint = ptp;
  	return (ptp);
  }
  
! /* End of pmap.c */
--- 3758,3830 ----
  //	pmap->pm_ptphint = ptp;
  	return (ptp);
  }
+ 
+ /*
+  * 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;
+ 
+ 	pte_cache_bits = PT_B | PT_C;
+ 
+ 	for (prot = 0; prot < 8; prot++)
+ 		pte_cache_mode[prot] = PT_B | PT_C;
+ }
+ #endif /* CPU_ARM6 || CPU_ARM7 || CPU_ARM7TDMI || CPU_ARM8 || CPU_SA110 */
  
! #if defined(CPU_ARM9)
! void
! pmap_pte_protos_init_arm9(void)
! {
! 	int prot;
! 
! 	pte_cache_bits = PT_B | PT_C;
! 
! 	/* We use the cache in write-through mode. */
! 
! 	for (prot = 0; prot < 8; prot++)
! 		pte_cache_mode[prot] = PT_C;
! }
! #endif /* CPU_ARM9 */
! 
! #if defined(CPU_XSCALE)
! void
! pmap_pte_protos_init_xscale(void)
! {
! 	int prot;
! 
! 	/* XXX X-bit */
! 	pte_cache_bits = PT_B | PT_C;
! 
! 	/* We use the cache in write-through mode. */
! 
! 	for (prot = 0; prot < 8; 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.
! 		 */
! 		if ((prot & VM_PROT_WRITE) == 0)
! 			pte_cache_mode[prot] = PT_C;
! 		else {
! 			/* Use the cache in write-though mode for now... */
! 			pte_cache_mode[prot] = PT_C;
! 		}
! 	}
! }
! #endif /* CPU_XSCALE */
Index: arm/footbridge/footbridge_machdep.c
===================================================================
RCS file: /cvsroot/syssrc/sys/arch/arm/footbridge/footbridge_machdep.c,v
retrieving revision 1.5
diff -c -r1.5 footbridge_machdep.c
*** arm/footbridge/footbridge_machdep.c	2002/01/05 22:41:48	1.5
--- arm/footbridge/footbridge_machdep.c	2002/01/30 04:26:03
***************
*** 77,83 ****
  
  	for (loop = 0; loop < cleanarea; loop += NBPG) {
  		pte = pmap_pte(pmap_kernel(), (addr + loop));
! 		*pte = L2_PTE(DC21285_SA_CACHE_FLUSH_BASE + loop, AP_KR);
  	}
  	sa110_cache_clean_addr = addr;
  	sa110_cache_clean_size = cleanarea / 2;
--- 77,84 ----
  
  	for (loop = 0; loop < cleanarea; loop += NBPG) {
  		pte = pmap_pte(pmap_kernel(), (addr + loop));
! 		*pte = L2_SPTE(DC21285_SA_CACHE_FLUSH_BASE + loop, AP_KR,
! 		    pte_cache_mode[VM_PROT_READ]);
  	}
  	sa110_cache_clean_addr = addr;
  	sa110_cache_clean_size = cleanarea / 2;
Index: arm/include/arm32/pmap.h
===================================================================
RCS file: /cvsroot/syssrc/sys/arch/arm/include/arm32/pmap.h,v
retrieving revision 1.20
diff -c -r1.20 pmap.h
*** arm/include/arm32/pmap.h	2002/01/19 16:55:22	1.20
--- arm/include/arm32/pmap.h	2002/01/30 04:26:03
***************
*** 138,147 ****
  } pv_addr_t;
  
  /*
!  * _KERNEL specific macros, functions and prototypes
   */
  
! #ifdef  _KERNEL
  
  /*
   * Commonly referenced structures
--- 138,151 ----
  } pv_addr_t;
  
  /*
!  * Cache mode for each prot type.
   */
+ extern pt_entry_t pte_cache_mode[8];
+ extern pt_entry_t pte_cache_bits;
  
! void	pmap_pte_protos_init_arm678(void);
! void	pmap_pte_protos_init_arm9(void);
! void	pmap_pte_protos_init_xscale(void);
  
  /*
   * Commonly referenced structures
***************
*** 181,188 ****
   */
  boolean_t	pmap_pageidlezero __P((paddr_t));
  #define PMAP_PAGEIDLEZERO(pa)	pmap_pageidlezero((pa))
- 
- #endif	/* _KERNEL */
  
  /*
   * Useful macros and constants 
--- 185,190 ----
Index: arm/include/arm32/pte.h
===================================================================
RCS file: /cvsroot/syssrc/sys/arch/arm/include/arm32/pte.h,v
retrieving revision 1.1
diff -c -r1.1 pte.h
*** arm/include/arm32/pte.h	2001/11/23 17:39:04	1.1
--- arm/include/arm32/pte.h	2002/01/30 04:26:03
***************
*** 74,85 ****
  #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) */
--- 74,79 ----
***************
*** 107,115 ****
  /* 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)
  
--- 101,106 ----
Index: arm/mainbus/mainbus_io.c
===================================================================
RCS file: /cvsroot/syssrc/sys/arch/arm/mainbus/mainbus_io.c,v
retrieving revision 1.6
diff -c -r1.6 mainbus_io.c
*** arm/mainbus/mainbus_io.c	2001/11/23 17:23:42	1.6
--- arm/mainbus/mainbus_io.c	2002/01/30 04:26:04
***************
*** 165,173 ****
  		pmap_kenter_pa(va, pa, VM_PROT_READ | VM_PROT_WRITE);
  		pte = pmap_pte(pmap_kernel(), va);
  		if (cacheable)
! 			*pte |= PT_CACHEABLE;
  		else
! 			*pte &= ~PT_CACHEABLE;
  	}
  	pmap_update(pmap_kernel());
  
--- 165,173 ----
  		pmap_kenter_pa(va, pa, VM_PROT_READ | VM_PROT_WRITE);
  		pte = pmap_pte(pmap_kernel(), va);
  		if (cacheable)
! 			*pte |= pte_cache_mode[VM_PROT_READ|VM_PROT_WRITE];
  		else
! 			*pte &= ~pte_cache_bits;
  	}
  	pmap_update(pmap_kernel());
  
Index: arm/sa11x0/sa11x0_io.c
===================================================================
RCS file: /cvsroot/syssrc/sys/arch/arm/sa11x0/sa11x0_io.c,v
retrieving revision 1.5
diff -c -r1.5 sa11x0_io.c
*** arm/sa11x0/sa11x0_io.c	2001/11/23 17:23:42	1.5
--- arm/sa11x0/sa11x0_io.c	2002/01/30 04:26:04
***************
*** 168,176 ****
  		pmap_kenter_pa(va, pa, VM_PROT_READ | VM_PROT_WRITE);
  		pte = pmap_pte(pmap_kernel(), va);
  		if (cacheable)
! 			*pte |= PT_CACHEABLE;
  		else
! 			*pte &= ~PT_CACHEABLE;
  	}
  	pmap_update(pmap_kernel());
  
--- 168,176 ----
  		pmap_kenter_pa(va, pa, VM_PROT_READ | VM_PROT_WRITE);
  		pte = pmap_pte(pmap_kernel(), va);
  		if (cacheable)
! 			*pte |= pte_cache_mode[VM_PROT_READ|VM_PROT_WRITE];
  		else
! 			*pte &= ~pte_cache_bits;
  	}
  	pmap_update(pmap_kernel());
  
Index: evbarm/integrator/int_bus_dma.c
===================================================================
RCS file: /cvsroot/syssrc/sys/arch/evbarm/integrator/int_bus_dma.c,v
retrieving revision 1.5
diff -c -r1.5 int_bus_dma.c
*** evbarm/integrator/int_bus_dma.c	2002/01/25 20:57:43	1.5
--- evbarm/integrator/int_bus_dma.c	2002/01/30 04:26:05
***************
*** 350,356 ****
  				cpu_dcache_wbinv_range(va, NBPG);
  				cpu_drain_writebuf();
  				ptep = vtopte(va);
! 				*ptep = ((*ptep) & (~PT_C | PT_B));
  				tlb_flush();
  			}
  #ifdef DEBUG_DMA
--- 350,356 ----
  				cpu_dcache_wbinv_range(va, NBPG);
  				cpu_drain_writebuf();
  				ptep = vtopte(va);
! 				*ptep = *ptep & ~pte_cache_bits;
  				tlb_flush();
  			}
  #ifdef DEBUG_DMA
Index: evbarm/integrator/integrator_machdep.c
===================================================================
RCS file: /cvsroot/syssrc/sys/arch/evbarm/integrator/integrator_machdep.c,v
retrieving revision 1.8
diff -c -r1.8 integrator_machdep.c
*** evbarm/integrator/integrator_machdep.c	2002/01/30 04:00:47	1.8
--- evbarm/integrator/integrator_machdep.c	2002/01/30 04:26:06
***************
*** 645,662 ****
  		totalsize = (totalsize + PGOFSET) & ~PGOFSET;
  		/* logical  = map_chunk(l1pagetable, l2pagetable, KERNEL_BASE,
  		    physical_start, KERNEL_TEXT_BASE - KERNEL_BASE,
! 		    AP_KRW, PT_CACHEABLE); */
  		logical = map_chunk(l1pagetable, l2pagetable,
  		    KERNEL_TEXT_BASE, physical_start, textsize,
! 		    AP_KRW, PT_CACHEABLE);
  		logical += map_chunk(l1pagetable, l2pagetable,
  		    KERNEL_TEXT_BASE + logical, physical_start + logical,
! 		    totalsize - textsize, AP_KRW, PT_CACHEABLE);
  #if 0
  		logical += map_chunk(0, l2pagetable, KERNEL_BASE + logical,
  		    physical_start + logical, kernexec->a_syms + sizeof(int)
  		    + *(u_int *)((int)end + kernexec->a_syms + sizeof(int)),
! 		    AP_KRW, PT_CACHEABLE);
  #endif
  	}
  
--- 645,663 ----
  		totalsize = (totalsize + PGOFSET) & ~PGOFSET;
  		/* logical  = map_chunk(l1pagetable, l2pagetable, KERNEL_BASE,
  		    physical_start, KERNEL_TEXT_BASE - KERNEL_BASE,
! 		    AP_KRW, pte_cache_mode[VM_PROT_READ|VM_PROT_WRITE]); */
  		logical = map_chunk(l1pagetable, l2pagetable,
  		    KERNEL_TEXT_BASE, physical_start, textsize,
! 		    AP_KRW, pte_cache_mode[VM_PROT_READ|VM_PROT_WRITE]);
  		logical += map_chunk(l1pagetable, l2pagetable,
  		    KERNEL_TEXT_BASE + logical, physical_start + logical,
! 		    totalsize - textsize, AP_KRW,
! 		    pte_cache_mode[VM_PROT_READ|VM_PROT_WRITE]);
  #if 0
  		logical += map_chunk(0, l2pagetable, KERNEL_BASE + logical,
  		    physical_start + logical, kernexec->a_syms + sizeof(int)
  		    + *(u_int *)((int)end + kernexec->a_syms + sizeof(int)),
! 		    AP_KRW, pte_cache_mode[VM_PROT_READ|VM_PROT_WRITE]);
  #endif
  	}
  
***************
*** 671,683 ****
  
  	/* Map the stack pages */
  	map_chunk(0, l2pagetable, irqstack.pv_va, irqstack.pv_pa,
! 	    IRQ_STACK_SIZE * NBPG, AP_KRW, PT_CACHEABLE);
  	map_chunk(0, l2pagetable, abtstack.pv_va, abtstack.pv_pa,
! 	    ABT_STACK_SIZE * NBPG, AP_KRW, PT_CACHEABLE);
  	map_chunk(0, l2pagetable, undstack.pv_va, undstack.pv_pa,
! 	    UND_STACK_SIZE * NBPG, AP_KRW, PT_CACHEABLE);
  	map_chunk(0, l2pagetable, kernelstack.pv_va, kernelstack.pv_pa,
! 	    UPAGES * NBPG, AP_KRW, PT_CACHEABLE);
  	map_chunk(0, l2pagetable, kernel_l1pt.pv_va, kernel_l1pt.pv_pa,
  	    PD_SIZE, AP_KRW, 0);
  
--- 672,688 ----
  
  	/* Map the stack pages */
  	map_chunk(0, l2pagetable, irqstack.pv_va, irqstack.pv_pa,
! 	    IRQ_STACK_SIZE * NBPG, AP_KRW,
! 	    pte_cache_mode[VM_PROT_READ|VM_PROT_WRITE]);
  	map_chunk(0, l2pagetable, abtstack.pv_va, abtstack.pv_pa,
! 	    ABT_STACK_SIZE * NBPG, AP_KRW,
! 	    pte_cache_mode[VM_PROT_READ|VM_PROT_WRITE]);
  	map_chunk(0, l2pagetable, undstack.pv_va, undstack.pv_pa,
! 	    UND_STACK_SIZE * NBPG, AP_KRW,
! 	    pte_cache_mode[VM_PROT_READ|VM_PROT_WRITE]);
  	map_chunk(0, l2pagetable, kernelstack.pv_va, kernelstack.pv_pa,
! 	    UPAGES * NBPG, AP_KRW,
! 	    pte_cache_mode[VM_PROT_READ|VM_PROT_WRITE]);
  	map_chunk(0, l2pagetable, kernel_l1pt.pv_va, kernel_l1pt.pv_pa,
  	    PD_SIZE, AP_KRW, 0);
  
Index: evbarm/iq80310/iq80310_machdep.c
===================================================================
RCS file: /cvsroot/syssrc/sys/arch/evbarm/iq80310/iq80310_machdep.c,v
retrieving revision 1.18
diff -c -r1.18 iq80310_machdep.c
*** evbarm/iq80310/iq80310_machdep.c	2002/01/30 04:01:36	1.18
--- evbarm/iq80310/iq80310_machdep.c	2002/01/30 04:26:06
***************
*** 612,629 ****
  		logical += map_chunk(l1pagetable, l2pagetable,
  		    KERNEL_BASE + logical,
  		    physical_start + logical, textsize,
! 		    AP_KRW, PT_CACHEABLE);
  		logical += map_chunk(l1pagetable, l2pagetable,
  		    KERNEL_BASE + logical,
  		    physical_start + logical, totalsize - textsize,
! 		    AP_KRW, PT_CACHEABLE);
  
  #if 0 /* XXX No symbols yet. */
  		logical += map_chunk(l1pagetable, l2pagetable,
  		    KERNEL_BASE + logical,
  		    physical_start + logical, kernexec->a_syms + sizeof(int)
  		    + *(u_int *)((int)end + kernexec->a_syms + sizeof(int)),
! 		    AP_KRW, PT_CACHEABLE);
  #endif
  	}
  
--- 612,629 ----
  		logical += map_chunk(l1pagetable, l2pagetable,
  		    KERNEL_BASE + logical,
  		    physical_start + logical, textsize,
! 		    AP_KRW, pte_cache_mode[VM_PROT_READ|VM_PROT_WRITE]);
  		logical += map_chunk(l1pagetable, l2pagetable,
  		    KERNEL_BASE + logical,
  		    physical_start + logical, totalsize - textsize,
! 		    AP_KRW, pte_cache_mode[VM_PROT_READ|VM_PROT_WRITE]);
  
  #if 0 /* XXX No symbols yet. */
  		logical += map_chunk(l1pagetable, l2pagetable,
  		    KERNEL_BASE + logical,
  		    physical_start + logical, kernexec->a_syms + sizeof(int)
  		    + *(u_int *)((int)end + kernexec->a_syms + sizeof(int)),
! 		    AP_KRW, pte_cache_mode[VM_PROT_READ|VM_PROT_WRITE]);
  #endif
  	}
  
***************
*** 633,651 ****
  
  	/* Map the stack pages */
  	map_chunk(0, l2pagetable, irqstack.pv_va, irqstack.pv_pa,
! 	    IRQ_STACK_SIZE * NBPG, AP_KRW, PT_CACHEABLE);
  	map_chunk(0, l2pagetable, abtstack.pv_va, abtstack.pv_pa,
! 	    ABT_STACK_SIZE * NBPG, AP_KRW, PT_CACHEABLE);
  	map_chunk(0, l2pagetable, undstack.pv_va, undstack.pv_pa,
! 	    UND_STACK_SIZE * NBPG, AP_KRW, PT_CACHEABLE);
  	map_chunk(0, l2pagetable, kernelstack.pv_va, kernelstack.pv_pa,
! 	    UPAGES * NBPG, AP_KRW, PT_CACHEABLE);
  	map_chunk(0, l2pagetable, kernel_l1pt.pv_va, kernel_l1pt.pv_pa,
  	    PD_SIZE, AP_KRW, 0);
  
  	/* Map the Mini-Data cache clean area. */
  	map_chunk(0, l2pagetable, minidataclean.pv_va, minidataclean.pv_pa,
! 	    NBPG, AP_KRW, PT_CACHEABLE);
  
  	/* Map the page table that maps the kernel pages */
  	map_entry_nc(l2pagetable, kernel_ptpt.pv_pa, kernel_ptpt.pv_pa);
--- 633,655 ----
  
  	/* Map the stack pages */
  	map_chunk(0, l2pagetable, irqstack.pv_va, irqstack.pv_pa,
! 	    IRQ_STACK_SIZE * NBPG, AP_KRW,
! 	    pte_cache_mode[VM_PROT_READ|VM_PROT_WRITE]);
  	map_chunk(0, l2pagetable, abtstack.pv_va, abtstack.pv_pa,
! 	    ABT_STACK_SIZE * NBPG, AP_KRW,
! 	    pte_cache_mode[VM_PROT_READ|VM_PROT_WRITE]);
  	map_chunk(0, l2pagetable, undstack.pv_va, undstack.pv_pa,
! 	    UND_STACK_SIZE * NBPG, AP_KRW,
! 	    pte_cache_mode[VM_PROT_READ|VM_PROT_WRITE]);
  	map_chunk(0, l2pagetable, kernelstack.pv_va, kernelstack.pv_pa,
! 	    UPAGES * NBPG, AP_KRW,
! 	    pte_cache_mode[VM_PROT_READ|VM_PROT_WRITE]);
  	map_chunk(0, l2pagetable, kernel_l1pt.pv_va, kernel_l1pt.pv_pa,
  	    PD_SIZE, AP_KRW, 0);
  
  	/* Map the Mini-Data cache clean area. */
  	map_chunk(0, l2pagetable, minidataclean.pv_va, minidataclean.pv_pa,
! 	    NBPG, AP_KRW, pte_cache_mode[VM_PROT_READ|VM_PROT_WRITE]);
  
  	/* Map the page table that maps the kernel pages */
  	map_entry_nc(l2pagetable, kernel_ptpt.pv_pa, kernel_ptpt.pv_pa);

--+Yg8W10oK6rlW0RR--