From 11fe8c59c6c145bca52e977363183add0fbe1b59 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Mon, 26 Mar 2018 06:18:51 +0200 Subject: bsps/powerpc: Move MMU support to bsps This patch is a part of the BSP source reorganization. Update #3285. --- c/src/lib/libcpu/powerpc/Makefile.am | 16 - c/src/lib/libcpu/powerpc/e500/mmu/mmu.c | 631 -------------- c/src/lib/libcpu/powerpc/mpc6xx/mmu/bat.c | 545 ------------ c/src/lib/libcpu/powerpc/mpc6xx/mmu/mmuAsm.S | 530 ------------ c/src/lib/libcpu/powerpc/mpc6xx/mmu/pte121.c | 1139 -------------------------- 5 files changed, 2861 deletions(-) delete mode 100644 c/src/lib/libcpu/powerpc/e500/mmu/mmu.c delete mode 100644 c/src/lib/libcpu/powerpc/mpc6xx/mmu/bat.c delete mode 100644 c/src/lib/libcpu/powerpc/mpc6xx/mmu/mmuAsm.S delete mode 100644 c/src/lib/libcpu/powerpc/mpc6xx/mmu/pte121.c (limited to 'c/src/lib/libcpu') diff --git a/c/src/lib/libcpu/powerpc/Makefile.am b/c/src/lib/libcpu/powerpc/Makefile.am index 5f5813d350..f61524f496 100644 --- a/c/src/lib/libcpu/powerpc/Makefile.am +++ b/c/src/lib/libcpu/powerpc/Makefile.am @@ -41,14 +41,6 @@ endif # ppc405 if mpc6xx -# mpc6xx/mmu -noinst_PROGRAMS += mpc6xx/mmu.rel -mpc6xx_mmu_rel_SOURCES = mpc6xx/mmu/bat.c mpc6xx/mmu/bat.h \ - mpc6xx/mmu/pte121.c mpc6xx/mmu/pte121.h \ - mpc6xx/mmu/mmuAsm.S -mpc6xx_mmu_rel_CPPFLAGS = $(AM_CPPFLAGS) -mpc6xx_mmu_rel_LDFLAGS = $(RTEMS_RELLDFLAGS) - # mpc6xx/clock noinst_PROGRAMS += mpc6xx/clock.rel mpc6xx_clock_rel_SOURCES = mpc6xx/clock/c_clock.c mpc6xx/clock/c_clock.h @@ -71,12 +63,4 @@ e500_clock_rel_CPPFLAGS = $(AM_CPPFLAGS) e500_clock_rel_LDFLAGS = $(RTEMS_RELLDFLAGS) endif -# e500/mmu -if e500_mmu -noinst_PROGRAMS += e500/mmu.rel -e500_mmu_rel_SOURCES = e500/mmu/mmu.c e500/mmu/e500_mmu.h -e500_mmu_rel_CPPFLAGS = $(AM_CPPFLAGS) -e500_mmu_rel_LDFLAGS = $(RTEMS_RELLDFLAGS) -endif - include $(top_srcdir)/../../../automake/local.am diff --git a/c/src/lib/libcpu/powerpc/e500/mmu/mmu.c b/c/src/lib/libcpu/powerpc/e500/mmu/mmu.c deleted file mode 100644 index 15fe88f91a..0000000000 --- a/c/src/lib/libcpu/powerpc/e500/mmu/mmu.c +++ /dev/null @@ -1,631 +0,0 @@ -/* - * Routines to manipulate e500 TLBs; TLB0 (fixed 4k page size) - * is not very useful so we mostly focus on TLB1 (variable page size). - * - * TLB0's 256 entries are 2-way set associative which means that - * only 2 entries for page index numbers with matching 7 LSBs - * are available. - * - * E.g., look at EA = 0xAAAyy000. 0xAAAyy is the page index. - * - * The least-significant 7 bits in 'yy' determine the 'way' - * in the TLB 0 array. At most two EAs with matching 'yy' bits - * (the 7 LSBs, that is) can be mapped with TLB0 since there - * are only two entries per 'way'. - * - * Since this is a real-time OS we want to stay away from - * software TLB replacement. - */ - -/* - * Authorship - * ---------- - * This software was created by - * Till Straumann , 2005-2007, - * Stanford Linear Accelerator Center, Stanford University. - * - * Acknowledgement of sponsorship - * ------------------------------ - * This software was produced by - * the Stanford Linear Accelerator Center, Stanford University, - * under Contract DE-AC03-76SFO0515 with the Department of Energy. - * - * Government disclaimer of liability - * ---------------------------------- - * Neither the United States nor the United States Department of Energy, - * nor any of their employees, makes any warranty, express or implied, or - * assumes any legal liability or responsibility for the accuracy, - * completeness, or usefulness of any data, apparatus, product, or process - * disclosed, or represents that its use would not infringe privately owned - * rights. - * - * Stanford disclaimer of liability - * -------------------------------- - * Stanford University makes no representations or warranties, express or - * implied, nor assumes any liability for the use of this software. - * - * Stanford disclaimer of copyright - * -------------------------------- - * Stanford University, owner of the copyright, hereby disclaims its - * copyright and all other rights in this software. Hence, anyone may - * freely use it for any purpose without restriction. - * - * Maintenance of notices - * ---------------------- - * In the interest of clarity regarding the origin and status of this - * SLAC software, this and all the preceding Stanford University notices - * are to remain affixed to any copy or derivative of this software made - * or distributed by the recipient and are to be affixed to any copy of - * software made or distributed by the recipient that contains a copy or - * derivative of this software. - * - * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03 - */ - -/* 8450 MSR definitions; note that there are *substantial* differences - * compared to classic powerpc; in particular, IS/DS are *different* - * from IR/DR; the e500 MMU can not be switched off! - * - * Also: To disable/enable all external interrupts, CE and EE must both be - * controlled. - */ -#include -#include -#include -#include - -#include - -#define TLBIVAX_TLBSEL (1<<(63-60)) -#define TLBIVAX_INV_ALL (1<<(63-61)) - -#define E500_TLB_ATTR_WIMGE(x) ((x)&0x7f) /* includes user bits */ -#define E500_TLB_ATTR_WIMGE_GET(x) ((x)&0x7f) -#define E500_TLB_ATTR_TS (1<<7) -#define E500_TLB_ATTR_PERM(x) (((x)&0x3ff)<<8) -#define E500_TLB_ATTR_PERM_GET(x) (((x)>>8)&0x3ff) -#define E500_TLB_ATTR_TID(x) (((x)&0xfff)<<20) -#define E500_TLB_ATTR_TID_GET(x) (((x)>>20)&0xfff) - - -#ifdef DEBUG -#define STATIC -#else -#define STATIC static -#endif - -/* Factory to generate inline macros for accessing the MAS registers */ -#define __RDWRMAS(mas,rmas) \ - static inline uint32_t _read_MAS##mas(void) \ - { uint32_t x; __asm__ volatile("mfspr %0, %1": "=r"(x):"i"(rmas)); return x; } \ - static inline void _write_MAS##mas(uint32_t x) \ - { __asm__ volatile("mtspr %1, %0":: "r"(x),"i"(rmas)); } - -__RDWRMAS(0,FSL_EIS_MAS0) -__RDWRMAS(1,FSL_EIS_MAS1) -__RDWRMAS(2,FSL_EIS_MAS2) -__RDWRMAS(3,FSL_EIS_MAS3) -__RDWRMAS(4,FSL_EIS_MAS4) -__RDWRMAS(6,FSL_EIS_MAS6) - -#undef __RDWRMAS - -static int initialized = 0; - -E500_tlb_va_cache_t rtems_e500_tlb_va_cache[16]; - -/* Since it is likely that these routines are used during - * early initialization when stdio is not available yet - * we provide a helper that resorts to 'printk()' - */ -static void -myprintf(FILE *f, char *fmt, ...) -{ - va_list ap; - va_start(ap, fmt); - - if (!f || !_impure_ptr->__sdidinit) { - /* - * Might be called at an early stage when - * stdio is not yet initialized. - */ - vprintk(fmt,ap); - } else { - vfprintf(f,fmt,ap); - } - va_end(ap); -} - - -void -rtems_e500_dmptlbc(FILE *f) -{ -int i; - if ( !initialized ) { - myprintf(stderr,"TLB cache not initialized\n"); - return; - } - for ( i=0; i<16; i++ ) { - if ( !rtems_e500_tlb_va_cache[i].att.v ) - continue; - myprintf(f,"#%2i: TID 0x%03x, TS %i, ea 0x%08x .. 0x%08x\n", - i, - rtems_e500_tlb_va_cache[i].va.va_tid, - rtems_e500_tlb_va_cache[i].att.ts, - rtems_e500_tlb_va_cache[i].va.va_epn<<12, - (rtems_e500_tlb_va_cache[i].va.va_epn<<12) + (1024<<(2*rtems_e500_tlb_va_cache[i].att.sz))-1); - myprintf(f,"PA 0x%08"PRIx32", PERM 0x%03x, WIMGE 0x%02x\n", - rtems_e500_tlb_va_cache[i].rpn<<12, - rtems_e500_tlb_va_cache[i].att.perm, - rtems_e500_tlb_va_cache[i].att.wimge); - } -} - -#define E500_SELTLB_1 0x1000 - -static void seltlb(rtems_e500_tlb_idx key) -{ -int idx = key & ~E500_SELTLB_1; - - if ( key & E500_SELTLB_1 ) { - _write_MAS0( FSL_EIS_MAS0_TLBSEL | FSL_EIS_MAS0_ESEL(idx) ); - } else { - _write_MAS0( (idx & 128) ? FSL_EIS_MAS0_ESEL(1) : FSL_EIS_MAS0_ESEL(0) ); - _write_MAS2( FSL_EIS_MAS2_EPN( idx & 127 ) ); - } -} - -/* - * Read a TLB entry from the hardware; if it is a TLB1 entry - * then the current settings are stored in the - * rtems_e500_tlb_va_cache[] structure. - * - * The routine can perform this operation quietly or - * print information to a file. - * - * 'sel': which TLB array to use; TLB0 (4k) if zero, - * TLB1 (variable) if nonzero. - * 'idx': which TLB entry to access. - * 'quiet': perform operation silently (no info printed) - * if nonzero. - * 'f': open FILE where to print information. May be - * NULL in which case 'stdout' is used. - * - * RETURNS: - * 0: success; TLB entry is VALID - * +1: success but TLB entry is INVALID - * < 0: error (-1: invalid argument) - */ -int -rtems_e500_prtlb(rtems_e500_tlb_idx key, int quiet, FILE *f) -{ - uint32_t mas1, mas2, mas3; - rtems_interrupt_level lvl; - E500_tlb_va_cache_t *tlb; - E500_tlb_va_cache_t buf; - int sel, idx; - - sel = (key & E500_SELTLB_1) ? 1 : 0; - idx = key & ~E500_SELTLB_1; - - if ( idx < 0 || idx > 255 || ( idx > 15 && sel ) ) - return -1; - - rtems_interrupt_disable(lvl); - - seltlb( key ); - - asm volatile("tlbre"); - - /* not manipulating MAS0, skip reading it */ - mas1 = _read_MAS1(); - mas2 = _read_MAS2(); - mas3 = _read_MAS3(); - - rtems_interrupt_enable(lvl); - - tlb = sel ? rtems_e500_tlb_va_cache + idx : &buf; - - if ( (tlb->att.v = (FSL_EIS_MAS1_V & mas1) ? 1 : 0) ) { - tlb->va.va_epn = FSL_EIS_MAS2_EPN_GET(mas2); - tlb->rpn = FSL_EIS_MAS3_RPN_GET(mas3); - tlb->va.va_tid = FSL_EIS_MAS1_TID_GET(mas1); - tlb->att.ts = (FSL_EIS_MAS1_TS & mas1) ? 1 : 0; - tlb->att.sz = sel ? FSL_EIS_MAS1_TSIZE_GET(mas1) : 1 /* 4k size */; - tlb->att.wimge = FSL_EIS_MAS2_ATTR_GET(mas2); - tlb->att.perm = FSL_EIS_MAS3_PERM_GET(mas3); - } - - if ( tlb->att.v ) { - if ( !quiet ) { -/* - "TLB[1] Entry # 0 spans EA range 0x00000000 .. 0x00000000 - "Mapping: VA [TS 0/TID 0x00/EPN 0x00000] -> RPN 0x00000" - "Size: TSIZE 0x0 ( 4^ts KiB = 000000 KiB = 0x00000000 B) - "Attributes: PERM 0x000 (ux/sx/uw/sw/ur/sr) WIMGE 0x00 IPROT 0" -*/ - myprintf(f, - "TLB[%i] Entry # %d spans EA range 0x%08x .. 0x%08x\r\n", - sel, - idx, - (tlb->va.va_epn << 12), - (tlb->va.va_epn << 12) + (1024<<(2*tlb->att.sz)) - 1 - ); - - myprintf(f, - "Mapping: VA [TS %d/TID 0x%02x/EPN 0x%05x] -> RPN 0x%05"PRIx32"\r\n", - tlb->att.ts, tlb->va.va_tid, tlb->va.va_epn, tlb->rpn - ); - myprintf(f, - "Size: TSIZE 0x%x ( 4^ts KiB = %6d KiB = 0x%08x B)\r\n", - tlb->att.sz, (1<<(2*tlb->att.sz)), (1024<<(2*tlb->att.sz)) - ); - myprintf(f, - "Attributes: PERM 0x%03x (ux/sx/uw/sw/ur/sr) WIMGE 0x%02x IPROT %i\r\n", - tlb->att.perm, tlb->att.wimge, (sel && (mas1 & FSL_EIS_MAS1_IPROT) ? 1 : 0) - ); - myprintf(f, - "EA range 0x%08x .. 0x%08x\r\n", - (tlb->va.va_epn << 12), - (tlb->va.va_epn << 12) + (1024<<(2*tlb->att.sz)) - 1 - ); - } - } else { - if ( !quiet ) { - myprintf(f, "TLB[%i] Entry #%i (size 0x%x = 0x%xb)\n", sel, idx, tlb->att.sz, (1024<<(2*tlb->att.sz))); - } - return 1; - } - return 0; -} - -/* Initialize cache; verify that TLB0 is unused; - * - * RETURNS: zero on success, nonzero on error (TLB0 - * seems to be in use); in this case the - * driver will refuse to change TLB1 entries - * (other than disabling them). - */ -int rtems_e500_initlb() -{ -int i; -int rval = 0; - for (i=0; i<16; i++) - rtems_e500_prtlb(E500_SELTLB_1 | i, 1, 0); - for (i=0; i<256; i++) { - /* refuse to enable operations that change TLB entries - * if anything in TLB[0] is valid (because we currently - * don't check against overlap with TLB[0] when we - * write a new entry). - */ - if ( rtems_e500_prtlb(E500_SELTLB_0 | i, 1, 0) <=0 ) { - myprintf(stderr,"WARNING: 4k TLB #%i seems to be valid; UNSUPPORTED configuration\n", i); - rval = -1; - } - } - if ( !rval ) - initialized = 1; - return rval; -} - -/* - * Write TLB1 entry (can also be used to disable an entry). - * - * The routine checks against the cached data in - * rtems_e500_tlb_va[] to prevent the user from generating - * overlapping entries. - * - * 'idx': TLB 1 entry # to manipulate - * 'ea': Effective address (must be page aligned) - * 'pa': Physical address (must be page aligned) - * 'sz': Page size selector; page size is - * 1024 * 2^(2*sz) bytes. - * 'sz' may also be one of the following: - * - page size in bytes ( >= 1024 ); the selector - * value is then computed by this routine. - * However, 'sz' must be a valid page size - * or -1 will be returned. - * - a value < 0 to invalidate/disable the - * TLB entry. - * 'attr': Page attributes; ORed combination of WIMGE, - * PERMissions, TID and TS. Use ATTR_xxx macros - * - * RETURNS: 0 on success, nonzero on error: - * - * >0: requested mapping would overlap with - * existing mapping in other entry. Return - * value gives conflicting entry + 1; i.e., - * if a value of 4 is returned then the request - * conflicts with existing mapping in entry 3. - * -1: invalid argument - * -3: driver not initialized (or initialization - * failed because TLB0 is in use). - * <0: other error - * - */ -#define E500_TLB_ATTR_WIMGE(x) ((x)&0x7f) /* includes user bits */ -#define E500_TLB_ATTR_WIMGE_GET(x) ((x)&0x7f) -#define E500_TLB_ATTR_TS (1<<7) -#define E500_TLB_ATTR_PERM(x) (((x)&0x3ff)<<8) -#define E500_TLB_ATTR_PERM_GET(x) (((x)>>8)&0x3ff) -#define E500_TLB_ATTR_TID(x) (((x)&0xfff)<<20) -#define E500_TLB_ATTR_TID_GET(x) (((x)>>20)&0xfff) - -int -rtems_e500_wrtlb(int idx, uint32_t ea, uint32_t pa, int sz, uint32_t attr) -{ -uint32_t mas1, mas2, mas3, mas4; -uint32_t tid, msk; -int lkup; -rtems_interrupt_level lvl; - - if ( sz >= 1024 ) { - /* Assume they literally specify a size */ - msk = sz; - sz = 0; - while ( msk != (1024<<(2*sz)) ) { - if ( ++sz > 15 ) { - return -1; - } - } - /* OK, acceptable */ - } - - msk = sz > 0 ? (1024<<(2*sz)) - 1 : 0; - - if ( !initialized && sz > 0 ) { - myprintf(stderr,"TLB driver not initialized; refuse to enable any entry\n"); - return -3; - } - - if ( (ea & msk) || (pa & msk) ) { - myprintf(stderr,"Misaligned ea or pa\n"); - return -1; - } - - if ( idx < 0 || idx > 15 ) - return -1; - - if ( sz > 15 ) { - /* but e500v1 doesn't support all 16 sizes!! */ - /* FIXME: we should inquire about this CPU's - * capabilities... - */ - return -1; - } - - tid = E500_TLB_ATTR_TID_GET(attr); - - mas1 = (attr & E500_TLB_ATTR_TS) ? FSL_EIS_MAS1_TS : 0; - - if ( sz >=0 ) { - lkup = rtems_e500_matchtlb(ea, tid, mas1, sz); - - if ( lkup < -1 ) { - /* some error */ - return lkup; - } - - if ( lkup >= 0 && lkup != idx ) { - myprintf(stderr,"TLB[1] #%i overlaps with requested mapping\n", lkup); - rtems_e500_prtlb( E500_SELTLB_1 | lkup, 0, stderr); - return lkup+1; - } - } - - /* OK to proceed */ - mas1 |= FSL_EIS_MAS1_IPROT | FSL_EIS_MAS1_TID(tid); - - if ( sz >= 0 ) - mas1 |= FSL_EIS_MAS1_V | FSL_EIS_MAS1_TSIZE(sz); - - mas2 = FSL_EIS_MAS2_EPN( ea>>12 ) | E500_TLB_ATTR_WIMGE(attr); - mas3 = FSL_EIS_MAS3_RPN( pa>>12 ) | E500_TLB_ATTR_PERM_GET(attr); - /* mas4 is not really relevant; we don't use TLB replacement */ - mas4 = FSL_EIS_MAS4_TLBSELD | FSL_EIS_MAS4_TIDSELD(0) | FSL_EIS_MAS4_TSIZED(9) | FSL_EIS_MAS4_ID | FSL_EIS_MAS4_GD; - - rtems_interrupt_disable(lvl); - - seltlb(idx | E500_SELTLB_1); - - _write_MAS1(mas1); - _write_MAS2(mas2); - _write_MAS3(mas3); - _write_MAS4(mas4); - - asm volatile( - " sync\n" - " isync\n" - " tlbwe\n" - " sync\n" - " isync\n" - ); - - rtems_interrupt_enable(lvl); - - /* update cache */ - rtems_e500_prtlb( E500_SELTLB_1 | idx, 1, 0); - - return 0; -} - -/* - * Check if a ts/tid/ea/sz mapping overlaps - * with an existing entry. - * - * ASSUMPTION: all TLB0 (fixed 4k pages) are invalid and always unused. - * - * NOTE: 'sz' is the 'logarithmic' size selector; the page size - * is 1024*2^(2*sz). - * - * RETURNS: - * >= 0: index of TLB1 entry that already provides a mapping - * which overlaps within the ea range. - * -1: SUCCESS (no conflicting entry found) - * <=-2: ERROR (invalid input) - */ -int rtems_e500_matchtlb(uint32_t ea, uint32_t tid, int ts, int sz) -{ -int i; -uint32_t m,a; -E500_tlb_va_cache_t *tlb; - - if ( sz < 0 || sz > 15 ) - return -4; - - sz = (1024<<(2*sz)); - - if ( !initialized ) { - /* cache not initialized */ - return -3; - } - - if ( ea & (sz-1) ) { - /* misaligned ea */ - return -2; - } - - if ( ts ) - ts = 1; - - for ( i=0, tlb=rtems_e500_tlb_va_cache; i<16; i++, tlb++ ) { - if ( ! tlb->att.v ) - continue; - if ( tlb->att.ts != ts ) - continue; - if ( tlb->va.va_tid && tlb->va.va_tid != tid ) - continue; - /* TID and TS match a valid entry */ - m = (1024<<(2*tlb->att.sz)) - 1; - /* calculate starting address of this entry */ - a = tlb->va.va_epn<<12; - if ( ea <= a + m && ea + sz -1 >= a ) { - /* overlap */ - return i; - } - } - return -1; -} - -/* Find TLB index that maps 'ea/as' combination - * - * RETURNS: index 'key'; i.e., the index number plus - * a bit (E500_SELTLB_1) which indicates whether - * the mapping was found in TLB0 (4k fixed page - * size) or in TLB1 (variable page size). - * - * On error (no mapping) -1 is returned. - */ -rtems_e500_tlb_idx -rtems_e500_ftlb(uint32_t ea, int as) -{ -uint32_t pid, mas0, mas1; -int i, rval = -1; -rtems_interrupt_level lvl; - - rtems_interrupt_disable(lvl); - - for ( i=0; i<3; i++ ) { - switch (i) { - case 0: asm volatile("mfspr %0, %1":"=r"(pid):"i"(FSL_EIS_PID0)); break; - case 1: asm volatile("mfspr %0, %1":"=r"(pid):"i"(FSL_EIS_PID1)); break; - case 2: asm volatile("mfspr %0, %1":"=r"(pid):"i"(FSL_EIS_PID2)); break; - default: - goto bail; - } - - _write_MAS6( FSL_EIS_MAS6_SPID0(pid) | (as ? FSL_EIS_MAS6_SAS : 0 ) ); - - asm volatile("tlbsx 0, %0"::"r"(ea)); - - mas1 = _read_MAS1(); - - if ( (FSL_EIS_MAS1_V & mas1) ) { - mas0 = _read_MAS0(); - if ( FSL_EIS_MAS0_TLBSEL & mas0 ) { - /* TLB1 */ - rval = FSL_EIS_MAS0_ESEL_GET(mas0) | E500_SELTLB_1; - } else { - rval = (ea >> (63-51)) | (( FSL_EIS_MAS0_NV & mas0 ) ? 180 : 0 ) ; - } - break; - } - } - -bail: - rtems_interrupt_enable(lvl); - return rval; -} - -/* Mark TLB entry as invalid ('disabled'). Unlike - * rtems_e500_wrtlb() with a negative size argument - * this routine also can disable TLB0 entries. - * - * 'key': TLB entry (index) ORed with selector bit - * (0 for TLB0, E500_SELTLB_1 for TLB1). - * - * RETURNS: zero on success, nonzero on error (TLB - * unchanged). - * - * NOTE: If a TLB1 entry is disabled the associated - * entry in rtems_e500_va_cache[] is also - * marked as disabled. - */ -int -rtems_e500_clrtlb(rtems_e500_tlb_idx key) -{ -rtems_e500_tlb_idx k0; -rtems_interrupt_level lvl; - - /* minimal guard against bad key */ - if ( key < 0 ) - return -1; - - if ( (key & E500_SELTLB_1) ) { - if ( (key & ~E500_SELTLB_1) > 15 ) { - myprintf(stderr,"Invalid TLB index; TLB1 index must be < 16\n"); - return -1; - } - } else if ( key > 255 ) { - myprintf(stderr,"Invalid TLB index; TLB0 index must be < 256\n"); - return -1; - } - - /* Must not invalidate page 0 which holds vectors, text etc... */ - k0 = rtems_e500_ftlb(0, 0); - if ( -1 == k0 ) { - myprintf(stderr,"tlbivax; something's fishy - I don't find mapping for addr. 0\n"); - return -1; - } - - /* NOTE: we assume PID is ignored, and AS is 0 */ - if ( k0 == key ) { - myprintf(stderr,"Refuse to invalidate page holding addr 0 (always needed)\n"); - return -1; - } - - rtems_interrupt_disable(lvl); - - seltlb(key); - - asm volatile("tlbre"); - - /* read old entries */ - _write_MAS1( _read_MAS1() & ~FSL_EIS_MAS1_V ); - - asm volatile( - " sync\n" - " isync\n" - " tlbwe\n" - " sync\n" - " isync\n" - ); - - /* update cache */ - if ( E500_SELTLB_1 & key ) - rtems_e500_tlb_va_cache[ (~E500_SELTLB_1 & key) ].att.v = 0; - - rtems_interrupt_enable(lvl); - - return 0; -} diff --git a/c/src/lib/libcpu/powerpc/mpc6xx/mmu/bat.c b/c/src/lib/libcpu/powerpc/mpc6xx/mmu/bat.c deleted file mode 100644 index 7a9487b9ff..0000000000 --- a/c/src/lib/libcpu/powerpc/mpc6xx/mmu/bat.c +++ /dev/null @@ -1,545 +0,0 @@ -/* - * bat.c - * - * This file contains the implementation of C function to - * Instantiate 60x/7xx ppc Block Address Translation (BAT) registers. - * More detailed information can be found on motorola - * site and more precisely in the following book : - * - * MPC750 - * Risc Microporcessor User's Manual - * Mtorola REF : MPC750UM/AD 8/97 - * - * Copyright (C) 1999 Eric Valette (valette@crf.canon.fr) - * Canon Centre Recherche France. - * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.org/license/LICENSE. - */ -#include -#include -#include -#include - -#include - -#define TYP_I 1 -#define TYP_D 0 - -typedef union -{ /* BAT register values to be loaded */ - BAT bat; - struct - { - unsigned int u, l; - } words; -} ubat; - -typedef struct batrange -{ /* stores address ranges mapped by BATs */ - unsigned long start; - unsigned long limit; - unsigned long phys; -} batrange; - -batrange bat_addrs[2][8] = { { {0,} } }; - -/* could encode this in bat_addrs but I don't touch that one for bwds compat. reasons */ -/* bitmask of used bats */ -static unsigned bat_in_use[2] = { 0, 0 }; - -/* define a few macros */ - -#define CLRBAT_ASM(batu,r) \ - " sync \n" \ - " isync \n" \ - " li "#r ", 0 \n" \ - " mtspr "#batu ", "#r "\n" \ - " sync \n" \ - " isync \n" - -#define SETBAT_ASM(batu, batl, u, l)\ - " mtspr "#batl ", "#l " \n" \ - " sync \n" \ - " isync \n" \ - " mtspr "#batu ", "#u " \n" \ - " sync \n" \ - " isync \n" - -#define CLRBAT(bat) \ - asm volatile( \ - CLRBAT_ASM(%0, 0) \ - : \ - :"i"(bat##U) \ - :"0") - -#define GETBAT(bat,u,l) \ - asm volatile( \ - " mfspr %0, %2 \n" \ - " mfspr %1, %3 \n" \ - :"=r"(u),"=r"(l) \ - :"i"(bat##U),"i"(bat##L) \ - ) - -#define DECL_SETBAT(lcbat,bat) \ -void \ -asm_set##lcbat(unsigned int upper, unsigned int lower) \ -{ \ -asm volatile( \ - CLRBAT_ASM(%0,0) \ - SETBAT_ASM(%0,%1,%2,%3) \ - : \ - :"i"(bat##U), \ - "i"(bat##L), \ - "r"(upper),"r"(lower) \ - :"0"); \ -} - -/* export the 'asm' versions for historic reasons */ -DECL_SETBAT (dbat0, DBAT0) -DECL_SETBAT (dbat1, DBAT1) -DECL_SETBAT (dbat2, DBAT2) -DECL_SETBAT (dbat3, DBAT3) - -static DECL_SETBAT (dbat4, DBAT4) -static DECL_SETBAT (dbat5, DBAT5) -static DECL_SETBAT (dbat6, DBAT6) -static DECL_SETBAT (dbat7, DBAT7) - -static DECL_SETBAT (ibat0, IBAT0) -static DECL_SETBAT (ibat1, IBAT1) -static DECL_SETBAT (ibat2, IBAT2) -static DECL_SETBAT (ibat3, IBAT3) -static DECL_SETBAT (ibat4, IBAT4) -static DECL_SETBAT (ibat5, IBAT5) -static DECL_SETBAT (ibat6, IBAT6) -static DECL_SETBAT (ibat7, IBAT7) - - -SPR_RO (HID0); - -static void -set_hid0_sync (unsigned long val) -{ - __asm__ volatile ( - " sync \n" - " isync \n" - " mtspr %0, %1 \n" - " sync \n" - " isync \n" - : - :"i" (HID0), "r" (val) - :"memory" /* paranoia */ - ); -} - -static void -bat_addrs_put (ubat * bat, int typ, int idx) -{ - unsigned long bl; - if (bat->bat.batu.vp || bat->bat.batu.vs) { - bat_addrs[typ][idx].start = bat->bat.batu.bepi << 17; - bat_addrs[typ][idx].phys = bat->bat.batl.brpn << 17; - - /* extended BL cannot be extracted using BAT union - * - let's just hope the upper bits read 0 on pre 745x - * CPUs. - */ - bl = (bat->words.u << 15) | ((1 << 17) - 1); - bat_addrs[typ][idx].limit = bat_addrs[typ][idx].start + bl; - - bat_in_use[typ] |= (1 << idx); - } -} - -/* We don't know how the board was initialized. Therefore, - * when 'setdbat' is first used we must initialize our - * cache. - */ -static void -bat_addrs_init (void) -{ - ubat bat; - - GETBAT (DBAT0, bat.words.u, bat.words.l); - bat_addrs_put (&bat, TYP_D, 0); - GETBAT (DBAT1, bat.words.u, bat.words.l); - bat_addrs_put (&bat, TYP_D, 1); - GETBAT (DBAT2, bat.words.u, bat.words.l); - bat_addrs_put (&bat, TYP_D, 2); - GETBAT (DBAT3, bat.words.u, bat.words.l); - bat_addrs_put (&bat, TYP_D, 3); - - GETBAT (IBAT0, bat.words.u, bat.words.l); - bat_addrs_put (&bat, TYP_I, 0); - GETBAT (IBAT1, bat.words.u, bat.words.l); - bat_addrs_put (&bat, TYP_I, 1); - GETBAT (IBAT2, bat.words.u, bat.words.l); - bat_addrs_put (&bat, TYP_I, 2); - GETBAT (IBAT3, bat.words.u, bat.words.l); - bat_addrs_put (&bat, TYP_I, 3); - - - if ( ppc_cpu_has_8_bats() && (HID0_7455_HIGH_BAT_EN & _read_HID0 ())) { - GETBAT (DBAT4, bat.words.u, bat.words.l); - bat_addrs_put (&bat, TYP_D, 4); - GETBAT (DBAT5, bat.words.u, bat.words.l); - bat_addrs_put (&bat, TYP_D, 5); - GETBAT (DBAT6, bat.words.u, bat.words.l); - bat_addrs_put (&bat, TYP_D, 6); - GETBAT (DBAT7, bat.words.u, bat.words.l); - bat_addrs_put (&bat, TYP_D, 7); - GETBAT (IBAT4, bat.words.u, bat.words.l); - bat_addrs_put (&bat, TYP_I, 4); - GETBAT (IBAT5, bat.words.u, bat.words.l); - bat_addrs_put (&bat, TYP_I, 5); - GETBAT (IBAT6, bat.words.u, bat.words.l); - bat_addrs_put (&bat, TYP_I, 6); - GETBAT (IBAT7, bat.words.u, bat.words.l); - bat_addrs_put (&bat, TYP_I, 7); - } -} - -static void -do_dssall (void) -{ - /* Before changing BATs, 'dssall' must be issued. - * We check MSR for MSR_VE and issue a 'dssall' if - * MSR_VE is set hoping that - * a) on non-altivec CPUs MSR_VE reads as zero - * b) all altivec CPUs use the same bit - * NOTE: psim doesn't implement dssall so we skip if we run on psim - */ - if ( (_read_MSR () & MSR_VE) && PPC_PSIM != get_ppc_cpu_type() ) { - /* this construct is needed because we don't know - * if this file is compiled with -maltivec. - * (I plan to add altivec support outside of - * RTEMS core and hence I'd rather not - * rely on consistent compiler flags). - */ -#define DSSALL 0x7e00066c /* dssall opcode */ - __asm__ volatile (" .long %0"::"i" (DSSALL)); -#undef DSSALL - } -} - -/* Clear I/D bats 4..7 ONLY ON 7455 etc. */ -static void -clear_hi_bats (void) -{ - do_dssall (); - CLRBAT (DBAT4); - CLRBAT (DBAT5); - CLRBAT (DBAT6); - CLRBAT (DBAT7); - CLRBAT (IBAT4); - CLRBAT (IBAT5); - CLRBAT (IBAT6); - CLRBAT (IBAT7); -} - -static int -check_bat_index (int i) -{ - unsigned long hid0; - - if (i >= 0 && i < 4) - return 0; - if (i >= 4 && i < 8) { - if ( ! ppc_cpu_has_8_bats() ) - return -1; - /* OK, we're on the right hardware; - * check if we are already enabled - */ - hid0 = _read_HID0 (); - if (HID0_7455_HIGH_BAT_EN & hid0) - return 0; - /* No; enable now */ - clear_hi_bats (); - set_hid0_sync (hid0 | HID0_7455_HIGH_BAT_EN); - return 0; - } - return -1; -} - -/* size argument check: - * - must be a power of two or zero - * - must be <= 1<<28 ( non 745x cpu ) - * - can be 1<<29..1<31 or 0xffffffff on 745x - * - size < 1<<17 means 0 - * computes and returns the block mask - * RETURNS: - * block mask on success or -1 on error - */ -static int -check_bat_size (unsigned long size) -{ - unsigned long bit; - unsigned long hid0; - - /* First of all, it must be a power of two */ - if (0 == size) - return 0; - - if (0xffffffff == size) { - bit = 32; - } else { - __asm__ volatile (" cntlzw %0, %1":"=r" (bit):"r" (size)); - bit = 31 - bit; - if (1 << bit != size) - return -1; - } - /* bit < 17 is not really legal but we aliased it to 0 in the past */ - if (bit > (11 + 17)) { - if ( ! ppc_cpu_has_8_bats() ) - return -1; - - hid0 = _read_HID0 (); - /* Let's enable the larger block size if necessary */ - if (!(HID0_7455_XBSEN & hid0)) - set_hid0_sync (hid0 | HID0_7455_XBSEN); - } - - return (1 << (bit - 17)) - 1; -} - -static int -check_overlap (int typ, unsigned long start, unsigned long size) -{ - int i; - unsigned long limit = start + size - 1; - for (i = 0; i < sizeof (bat_addrs[typ]) / sizeof (bat_addrs[typ][0]); i++) { - if (!((1 << i) & bat_in_use[typ])) - continue; /* unused bat */ - /* safe is 'limit < bat_addrs[t][i].start || start > bat_addrs[t][i].limit */ - if (limit >= bat_addrs[typ][i].start && start <= bat_addrs[typ][i].limit) - return i; - } - return -1; -} - - -/* Take no risks -- the essential parts of this routine run with - * interrupts disabled! - */ - -static int -setbat (int typ, int bat_index, unsigned long virt, unsigned long phys, - unsigned int size, int flags) -{ - unsigned long level; - unsigned int bl; - int err; - int wimgxpp; - ubat bat; - - if (check_bat_index (bat_index)) { - printk ("Invalid BAT index %d\n", bat_index); - return -1; - } - - if ((int) (bl = check_bat_size (size)) < 0) { - printk ("Invalid BAT size %u\n", size); - return -1; - } - - if (virt & (size - 1)) { - printk ("BAT effective address 0x%08lx misaligned (size is 0x%08x)\n", - virt, size); - return -1; - } - - if (phys & (size - 1)) { - printk ("BAT physical address 0x%08lx misaligned (size is 0x%08x)\n", phys, - size); - return -1; - } - - if (virt + size - 1 < virt) { - printk ("BAT range invalid: wraps around zero 0x%08lx..0x%08lx\n", virt, - virt + size - 1); - return -1; - } - - if ( TYP_I == typ && ( ( _PAGE_GUARDED | _PAGE_WRITETHRU ) & flags ) ) { - printk("IBAT must not have 'guarded' or 'writethrough' attribute\n"); - return -1; - } - -/* must protect the bat_addrs table -- since this routine is only used for board setup - * or similar special purposes we don't bother about interrupt latency too much. - */ - rtems_interrupt_disable (level); - - { /* might have to initialize our cached data */ - static char init_done = 0; - if (!init_done) { - bat_addrs_init (); - init_done = 1; - } - } - - err = check_overlap (typ, virt, size); - if ((size >= (1 << 17)) && (err >= 0) && (err != bat_index)) { - rtems_interrupt_enable (level); - printk ("BATs must not overlap; area 0x%08lx..0x%08lx hits %cBAT %i\n", - virt, virt + size, (TYP_I == typ ? 'I' : 'D'), err); - return -1; - } - - /* 603, 604, etc. */ - wimgxpp = flags & (_PAGE_WRITETHRU | _PAGE_NO_CACHE - | _PAGE_COHERENT | _PAGE_GUARDED); - wimgxpp |= (flags & _PAGE_RW) ? BPP_RW : BPP_RX; - bat.words.u = virt | (bl << 2) | 2; /* Vs=1, Vp=0 */ - bat.words.l = phys | wimgxpp; - if (flags & _PAGE_USER) - bat.bat.batu.vp = 1; - bat_addrs[typ][bat_index].start = virt; - bat_addrs[typ][bat_index].limit = virt + ((bl + 1) << 17) - 1; - bat_addrs[typ][bat_index].phys = phys; - bat_in_use[typ] |= 1 << bat_index; - if (size < (1 << 17)) { - /* size of 0 tells us to switch it off */ - bat.bat.batu.vp = 0; - bat.bat.batu.vs = 0; - bat_in_use[typ] &= ~(1 << bat_index); - /* mimic old behavior when bl was 0 (bs==0 is actually legal; it doesnt - * indicate a size of zero. We now accept bl==0 and look at the size. - */ - bat_addrs[typ][bat_index].limit = virt; - } - do_dssall (); - if ( TYP_I == typ ) { - switch (bat_index) { - case 0: asm_setibat0 (bat.words.u, bat.words.l); break; - case 1: asm_setibat1 (bat.words.u, bat.words.l); break; - case 2: asm_setibat2 (bat.words.u, bat.words.l); break; - case 3: asm_setibat3 (bat.words.u, bat.words.l); break; - /* cpu check already done in check_index */ - case 4: asm_setibat4 (bat.words.u, bat.words.l); break; - case 5: asm_setibat5 (bat.words.u, bat.words.l); break; - case 6: asm_setibat6 (bat.words.u, bat.words.l); break; - case 7: asm_setibat7 (bat.words.u, bat.words.l); break; - default: /* should never get here anyways */ - break; - } - } else { - switch (bat_index) { - case 0: asm_setdbat0 (bat.words.u, bat.words.l); break; - case 1: asm_setdbat1 (bat.words.u, bat.words.l); break; - case 2: asm_setdbat2 (bat.words.u, bat.words.l); break; - case 3: asm_setdbat3 (bat.words.u, bat.words.l); break; - /* cpu check already done in check_index */ - case 4: asm_setdbat4 (bat.words.u, bat.words.l); break; - case 5: asm_setdbat5 (bat.words.u, bat.words.l); break; - case 6: asm_setdbat6 (bat.words.u, bat.words.l); break; - case 7: asm_setdbat7 (bat.words.u, bat.words.l); break; - default: /* should never get here anyways */ - break; - } - } - rtems_interrupt_enable (level); - - return 0; -} - -static int -getbat (int typ, int idx, unsigned long *pu, unsigned long *pl) -{ - unsigned long u, l; - - if (check_bat_index (idx)) { - printk ("Invalid BAT #%i\n", idx); - return -1; - } - if ( TYP_I == typ ) { - switch (idx) { - case 0: GETBAT (IBAT0, u, l); break; - case 1: GETBAT (IBAT1, u, l); break; - case 2: GETBAT (IBAT2, u, l); break; - case 3: GETBAT (IBAT3, u, l); break; - /* cpu check already done in check_index */ - case 4: GETBAT (IBAT4, u, l); break; - case 5: GETBAT (IBAT5, u, l); break; - case 6: GETBAT (IBAT6, u, l); break; - case 7: GETBAT (IBAT7, u, l); break; - default: /* should never get here anyways */ - return -1; - } - } else { - switch (idx) { - case 0: GETBAT (DBAT0, u, l); break; - case 1: GETBAT (DBAT1, u, l); break; - case 2: GETBAT (DBAT2, u, l); break; - case 3: GETBAT (DBAT3, u, l); break; - /* cpu check already done in check_index */ - case 4: GETBAT (DBAT4, u, l); break; - case 5: GETBAT (DBAT5, u, l); break; - case 6: GETBAT (DBAT6, u, l); break; - case 7: GETBAT (DBAT7, u, l); break; - default: /* should never get here anyways */ - return -1; - } - } - if (pu) { - *pu = u; - } - if (pl) { - *pl = l; - } - - if (!pu && !pl) { - /* dump */ - ubat b; - b.words.u = u; - b.words.l = l; - printk ("Raw %cBAT %i contents; UPPER: (0x%08lx)", (TYP_I == typ ? 'I' : 'D'), idx, u); - printk (" BEPI: 0x%08x", b.bat.batu.bepi); - printk (" BL: 0x%08lx", (u >> 2) & ((1 << 15) - 1)); - printk (" VS: 0b%i", b.bat.batu.vs); - printk (" VP: 0b%i", b.bat.batu.vp); - printk ("\n"); - printk (" LOWER: (0x%08lx)", l); - printk (" RPN: 0x%08x", b.bat.batl.brpn); - printk (" wimg: 0b%1i%1i%1i%1i", b.bat.batl.w, b.bat.batl.i, - b.bat.batl.m, b.bat.batl.g); - printk (" PP: 0x%1x", b.bat.batl.pp); - printk ("\n"); - printk ("Covering EA Range: "); - if (bat_in_use[typ] & (1 << idx)) - printk ("0x%08lx .. 0x%08lx\n", bat_addrs[typ][idx].start, - bat_addrs[typ][idx].limit); - else - printk (" (BAT off)\n"); - - } - return u; -} - -int -setdbat (int bat_index, unsigned long virt, unsigned long phys, - unsigned int size, int flags) -{ - return setbat(TYP_D, bat_index, virt, phys, size, flags); -} - -int -setibat (int bat_index, unsigned long virt, unsigned long phys, - unsigned int size, int flags) -{ - return setbat(TYP_I, bat_index, virt, phys, size, flags); -} - -int -getdbat (int idx, unsigned long *pu, unsigned long *pl) -{ - return getbat (TYP_D, idx, pu, pl); -} - -int -getibat (int idx, unsigned long *pu, unsigned long *pl) -{ - return getbat (TYP_I, idx, pu, pl); -} diff --git a/c/src/lib/libcpu/powerpc/mpc6xx/mmu/mmuAsm.S b/c/src/lib/libcpu/powerpc/mpc6xx/mmu/mmuAsm.S deleted file mode 100644 index e64a5dfe89..0000000000 --- a/c/src/lib/libcpu/powerpc/mpc6xx/mmu/mmuAsm.S +++ /dev/null @@ -1,530 +0,0 @@ -/* - * mmuAsm.S - * - * Copyright (C) 1999 Eric Valette (valette@crf.canon.fr) - * - * This file contains the low-level support for various MMU - * features. - * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.org/license/LICENSE. - * - * T. Straumann - 11/2001: added support for 7400 (no AltiVec yet) - * S.K. Feng - 10/2003: added support for 7455 (no AltiVec yet) - * - */ - -#include -#include -#include -#include - -/* Unfortunately, the CPU types defined in cpu.h are - * an 'enum' type and hence not available :-( - */ -#define PPC_601 0x1 -#define PPC_603 0x3 -#define PPC_604 0x4 -#define PPC_603e 0x6 -#define PPC_603ev 0x7 -#define PPC_750 0x8 -#define PPC_604e 0x9 -#define PPC_604r 0xA -#define PPC_7400 0xC -#define PPC_7455 0x8001 -#define PPC_7457 0x8002 -#define PPC_620 0x16 -#define PPC_860 0x50 -#define PPC_821 PPC_860 -#define PPC_8260 0x81 -#define PPC_8240 PPC_8260 - -/* ALTIVEC instructions (not recognized by off-the shelf gcc yet) */ -#define DSSALL .long 0x7e00066c /* DSSALL altivec instruction opcode */ - -/* A couple of defines to make the code more readable */ -#define CACHE_LINE_SIZE 32 - -#ifndef MSSCR0 -#define MSSCR0 1014 -#endif - -#define DL1HWF (1<<(31-8)) -#define L2HWF (1<<(31-20)) - -#FIXME Should really move this to C code - - .globl L1_caches_enables - .type L1_caches_enables, @function - -L1_caches_enables: - /* - * Enable caches and 604-specific features if necessary. - */ - mfspr r9,PPC_PVR - rlwinm r9,r9,16,16,31 - cmpi 0,r9,PPC_601 - beq 4f /* not needed for 601 */ - mfspr r11,HID0 - andi. r0,r11,HID0_DCE - ori r11,r11,HID0_ICE|HID0_DCE - ori r8,r11,HID0_ICFI - bne 3f /* don't invalidate the D-cache */ - ori r8,r8,HID0_DCI /* unless it wasn't enabled */ -3: - sync - mtspr HID0,r8 /* enable and invalidate caches */ - sync - mtspr HID0,r11 /* enable caches */ - sync - isync - cmpi 1,r9,PPC_604 /* check for 604 */ - cmpi 2,r9,PPC_604e /* or 604e */ - cmpi 3,r9,PPC_604r /* or mach5 */ - cror 6,6,10 - cror 6,6,14 - cmpi 2,r9,PPC_750 /* or 750 */ - cror 6,6,10 - cmpi 2,r9,PPC_7400 /* or 7400 */ - cror 6,6,10 - cmpli 0,r9,PPC_7455 /* or 7455 */ - beq 1f - cmpli 0,r9,PPC_7457 /* or 7457 */ - bne 2f -1: - /* 7455:link register stack,branch folding & - * TBEN : enable the time base and decrementer. - * EMCP bit is defined in HID1. However, it's not used - * in mvme5500 board because of GT64260 (e.g. it's connected - * pull-up). - */ - oris r11,r11,(HID0_LRSTK|HID0_FOLD|HID0_TBEN)@h - ori r11,r11,(HID0_LRSTK|HID0_FOLD|HID0_TBEN)@l -2: cror 2,2,10 - bne 3f - ori r11,r11,HID0_BTIC /* enable branch tgt cache on 7400 , 7455 , 7457 */ -3: cror 2,2,6 - bne 4f - /* on 7400 SIED is actually SGE (store gathering enable) */ - ori r11,r11,HID0_SIED|HID0_BHTE /* for 604[e], enable */ - bne 2,5f - ori r11,r11,HID0_BTCD -5: mtspr HID0,r11 /* superscalar exec & br history tbl */ - sync /* for SGE bit */ - isync /* P2-17 to 2-22 in MPC7450UM */ -4: - blr - - .globl get_L1CR -.type get_L1CR, @function -get_L1CR: - mfspr r3,HID0 - blr - - .globl get_L2CR - .type get_L2CR, @function -get_L2CR: - /* Make sure this is a > 750 chip */ - mfspr r3,PPC_PVR - rlwinm r3,r3,16,16,31 - cmplwi r3,PPC_750 /* it's a 750 */ - beq 1f - cmplwi r3,PPC_7400 /* it's a 7400 */ - beq 1f - cmplwi r3,PPC_7455 /* it's a 7455 */ - beq 1f - cmplwi r3,PPC_7457 /* it's a 7457 */ - beq 1f - li r3,-1 - blr - -1: - /* Return the L2CR contents */ - mfspr r3,L2CR - blr - - .globl set_L2CR - .type set_L2CR, @function -set_L2CR: - /* Usage: - * When setting the L2CR register, you must do a few special things. - * If you are enabling the cache, you must perform a global invalidate. - * If you are disabling the cache, you must flush the cache contents first. - * This routine takes care of doing these things. When first - * enabling the cache, make sure you pass in the L2CR you want, as well as - * passing in the global invalidate bit set. A global invalidate will - * only be performed if the L2I bit is set in applyThis. When enabling - * the cache, you should also set the L2E bit in applyThis. If you - * want to modify the L2CR contents after the cache has been enabled, - * the recommended procedure is to first call __setL2CR(0) to disable - * the cache and then call it again with the new values for L2CR. Examples: - * - * _setL2CR(0) - disables the cache - * _setL2CR(0xb9A14000) - enables my G3 MCP750 card: - * - L2E set to turn on the cache - * - L2SIZ set to 1MB - * - L2CLK set to %2 - * - L2RAM set to pipelined syncronous late-write - * - L2I set to perform a global invalidation - * - L2OH set to 1 nS - * - * A similar call should work for your card. You need to know the correct - * setting for your card and then place them in the fields I have outlined - * above. Other fields support optional features, such as L2DO which caches - * only data, or L2TS which causes cache pushes from the L1 cache to go to - *the L2 cache instead of to main memory. - */ - - /* Make sure this is a > 750 chip */ - mfspr r0,PPC_PVR - rlwinm r0,r0,16,16,31 - cmplwi r0,PPC_750 - beq thisIs750 - cmplwi r0,PPC_7400 - beq thisIs750 - cmplwi r0,PPC_7455 - beq thisIs750 - cmplwi r0,PPC_7457 - beq thisIs750 - li r3,-1 - blr - -thisIs750: - /* Get the current enable bit of the L2CR into r4 */ - mfspr r4,L2CR - rlwinm r4,r4,0,0,0 - - /* See if we want to perform a global inval this time. */ - rlwinm r6,r3,0,10,10 /* r6 contains the new invalidate bit */ - rlwinm. r5,r3,0,0,0 /* r5 contains the new enable bit */ - rlwinm r3,r3,0,11,9 /* Turn off the invalidate bit */ - rlwinm r3,r3,0,1,31 /* Turn off the enable bit */ - or r3,r3,r4 /* Keep the enable bit the same as it was for now. */ - mfmsr r7 /* shut off interrupts around critical flush/invalidate sections */ - rlwinm r4,r7,0,17,15 /* Turn off EE bit - an external exception while we are flushing - the cache is fatal (comment this line and see!) */ - mtmsr r4 - bne dontDisableCache /* Only disable the cache if L2CRApply has the enable bit off */ - - cmplwi r0,PPC_7400 /* 7400 ? */ - bne disableCache /* use traditional method */ - - /* On the 7400, they recommend using the hardware flush feature */ - DSSALL /* stop all data streams */ - sync - /* we wouldn't have to flush L1, but for sake of consistency with the other code we do it anyway */ - mfspr r4, MSSCR0 - oris r4, r4, DL1HWF@h - mtspr MSSCR0, r4 - sync - /* L1 flushed */ - mfspr r4, L2CR - ori r4, r4, L2HWF - mtspr L2CR, r4 - sync - /* L2 flushed */ - b flushDone - -disableCache: - /* Disable the cache. First, we turn off data relocation. */ - rlwinm r4,r4,0,28,26 /* Turn off DR bit */ - cmplwi r0,PPC_7455 /* 7455 ? */ - beq 1f - cmplwi r0,PPC_7457 /* 7457 ? */ - bne not745x -1: - /* 745x:L1 Load/Flush, L2, L3 : hardware flush */ - DSSALL - mtmsr r4 - sync - isync - mfspr r4, MSSCR0 - rlwinm r4,r4,0,29,0 /* Turn off the L2PFE bits */ - mtspr MSSCR0, r4 - sync - /* flush L1 first */ - lis r4,0x0001 - mtctr r4 - li r4,0 - li r0,0 -loadFlush: - lwzx r0,r0,r4 - dcbf r0,r4 - addi r4,r4,CACHE_LINE_SIZE /* Go to start of next cache line */ - bdnz loadFlush - sync - /* Set the L2CR[L2IO & L2DO] bits to completely lock the L2 cache */ - mfspr r0, L2CR - lis r4,L2CR_LOCK_745x@h - ori r4,r4,L2CR_LOCK_745x@l - or r4,r0,r4 - rlwinm r4,r4,0,11,9 /* make sure the invalidate bit off */ - mtspr L2CR, r4 - sync - ori r4, r4, L2HWF - mtspr L2CR, r4 - sync - /* L2 flushed,L2IO & L2DO got cleared in the dontDisableCache: */ - b reenableDR - -not745x: - sync - mtmsr r4 - isync - /* - Now, read the first 2MB of memory to put new data in the cache. - (Actually we only need the size of the L2 cache plus - the size of the L1 cache, but 2MB will cover everything just to be safe). - */ - lis r4,0x0001 - mtctr r4 - li r4,0 -loadLoop: - lwzx r0,r0,r4 - addi r4,r4,CACHE_LINE_SIZE /* Go to start of next cache line */ - bdnz loadLoop - - /* Now, flush the first 2MB of memory */ - lis r4,0x0001 - mtctr r4 - li r4,0 - sync -flushLoop: - dcbf r0,r4 - addi r4,r4,CACHE_LINE_SIZE /* Go to start of next cache line */ - bdnz flushLoop -reenableDR: - rlwinm r4,r7,0,17,15 /* still mask EE but reenable data relocation */ - sync - mtmsr r4 - isync - -flushDone: - - /* Turn off the L2CR enable bit. */ - rlwinm r3,r3,0,1,31 - -dontDisableCache: - /* Set up the L2CR configuration bits */ - sync - mtspr L2CR,r3 - sync - cmplwi r6,0 - beq noInval - - /* Perform a global invalidation */ - oris r3,r3,0x0020 - sync - mtspr L2CR,r3 - sync -invalCompleteLoop: /* Wait for the invalidation to complete */ - mfspr r3,L2CR - rlwinm. r4,r3,0,31,31 - bne invalCompleteLoop - - rlwinm r3,r3,0,11,9; /* Turn off the L2I bit */ - sync - mtspr L2CR,r3 - -noInval: - sync - /* re-enable interrupts, i.e. restore original MSR */ - mtmsr r7 /* (no sync needed) */ - /* See if we need to enable the cache */ - cmplwi r5,0 - beqlr - -enableCache: - /* Enable the cache */ - oris r3,r3,0x8000 - mtspr L2CR,r3 - sync - blr - - - .globl get_L3CR - .type get_L3CR, @function -get_L3CR: - /* Make sure this is a 7455 chip */ - mfspr r3,PPC_PVR - rlwinm r3,r3,16,16,31 - cmplwi r3,PPC_7455 /* it's a 7455 */ - beq 1f - cmplwi r3,PPC_7457 /* it's a 7457 */ - beq 1f - li r3,-1 - blr - -1: - /* Return the L3CR contents */ - mfspr r3,L3CR - blr - - .globl set_L3CR - .type set_L3CR, @function -set_L3CR: - /* Usage: - * When setting the L3CR register, you must do a few special things. - * If you are enabling the cache, you must perform a global invalidate. - * Then call cpu_enable_l3cr(l3cr). - * If you are disabling the cache, you must flush the cache contents first. - * This routine takes care of doing these things. If you - * want to modify the L3CR contents after the cache has been enabled, - * the recommended procedure is to first call __setL3CR(0) to disable - * the cache and then call cpu_enable_l3cr with the new values for - * L3CR. - */ - - /* Make sure this is a 7455 chip */ - mfspr r0,PPC_PVR - rlwinm r0,r0,16,16,31 - cmplwi r0,PPC_7455 - beq thisIs7455 - cmplwi r0,PPC_7457 - beq thisIs7455 - li r3,-1 - blr - -thisIs7455: - /* Get the current enable bit of the L3CR into r4 */ - mfspr r4,L3CR - rlwinm r4,r4,0,0,0 - - /* See if we want to perform a global inval this time. */ - rlwinm r6,r3,0,10,10 /* r6 contains the new invalidate bit */ - rlwinm. r5,r3,0,0,0 /* r5 contains the new enable bit */ - rlwinm r3,r3,0,11,9 /* Turn off the invalidate bit */ - rlwinm r3,r3,0,1,31 /* Turn off the enable bit */ - or r3,r3,r4 /* Keep the enable bit the same as it was for now. */ - mfmsr r7 /* shut off interrupts around critical flush/invalidate sections */ - rlwinm r4,r7,0,17,15 /* Turn off EE bit - an external exception while we are flushing - the cache is fatal (comment this line and see!) */ - mtmsr r4 - bne dontDisableL3Cache /* Only disable the cache if L3CRApply has the enable bit off */ - /* Before the L3 is disabled, it must be flused to prevent coherency problems */ - /* First, we turn off data relocation. */ - rlwinm r4,r4,0,28,26 /* Turn off DR bit */ - DSSALL - sync - mtmsr r4 - isync /* make sure memory accesses have completed */ - /* 7455: L3 : hardware flush - * Set the L3CR[L3IO & L3DO] bits to completely lock the L3 cache */ - mfspr r0, L3CR - lis r4, L3CR_LOCK_745x@h - ori r4,r4, L3CR_LOCK_745x@l - or r4,r0,r4 - rlwinm r4,r4,0,11,9 /* make sure the invalidate bit off */ - mtspr L3CR, r4 - sync - ori r4, r4, L3CR_L3HWF - mtspr L3CR, r4 - sync - /* L3 flushed,L3IO & L3DO got cleared in the dontDisableL3Cache: */ - rlwinm r4,r7,0,17,15 /* still mask EE but reenable data relocation */ - sync - mtmsr r4 - isync - - /* Turn off the L3CR enable bit. */ - rlwinm r3,r3,0,1,31 - -dontDisableL3Cache: - /* Set up the L3CR configuration bits */ - sync - mtspr L3CR,r3 - sync -ifL3Inval: - cmplwi r6,0 - beq noL3Inval - - /* Perform a global invalidation */ - oris r3,r3,0x0020 - sync - mtspr L3CR,r3 - sync -invalCompleteL3: /* Wait for the invalidation to complete */ - mfspr r3,L3CR - rlwinm. r4,r3,0,31,31 - bne invalCompleteL3 - - rlwinm r3,r3,0,11,9; /* Turn off the L3I bit */ - sync - mtspr L3CR,r3 - sync - -noL3Inval: - /* re-enable interrupts, i.e. restore original MSR */ - mtmsr r7 /* (no sync needed) */ - /* See if we need to enable the cache */ - cmplwi r5,0 - beqlr - -enableL3Cache: - /* Enable the cache */ - oris r3,r3,0x8000 - mtspr L3CR,r3 - sync - blr - -/* - * An undocumented "feature" of 604e requires that the v bit - * be cleared before changing BAT values. - * - * Also, newer IBM firmware does not clear bat3 and 4 so - * this makes sure it's done. - * -- Cort - */ - .globl CPU_clear_bats_early - .type CPU_clear_bats_early,@function -CPU_clear_bats_early: - li r3,0 - mfspr r4,PPC_PVR - rlwinm r4,r4,16,16,31 /* r4 = 1 for 601, 4 for 604 */ - cmpwi r4, 1 - sync - isync - beq 1f - cmplwi r4,0x8001 /* 7445, 7455 (0x8001), 7447, 7457 (0x8002) */ - blt 2f /* 7447a (0x8003) and 7448 (0x8004) have 16 bats */ - cmplwi r4,0x8004 - bgt 2f - mtspr DBAT4U,r3 - mtspr DBAT4L,r3 - mtspr DBAT5U,r3 - mtspr DBAT5L,r3 - mtspr DBAT6U,r3 - mtspr DBAT6L,r3 - mtspr DBAT7U,r3 - mtspr DBAT7L,r3 - mtspr IBAT4U,r3 - mtspr IBAT4L,r3 - mtspr IBAT5U,r3 - mtspr IBAT5L,r3 - mtspr IBAT6U,r3 - mtspr IBAT6L,r3 - mtspr IBAT7U,r3 - mtspr IBAT7L,r3 -2: - mtspr DBAT0U,r3 - mtspr DBAT0L,r3 - mtspr DBAT1U,r3 - mtspr DBAT1L,r3 - mtspr DBAT2U,r3 - mtspr DBAT2L,r3 - mtspr DBAT3U,r3 - mtspr DBAT3L,r3 -1: - mtspr IBAT0U,r3 - mtspr IBAT0L,r3 - mtspr IBAT1U,r3 - mtspr IBAT1L,r3 - mtspr IBAT2U,r3 - mtspr IBAT2L,r3 - mtspr IBAT3U,r3 - mtspr IBAT3L,r3 - sync - isync - blr - diff --git a/c/src/lib/libcpu/powerpc/mpc6xx/mmu/pte121.c b/c/src/lib/libcpu/powerpc/mpc6xx/mmu/pte121.c deleted file mode 100644 index 93ef909776..0000000000 --- a/c/src/lib/libcpu/powerpc/mpc6xx/mmu/pte121.c +++ /dev/null @@ -1,1139 +0,0 @@ -/* - * Trivial page table setup for RTEMS - * Purpose: allow write protection of text/RO-data - */ - -/* - * Authorship - * ---------- - * This software was created by - * Till Straumann , 4/2002, 2003, 2004, - * Stanford Linear Accelerator Center, Stanford University. - * - * Acknowledgement of sponsorship - * ------------------------------ - * This software was produced by - * the Stanford Linear Accelerator Center, Stanford University, - * under Contract DE-AC03-76SFO0515 with the Department of Energy. - * - * Government disclaimer of liability - * ---------------------------------- - * Neither the United States nor the United States Department of Energy, - * nor any of their employees, makes any warranty, express or implied, or - * assumes any legal liability or responsibility for the accuracy, - * completeness, or usefulness of any data, apparatus, product, or process - * disclosed, or represents that its use would not infringe privately owned - * rights. - * - * Stanford disclaimer of liability - * -------------------------------- - * Stanford University makes no representations or warranties, express or - * implied, nor assumes any liability for the use of this software. - * - * Stanford disclaimer of copyright - * -------------------------------- - * Stanford University, owner of the copyright, hereby disclaims its - * copyright and all other rights in this software. Hence, anyone may - * freely use it for any purpose without restriction. - * - * Maintenance of notices - * ---------------------- - * In the interest of clarity regarding the origin and status of this - * SLAC software, this and all the preceding Stanford University notices - * are to remain affixed to any copy or derivative of this software made - * or distributed by the recipient and are to be affixed to any copy of - * software made or distributed by the recipient that contains a copy or - * derivative of this software. - * - * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03 - */ - -/* Chose debugging options */ -#undef DEBUG_MAIN /* create a standalone (host) program for basic testing */ -#undef DEBUG /* target debugging and consistency checking */ -#undef DEBUG_EXC /* add exception handler which reenables BAT0 and recovers from a page fault */ - -#ifdef DEBUG_MAIN -#undef DEBUG /* must not use these together with DEBUG_MAIN */ -#undef DEBUG_EXC -#endif - -/***************************** INCLUDE HEADERS ****************************/ - -#ifndef DEBUG_MAIN -#include -#include -#include -#include -#include -#ifdef DEBUG_EXC -#include -#include -#endif -#endif - -#include -#include -#include - -#include - -/************************** CONSTANT DEFINITIONS **************************/ - -/* Base 2 logs of some sizes */ - -#ifndef DEBUG_MAIN - -#define LD_PHYS_SIZE 32 /* physical address space */ -#define LD_PG_SIZE 12 /* page size */ -#define LD_PTEG_SIZE 6 /* PTEG size */ -#define LD_PTE_SIZE 3 /* PTE size */ -#define LD_SEG_SIZE 28 /* segment size */ -#define LD_MIN_PT_SIZE 16 /* minimal size of a page table */ -#define LD_HASH_SIZE 19 /* lengh of a hash */ -#define LD_VSID_SIZE 24 /* vsid bits in seg. register */ - -#else /* DEBUG_MAIN */ - -/* Reduced 'fantasy' sizes for testing */ -#define LD_PHYS_SIZE 32 /* physical address space */ -#define LD_PG_SIZE 6 /* page size */ -#define LD_PTEG_SIZE 5 /* PTEG size */ -#define LD_PTE_SIZE 3 /* PTE size */ -#define LD_SEG_SIZE 28 /* segment size */ -#define LD_MIN_PT_SIZE 7 /* minimal size of a page table */ -#define LD_HASH_SIZE 19 /* lengh of a hash */ - -#endif /* DEBUG_MAIN */ - -/* Derived sizes */ - -/* Size of a page index */ -#define LD_PI_SIZE ((LD_SEG_SIZE) - (LD_PG_SIZE)) - -/* Number of PTEs in a PTEG */ -#define PTE_PER_PTEG (1<<((LD_PTEG_SIZE)-(LD_PTE_SIZE))) - -/* Segment register bits */ -#define KEY_SUP (1<<30) /* supervisor mode key */ -#define KEY_USR (1<<29) /* user mode key */ - -/* The range of effective addresses to scan with 'tlbie' - * instructions in order to flush all TLBs. - * On the 750 and 7400, there are 128 two way I and D TLBs, - * indexed by EA[14:19]. Hence calling - * tlbie rx - * where rx scans 0x00000, 0x01000, 0x02000, ... 0x3f000 - * is sufficient to do the job - */ -#define NUM_TLB_PER_WAY 64 /* 750 and 7400 have 128 two way TLBs */ -#define FLUSH_EA_RANGE (NUM_TLB_PER_WAY<>LD_SEG_SIZE) & ((1<<(LD_PHYS_SIZE-LD_SEG_SIZE))-1)) -/* page index of an EA */ -#define PI121(ea) (((ea)>>LD_PG_SIZE) & ((1< 6bit API]) - */ -#define API(pi) ((pi)>>((LD_MIN_PT_SIZE)-(LD_PTEG_SIZE))) - - -/* Horrible Macros */ -#ifdef __rtems__ -/* must not use printf until multitasking is up */ -typedef int (*PrintF) (const char *, ...); -static PrintF -whatPrintf (void) -{ - return _Thread_Executing ? printf : printk; -} - -#define PRINTF(args...) ((void)(whatPrintf())(args)) -#else -#define PRINTF(args...) printf(args) -#endif - -#ifdef DEBUG -static unsigned long triv121PgTblConsistency( - Triv121PgTbl pt, int pass, int expect); - -static int consistencyPass = 0; -#define CONSCHECK(expect) triv121PgTblConsistency(&pgTbl,consistencyPass++,(expect)) -#else -#define CONSCHECK(expect) do {} while (0) -#endif - -/**************************** TYPE DEFINITIONS ****************************/ - -/* internal description of a trivial page table */ -typedef struct Triv121PgTblRec_ -{ - APte base; - unsigned long size; - int active; -} Triv121PgTblRec; - - -/************************** FORWARD DECLARATIONS *************************/ - -#ifdef DEBUG_EXC -static void myhdl (BSP_Exception_frame * excPtr); -#endif - -static void dumpPte (APte pte); - -#ifdef DEBUG -static void -dumpPteg (unsigned long vsid, unsigned long pi, unsigned long hash); -#endif - -unsigned long -triv121IsRangeMapped (long vsid, unsigned long start, unsigned long end); - -static void do_dssall (void); - -/**************************** STATIC VARIABLES ****************************/ - -/* dont malloc - we might have to use this before - * we have malloc or even RTEMS workspace available - */ -static Triv121PgTblRec pgTbl = { 0 }; - -#ifdef DEBUG_EXC -static void *ohdl; /* keep a pointer to the original handler */ -#endif - -/*********************** INLINES & PRIVATE ROUTINES ***********************/ - -/* compute the page table entry group (PTEG) of a hash */ -static inline APte -ptegOf (Triv121PgTbl pt, unsigned long hash) -{ - hash &= ((1 << LD_HASH_SIZE) - 1); - return (APte) (((unsigned long) pt-> - base) | ((hash << LD_PTEG_SIZE) & (pt->size - 1))); -} - -/* see if a vsid/pi combination is already mapped - * - * RETURNS: PTE of mapping / NULL if none exists - * - * NOTE: a vsid<0 is legal and will tell this - * routine that 'pi' is actually an EA to - * be split into vsid and pi... - */ -static APte -alreadyMapped (Triv121PgTbl pt, long vsid, unsigned long pi) -{ - int i; - unsigned long hash, api; - APte pte; - - if (!pt->size) - return 0; - - if (TRIV121_121_VSID == vsid) { - vsid = VSID121 (pi); - pi = PI121 (pi); - } else if (TRIV121_SEG_VSID == vsid) { - vsid = seg2vsid (pi); - pi = PI121 (pi); - } - - hash = PTE_HASH1 (vsid, pi); - api = API (pi); - for (i = 0, pte = ptegOf (pt, hash); i < PTE_PER_PTEG; i++, pte++) - if (pte->v && pte->vsid == vsid && pte->api == api && 0 == pte->h) - return pte; - /* try the secondary hash table */ - hash = PTE_HASH2 (hash); - for (i = 0, pte = ptegOf (pt, hash); i < PTE_PER_PTEG; i++, pte++) - if (pte->v && pte->vsid == vsid && pte->api == api && 1 == pte->h) - return pte; - return 0; -} - -/* find the first available slot for vsid/pi - * - * NOTE: it is NOT legal to pass a vsid<0 / EA combination. - * - * RETURNS free slot with the 'marked' field set. The 'h' - * field is set to 0 or one, depending on whether - * the slot was allocated by using the primary or - * the secondary hash, respectively. - */ -static APte -slotFor (Triv121PgTbl pt, unsigned long vsid, unsigned long pi) -{ - int i; - unsigned long hash; - APte pte; - - /* primary hash */ - hash = PTE_HASH1 (vsid, pi); - /* linear search thru all buckets for this hash */ - for (i = 0, pte = ptegOf (pt, hash); i < PTE_PER_PTEG; i++, pte++) { - if (!pte->v && !pte->marked) { - /* found a free PTE; mark it as potentially used and return */ - pte->h = 0; /* found by the primary hash fn */ - pte->marked = 1; - return pte; - } - } - -#ifdef DEBUG - /* Strange: if the hash table was allocated big enough, - * this should not happen (when using a 1:1 mapping) - * Give them some information... - */ - PRINTF ("## First hash bucket full - "); - dumpPteg (vsid, pi, hash); -#endif - - hash = PTE_HASH2 (hash); -#ifdef DEBUG - PRINTF (" Secondary pteg is 0x%08x\n", (unsigned) ptegOf (pt, hash)); -#endif - for (i = 0, pte = ptegOf (pt, hash); i < PTE_PER_PTEG; i++, pte++) { - if (!pte->v && !pte->marked) { - /* mark this pte as potentially used */ - pte->marked = 1; - pte->h = 1; - return pte; - } - } -#ifdef DEBUG - /* Even more strange - most likely, something is REALLY messed up */ - PRINTF ("## Second hash bucket full - "); - dumpPteg (vsid, pi, hash); -#endif - return 0; -} - -/* unmark all entries */ -static void -unmarkAll (Triv121PgTbl pt) -{ - unsigned long n = pt->size / sizeof (PTERec); - unsigned long i; - APte pte; - for (i = 0, pte = pt->base; i < n; i++, pte++) - pte->marked = 0; - -} - -/* calculate the minimal size of a page/hash table - * to map a range of 'size' bytes in EA space. - * - * RETURNS: size in 'number of bits', i.e. the - * integer part of LOGbase2(minsize) - * is returned. - * NOTE: G3/G4 machines need at least 16 bits - * (64k). - */ -unsigned long -triv121PgTblLdMinSize (unsigned long size) -{ - unsigned long i; - /* round 'size' up to the next page boundary */ - size += (1 << LD_PG_SIZE) - 1; - size &= ~((1 << LD_PG_SIZE) - 1); - /* divide by number of PTEs and multiply - * by the size of a PTE. - */ - size >>= LD_PG_SIZE - LD_PTE_SIZE; - /* find the next power of 2 >= size */ - for (i = 0; i < LD_PHYS_SIZE; i++) { - if ((1 << i) >= size) - break; - } - /* pop up to the allowed minimum, if necessary */ - if (i < LD_MIN_PT_SIZE) - i = LD_MIN_PT_SIZE; - return i; -} - -/* initialize a trivial page table of 2^ldSize bytes - * at 'base' in memory. - * - * RETURNS: OPAQUE HANDLE (not the hash table address) - * or NULL on failure. - */ -Triv121PgTbl -triv121PgTblInit (unsigned long base, unsigned ldSize) -{ - if (pgTbl.size) { - /* already initialized */ - return 0; - } - - if (ldSize < LD_MIN_PT_SIZE) - return 0; /* too small */ - - if (base & ((1 << ldSize) - 1)) - return 0; /* misaligned */ - - /* This was tested on 604r, 750 and 7400. - * On other CPUs, verify that the TLB invalidation works - * for a new CPU variant and that it has hardware PTE lookup/ - * TLB replacement before adding it to this list. - * - * NOTE: The 603 features no hardware PTE lookup - and - * hence the page tables should NOT be used. - * Although lookup could be implemented in - * software this is probably not desirable - * as it could have an impact on hard realtime - * performance, screwing deterministic latency! - * (Could still be useful for debugging, though) - */ - if ( ! ppc_cpu_has_hw_ptbl_lkup() ) - return 0; /* unsupported by this CPU */ - - pgTbl.base = (APte) base; - pgTbl.size = 1 << ldSize; - /* clear all page table entries */ - memset (pgTbl.base, 0, pgTbl.size); - - CONSCHECK (0); - - /* map the page table itself 'm' and 'readonly' */ - if (triv121PgTblMap (&pgTbl, - TRIV121_121_VSID, - base, - (pgTbl.size >> LD_PG_SIZE), - TRIV121_ATTR_M, TRIV121_PP_RO_PAGE) >= 0) - return 0; - - CONSCHECK ((pgTbl.size >> LD_PG_SIZE)); - - return &pgTbl; -} - -/* return the handle of the (one and only) page table - * or NULL if none has been initialized yet. - */ -Triv121PgTbl -triv121PgTblGet (void) -{ - return pgTbl.size ? &pgTbl : 0; -} - -/* NOTE: this routine returns -1 on success; - * on failure, the page table index for - * which no PTE could be allocated is returned - * - * (Consult header about argument/return value - * description) - */ -long -triv121PgTblMap (Triv121PgTbl pt, - long ovsid, - unsigned long start, - unsigned long numPages, - unsigned attributes, unsigned protection) -{ - int i, pass; - unsigned long pi; - APte pte; - long vsid; -#ifdef DEBUG - long saved_vsid = ovsid; -#endif - - if (TRIV121_121_VSID == ovsid) { - /* use 1:1 mapping */ - ovsid = VSID121 (start); - } else if (TRIV121_SEG_VSID == ovsid) { - ovsid = seg2vsid (start); - } - -#ifdef DEBUG - PRINTF ("Mapping %i (0x%x) pages at 0x%08x for VSID 0x%08x\n", - (unsigned) numPages, (unsigned) numPages, - (unsigned) start, (unsigned) ovsid); -#endif - - /* map in two passes. During the first pass, we try - * to claim entries as needed. The 'slotFor()' routine - * will 'mark' the claimed entries without 'valid'ating - * them. - * If the mapping fails, all claimed entries are unmarked - * and we return the PI for which allocation failed. - * - * Once we know that the allocation would succeed, we - * do a second pass; during the second pass, the PTE - * is actually written. - * - */ - for (pass = 0; pass < 2; pass++) { - /* check if we would succeed during the first pass */ - for (i = 0, pi = PI121 (start), vsid = ovsid; i < numPages; i++, pi++) { - if (pi >= 1 << LD_PI_SIZE) { - vsid++; - pi = 0; - } - /* leave alone existing mappings for this EA */ - if (!alreadyMapped (pt, vsid, pi)) { - if (!(pte = slotFor (pt, vsid, pi))) { - /* no free slot found for page index 'pi' */ - unmarkAll (pt); - return pi; - } else { - /* have a free slot; marked by slotFor() */ - if (pass) { - /* second pass; do the real work */ - pte->vsid = vsid; - /* H was set by slotFor() */ - pte->api = API (pi); - /* set up 1:1 mapping */ - pte->rpn = - ((((unsigned long) vsid) & - ((1 << (LD_PHYS_SIZE - LD_SEG_SIZE)) - - 1)) << LD_PI_SIZE) | pi; - pte->wimg = attributes & 0xf; - pte->pp = protection & 0x3; - /* mark it valid */ - pte->marked = 0; - if (pt->active) { - uint32_t flags; - rtems_interrupt_disable (flags); - /* order setting 'v' after writing everything else */ - __asm__ volatile ("eieio":::"memory"); - pte->v = 1; - __asm__ volatile ("sync":::"memory"); - rtems_interrupt_enable (flags); - } else { - pte->v = 1; - } - -#ifdef DEBUG - /* add paranoia */ - assert (alreadyMapped (pt, vsid, pi) == pte); -#endif - } - } - } - } - unmarkAll (pt); - } -#ifdef DEBUG - { - unsigned long failedat; - CONSCHECK (-1); - /* double check that the requested range is mapped */ - failedat = - triv121IsRangeMapped (saved_vsid, start, - start + (1 << LD_PG_SIZE) * numPages); - if (0x0C0C != failedat) { - PRINTF ("triv121 mapping failed at 0x%08x\n", (unsigned) failedat); - return PI121 (failedat); - } - } -#endif - return TRIV121_MAP_SUCCESS; /* -1 !! */ -} - -unsigned long -triv121PgTblSDR1 (Triv121PgTbl pt) -{ - return (((unsigned long) pt->base) & ~((1 << LD_MIN_PT_SIZE) - 1)) | - (((pt->size - 1) >> LD_MIN_PT_SIZE) & - ((1 << (LD_HASH_SIZE - (LD_MIN_PT_SIZE - LD_PTEG_SIZE))) - 1) - ); -} - -void -triv121PgTblActivate (Triv121PgTbl pt) -{ -#ifndef DEBUG_MAIN - unsigned long sdr1 = triv121PgTblSDR1 (pt); - register unsigned long tmp0 = 16; /* initial counter value (#segment regs) */ - register unsigned long tmp1 = (KEY_USR | KEY_SUP); - register unsigned long tmp2 = (MSR_EE | MSR_IR | MSR_DR); -#endif - pt->active = 1; - -#ifndef DEBUG_MAIN -#ifdef DEBUG_EXC - /* install our exception handler */ - ohdl = globalExceptHdl; - globalExceptHdl = myhdl; - __asm__ __volatile__ ("sync"::"memory"); -#endif - - /* This section of assembly code takes care of the - * following: - * - get MSR and switch interrupts + MMU off - * - * - load up the segment registers with a - * 1:1 effective <-> virtual mapping; - * give user & supervisor keys - * - * - flush all TLBs; - * NOTE: the TLB flushing code is probably - * CPU dependent! - * - * - setup SDR1 - * - * - restore original MSR - */ - __asm__ __volatile ( - " mtctr %[tmp0]\n" - /* Get MSR and switch interrupts off - just in case. - * Also switch the MMU off; the book - * says that SDR1 must not be changed with either - * MSR_IR or MSR_DR set. I would guess that it could - * be safe as long as the IBAT & DBAT mappings override - * the page table... - */ - " mfmsr %[tmp0]\n" - " andc %[tmp2], %[tmp0], %[tmp2]\n" - " mtmsr %[tmp2]\n" - " isync \n" - /* set up the segment registers */ - " li %[tmp2], 0\n" - "1: mtsrin %[tmp1], %[tmp2]\n" - " addis %[tmp2], %[tmp2], 0x1000\n" /* address next SR */ - " addi %[tmp1], %[tmp1], 1\n" /* increment VSID */ - " bdnz 1b\n" - /* Now flush all TLBs, starting with the topmost index */ - " lis %[tmp2], %[ea_range]@h\n" - "2: addic. %[tmp2], %[tmp2], -%[pg_sz]\n" /* address the next one (decrementing) */ - " tlbie %[tmp2]\n" /* invalidate & repeat */ - " bgt 2b\n" - " eieio \n" - " tlbsync \n" - " sync \n" - /* set up SDR1 */ - " mtspr %[sdr1], %[sdr1val]\n" - /* restore original MSR */ - " mtmsr %[tmp0]\n" - " isync \n" - :[tmp0]"+r&"(tmp0), [tmp1]"+b&"(tmp1), [tmp2]"+b&"(tmp2) - :[ea_range]"i"(FLUSH_EA_RANGE), [pg_sz]"i" (1 << LD_PG_SIZE), - [sdr1]"i"(SDR1), [sdr1val]"r" (sdr1) - :"ctr", "cc", "memory" - ); - - /* At this point, BAT0 is probably still active; it's the - * caller's job to deactivate it... - */ -#endif -} - -/************************** DEBUGGING ROUTINES *************************/ - -/* Exception handler to catch page faults */ -#ifdef DEBUG_EXC - -#define BAT_VALID_BOTH 3 /* allow user + super access */ - -static void -myhdl (BSP_Exception_frame * excPtr) -{ - if (3 == excPtr->_EXC_number) { - unsigned long dsisr; - - /* reactivate DBAT0 and read DSISR */ - __asm__ __volatile__ ( - "mfspr %0, %1 \n" - "ori %0, %0, 3\n" - "mtspr %1, %0 \n" - "sync\n" - "mfspr %0, %2\n" - :"=&r" (dsisr) - :"i" (DBAT0U), "i" (DSISR), "i" (BAT_VALID_BOTH) - ); - - printk ("Data Access Exception (DSI) # 3\n"); - printk ("Reactivated DBAT0 mapping\n"); - - - printk ("DSISR 0x%08x\n", dsisr); - - printk ("revectoring to prevent default handler panic().\n"); - printk ("NOTE: exception number %i below is BOGUS\n", ASM_DEC_VECTOR); - /* make this exception 'recoverable' for - * the default handler by faking a decrementer - * exception. - * Note that the default handler's message will be - * wrong about the exception number. - */ - excPtr->_EXC_number = ASM_DEC_VECTOR; - } -/* now call the original handler */ - ((void (*)()) ohdl) (excPtr); -} -#endif - - - -#ifdef DEBUG -/* test the consistency of the page table - * - * 'pass' is merely a number which will be printed - * by this routine, so the caller may give some - * context information. - * - * 'expected' is the number of valid (plus 'marked') - * entries the caller believes the page table should - * have. This routine complains if its count differs. - * - * It basically verifies that the topmost 20bits - * of all VSIDs as well as the unused bits are all - * zero. Then it counts all valid and all 'marked' - * entries, adding them up and comparing them to the - * 'expected' number of occupied slots. - * - * RETURNS: total number of valid plus 'marked' slots. - */ -static unsigned long -triv121PgTblConsistency (Triv121PgTbl pt, int pass, int expected) -{ - APte pte; - int i; - unsigned v, m; - int warn = 0; - int errs = 0; - static int maxw = 20; /* mute after detecting this many errors */ - - PRINTF ("Checking page table at 0x%08x (size %i==0x%x)\n", - (unsigned) pt->base, (unsigned) pt->size, (unsigned) pt->size); - - if (!pt->base || !pt->size) { - PRINTF ("Uninitialized Page Table!\n"); - return 0; - } - - v = m = 0; -#if 1 - /* 10/9/2002: I had machine checks crashing after this loop - * terminated. Maybe caused by speculative loads - * from beyond the valid memory area (since the - * page hash table sits at the top of physical - * memory). - * Very bizarre - the other loops in this file - * seem to be fine. Maybe there is a compiler bug?? - * For the moment, I let the loop run backwards... - * - * Also see the comment a couple of lines down. - */ - for (i = pt->size / sizeof (PTERec) - 1, pte = pt->base + i; i >= 0; - i--, pte--) -#else - for (i = 0, pte = pt->base; i < pt->size / sizeof (PTERec); i++, pte++) -#endif - { - int err = 0; - char buf[500]; - unsigned long *lp = (unsigned long *) pte; -#if 0 - /* If I put this bogus while statement here (the body is - * never reached), the original loop works OK - */ - while (pte >= pt->base + pt->size / sizeof (PTERec)) - /* never reached */ ; -#endif - - if ( /* T.S: allow any VSID... (*lp & (0xfffff0 << 7)) || */ (*(lp + 1) & 0xe00) - || (pte->v && pte->marked)) { - /* check for vsid (without segment bits) == 0, unused bits == 0, valid && marked */ - sprintf (buf, "unused bits or v && m"); - err = 1; - } else { - if ( (*lp & (0xfffff0 << 7)) ) { - sprintf(buf,"(warning) non-1:1 VSID found"); - err = 2; - } - if (pte->v) - v++; - if (pte->marked) - m++; - } - if (err && maxw) { - PRINTF - ("Pass %i -- strange PTE at 0x%08x found for page index %i == 0x%08x:\n", - pass, (unsigned) pte, i, i); - PRINTF ("Reason: %s\n", buf); - dumpPte (pte); - if ( err & 2 ) { - warn++; - } else { - errs++; - } - maxw--; - } - } - if (errs) { - PRINTF ("%i errors %s", errs, warn ? "and ":""); - } - if (warn) { - PRINTF ("%i warnings ",warn); - } - if (errs || warn) { - PRINTF ("found; currently %i entries marked, %i are valid\n", - m, v); - } - v += m; - if (maxw && expected >= 0 && expected != v) { - /* number of occupied slots not what they expected */ - PRINTF ("Wrong # of occupied slots detected during pass"); - PRINTF ("%i; should be %i (0x%x) is %i (0x%x)\n", - pass, expected, (unsigned) expected, v, (unsigned) v); - maxw--; - } - return v; -} -#endif - -/* Find the PTE for a EA and print its contents - * RETURNS: pte for EA or NULL if no entry was found. - */ -APte -triv121DumpEa (unsigned long ea) -{ - APte pte; - - pte = - alreadyMapped (&pgTbl, pgTbl.active ? TRIV121_SEG_VSID : TRIV121_121_VSID, - ea); - - if (pte) - dumpPte (pte); - return pte; -} - -APte -triv121FindPte (unsigned long vsid, unsigned long pi) -{ - return alreadyMapped (&pgTbl, vsid, pi); -} - -APte -triv121UnmapEa (unsigned long ea) -{ - uint32_t flags; - APte pte; - - if (!pgTbl.active) { - pte = alreadyMapped (&pgTbl, TRIV121_121_VSID, ea); - if (pte) /* alreadyMapped checks for pte->v */ - pte->v = 0; - return pte; - } - - pte = alreadyMapped (&pgTbl, TRIV121_SEG_VSID, ea); - - if (!pte) - return 0; - - rtems_interrupt_disable (flags); - pte->v = 0; - do_dssall (); - __asm__ volatile (" sync \n\t" - " tlbie %0 \n\t" - " eieio \n\t" - " tlbsync \n\t" - " sync \n\t"::"r" (ea):"memory"); - rtems_interrupt_enable (flags); - return pte; -} - -/* A context synchronizing jump */ -#define SYNC_LONGJMP(msr) \ - asm volatile( \ - " mtsrr1 %0 \n\t" \ - " bl 1f \n\t" \ - "1: mflr 3 \n\t" \ - " addi 3,3,1f-1b \n\t" \ - " mtsrr0 3 \n\t" \ - " rfi \n\t" \ - "1: \n\t" \ - : \ - :"r"(msr) \ - :"3","lr","memory") - -/* The book doesn't mention dssall when changing PTEs - * but they require it for BAT changes and I guess - * it makes sense in the case of PTEs as well. - * Just do it to be on the safe side... - */ -static void -do_dssall (void) -{ - /* Before changing BATs, 'dssall' must be issued. - * We check MSR for MSR_VE and issue a 'dssall' if - * MSR_VE is set hoping that - * a) on non-altivec CPUs MSR_VE reads as zero - * b) all altivec CPUs use the same bit - * - * NOTE: psim doesn't implement dssall so we skip if we run on psim - */ - if ( (_read_MSR () & MSR_VE) && PPC_PSIM != get_ppc_cpu_type() ) { - /* this construct is needed because we don't know - * if this file is compiled with -maltivec. - * (I plan to add altivec support outside of - * RTEMS core and hence I'd rather not - * rely on consistent compiler flags). - */ -#define DSSALL 0x7e00066c /* dssall opcode */ - __asm__ volatile (" .long %0"::"i" (DSSALL)); -#undef DSSALL - } -} - -APte -triv121ChangeEaAttributes (unsigned long ea, int wimg, int pp) -{ - APte pte; - unsigned long msr; - - if (!pgTbl.active) { - pte = alreadyMapped (&pgTbl, TRIV121_121_VSID, ea); - if (!pte) - return 0; - if (wimg > 0) - pte->wimg = wimg; - if (pp > 0) - pte->pp = pp; - return pte; - } - - pte = alreadyMapped (&pgTbl, TRIV121_SEG_VSID, ea); - - if (!pte) - return 0; - - if (wimg < 0 && pp < 0) - return pte; - - __asm__ volatile ("mfmsr %0":"=r" (msr)); - - /* switch MMU and IRQs off */ - SYNC_LONGJMP (msr & ~(MSR_EE | MSR_DR | MSR_IR)); - - pte->v = 0; - do_dssall (); - __asm__ volatile ("sync":::"memory"); - if (wimg >= 0) - pte->wimg = wimg; - if (pp >= 0) - pte->pp = pp; - __asm__ volatile ("tlbie %0; eieio"::"r" (ea):"memory"); - pte->v = 1; - __asm__ volatile ("tlbsync; sync":::"memory"); - - /* restore, i.e., switch MMU and IRQs back on */ - SYNC_LONGJMP (msr); - - return pte; -} - -static void -pgtblChangePP (Triv121PgTbl pt, int pp) -{ - unsigned long n = pt->size >> LD_PG_SIZE; - unsigned long b, i; - - for (i = 0, b = (unsigned long) pt->base; i < n; - i++, b += (1 << LD_PG_SIZE)) { - triv121ChangeEaAttributes (b, -1, pp); - } -} - -void -triv121MakePgTblRW () -{ - pgtblChangePP (&pgTbl, TRIV121_PP_RW_PAGE); -} - -void -triv121MakePgTblRO () -{ - pgtblChangePP (&pgTbl, TRIV121_PP_RO_PAGE); -} - -long -triv121DumpPte (APte pte) -{ - if (pte) - dumpPte (pte); - return 0; -} - - -#ifdef DEBUG -/* Dump an entire PTEG */ - -static void -dumpPteg (unsigned long vsid, unsigned long pi, unsigned long hash) -{ - APte pte = ptegOf (&pgTbl, hash); - int i; - PRINTF ("hash 0x%08x, pteg 0x%08x (vsid 0x%08x, pi 0x%08x)\n", - (unsigned) hash, (unsigned) pte, (unsigned) vsid, (unsigned) pi); - for (i = 0; i < PTE_PER_PTEG; i++, pte++) { - PRINTF ("pte 0x%08x is 0x%08x : 0x%08x\n", - (unsigned) pte, - (unsigned) *(unsigned long *) pte, - (unsigned) *(((unsigned long *) pte) + 1)); - } -} -#endif - -/* Verify that a range of addresses is mapped the page table. - * start/end are segment offsets or EAs (if vsid has one of - * the special values), respectively. - * - * RETURNS: address of the first page for which no - * PTE was found (i.e. page index * page size) - * - * ON SUCCESS, the special value 0x0C0C ("OKOK") - * [which is not page aligned and hence is not - * a valid page address]. - */ - -unsigned long -triv121IsRangeMapped (long vsid, unsigned long start, unsigned long end) -{ -unsigned pi; - - start &= ~((1 << LD_PG_SIZE) - 1); - while (start < end) { - if ( TRIV121_SEG_VSID != vsid && TRIV121_121_VSID != vsid ) - pi = PI121(start); - else - pi = start; - if (!alreadyMapped (&pgTbl, vsid, pi)) - return start; - start += 1 << LD_PG_SIZE; - } - return 0x0C0C; /* OKOK - not on a page boundary */ -} - - -#include - -/* print a PTE */ -static void -dumpPte (APte pte) -{ - if (0 == ((unsigned long) pte & ((1 << LD_PTEG_SIZE) - 1))) - PRINTF ("PTEG--"); - else - PRINTF ("......"); - if (pte->v) { - PRINTF ("VSID: 0x%08x H:%1i API: 0x%02x\n", pte->vsid, pte->h, pte->api); - PRINTF (" "); - PRINTF ("RPN: 0x%08x WIMG: 0x%1x, (m %1i), pp: 0x%1x\n", - pte->rpn, pte->wimg, pte->marked, pte->pp); - } else { - PRINTF ("xxxxxx\n"); - PRINTF (" "); - PRINTF ("xxxxxx\n"); - } -} - - -#if defined(DEBUG_MAIN) -/* dump page table entries from index 'from' to 'to' - * The special values (unsigned)-1 are allowed which - * cause the routine to dump the entire table. - * - * RETURNS 0 - */ -int -triv121PgTblDump (Triv121PgTbl pt, unsigned from, unsigned to) -{ - int i; - APte pte; - PRINTF ("Dumping PT [size 0x%08x == %i] at 0x%08x\n", - (unsigned) pt->size, (unsigned) pt->size, (unsigned) pt->base); - if (from > pt->size >> LD_PTE_SIZE) - from = 0; - if (to > pt->size >> LD_PTE_SIZE) - to = (pt->size >> LD_PTE_SIZE); - for (i = from, pte = pt->base + from; i < (long) to; i++, pte++) { - dumpPte (pte); - } - return 0; -} - - - -#define LD_DBG_PT_SIZE LD_MIN_PT_SIZE - -int -main (int argc, char **argv) -{ - unsigned long base, start, numPages; - unsigned long size = 1 << LD_DBG_PT_SIZE; - Triv121PgTbl pt; - - base = (unsigned long) malloc (size << 1); - - assert (base); - - /* align pt */ - base += size - 1; - base &= ~(size - 1); - - assert (pt = triv121PgTblInit (base, LD_DBG_PT_SIZE)); - - triv121PgTblDump (pt, (unsigned) -1, (unsigned) -1); - do { - do { - PRINTF ("Start Address:"); - fflush (stdout); - } while (1 != scanf ("%i", &start)); - do { - PRINTF ("# pages:"); - fflush (stdout); - } while (1 != scanf ("%i", &numPages)); - } while (TRIV121_MAP_SUCCESS == - triv121PgTblMap (pt, TRIV121_121_VSID, start, numPages, - TRIV121_ATTR_IO_PAGE, 2) - && 0 == triv121PgTblDump (pt, (unsigned) -1, (unsigned) -1)); -} -#endif -- cgit v1.2.3