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/mpc6xx/mmu/pte121.c | 1139 -------------------------- 1 file changed, 1139 deletions(-) delete mode 100644 c/src/lib/libcpu/powerpc/mpc6xx/mmu/pte121.c (limited to 'c/src/lib/libcpu/powerpc/mpc6xx/mmu/pte121.c') 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