Changeset 1b1b43cc in rtems


Ignore:
Timestamp:
Nov 3, 2005, 2:26:08 AM (14 years ago)
Author:
Till Straumann <strauman@…>
Branches:
4.10, 4.11, 4.8, 4.9, master
Children:
6339f467
Parents:
ec58ea04
Message:

2005-11-02 straumanatslacdotstanford.edu

  • mpc6xx/mmu/pte121.c, mpc6xx/mmu/pte121.h: enhancements to mpc6xx page table support - PTEs can now be modified even if the page table is already active; bugfix: address range crossing 256MB boundary was not handled correctly
Location:
c/src/lib/libcpu/powerpc
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • c/src/lib/libcpu/powerpc/ChangeLog

    rec58ea04 r1b1b43cc  
     12005-11-02      straumanatslacdotstanford.edu
     2
     3        * mpc6xx/mmu/pte121.c, mpc6xx/mmu/pte121.h: enhancements to mpc6xx page
     4        table support - PTEs can now be modified even if the page table is
     5        already active; bugfix: address range crossing 256MB boundary was not
     6        handled correctly
     7
    182005-11-02      straumanatslacdotstanford.edu
    29
  • c/src/lib/libcpu/powerpc/mpc6xx/mmu/pte121.c

    rec58ea04 r1b1b43cc  
    88
    99/* Chose debugging options */
    10 #undef  DEBUG_MAIN      /* create a standalone (host) program for basic testing */
    11 #undef  DEBUG           /* target debugging and consistency checking */
    12 #undef  DEBUG_EXC       /* add exception handler which reenables BAT0 and recovers from a page fault */
     10#undef  DEBUG_MAIN              /* create a standalone (host) program for basic testing */
     11#undef  DEBUG                   /* target debugging and consistency checking */
     12#undef  DEBUG_EXC               /* add exception handler which reenables BAT0 and recovers from a page fault */
    1313
    1414#ifdef  DEBUG_MAIN
    15 #undef  DEBUG           /* must not use these together with DEBUG_MAIN */
     15#undef  DEBUG                   /* must not use these together with DEBUG_MAIN */
    1616#undef  DEBUG_EXC
    1717#endif
     
    2323#include <rtems/bspIo.h>
    2424#include <libcpu/cpuIdent.h>
     25#include <libcpu/spr.h>
    2526#ifdef  DEBUG_EXC
    2627#include <bsp.h>
     
    4243#ifndef DEBUG_MAIN
    4344
    44 #define LD_PHYS_SIZE    32              /* physical address space */
    45 #define LD_PG_SIZE              12              /* page size */
    46 #define LD_PTEG_SIZE    6               /* PTEG size */
    47 #define LD_PTE_SIZE             3               /* PTE size  */
    48 #define LD_SEG_SIZE             28              /* segment size */
    49 #define LD_MIN_PT_SIZE  16              /* minimal size of a page table */
    50 #define LD_HASH_SIZE    19              /* lengh of a hash */
     45#define LD_PHYS_SIZE    32      /* physical address space */
     46#define LD_PG_SIZE              12      /* page size */
     47#define LD_PTEG_SIZE    6       /* PTEG size */
     48#define LD_PTE_SIZE             3       /* PTE size  */
     49#define LD_SEG_SIZE             28      /* segment size */
     50#define LD_MIN_PT_SIZE  16      /* minimal size of a page table */
     51#define LD_HASH_SIZE    19      /* lengh of a hash */
     52#define LD_VSID_SIZE    24      /* vsid bits in seg. register */
    5153
    5254#else /* DEBUG_MAIN */
    5355
    5456/* Reduced 'fantasy' sizes for testing */
    55 #define LD_PHYS_SIZE    32              /* physical address space */
    56 #define LD_PG_SIZE              6               /* page size */
    57 #define LD_PTEG_SIZE    5               /* PTEG size */
    58 #define LD_PTE_SIZE             3               /* PTE size  */
    59 #define LD_SEG_SIZE             28              /* segment size */
    60 #define LD_MIN_PT_SIZE  7               /* minimal size of a page table */
    61 #define LD_HASH_SIZE    19              /* lengh of a hash */
     57#define LD_PHYS_SIZE    32      /* physical address space */
     58#define LD_PG_SIZE              6       /* page size */
     59#define LD_PTEG_SIZE    5       /* PTEG size */
     60#define LD_PTE_SIZE             3       /* PTE size  */
     61#define LD_SEG_SIZE             28      /* segment size */
     62#define LD_MIN_PT_SIZE  7       /* minimal size of a page table */
     63#define LD_HASH_SIZE    19      /* lengh of a hash */
    6264
    6365#endif /* DEBUG_MAIN */
     
    6668
    6769/* Size of a page index */
    68 #define LD_PI_SIZE              ((LD_SEG_SIZE) - (LD_PG_SIZE)) 
     70#define LD_PI_SIZE              ((LD_SEG_SIZE) - (LD_PG_SIZE))
    6971
    7072/* Number of PTEs in a PTEG */
     
    7274
    7375/* Segment register bits */
    74 #define KEY_SUP                 (1<<30) /* supervisor mode key */
    75 #define KEY_USR                 (1<<29) /* user mode key */
     76#define KEY_SUP                 (1<<30) /* supervisor mode key */
     77#define KEY_USR                 (1<<29) /* user mode key */
    7678
    7779/* The range of effective addresses to scan with 'tlbie'
     
    7981 * On the 750 and 7400, there are 128 two way I and D TLBs,
    8082 * indexed by EA[14:19]. Hence calling
    81  *        tlbie rx
     83 *   tlbie rx
    8284 * where rx scans 0x00000, 0x01000, 0x02000, ... 0x3f000
    8385 * is sufficient to do the job
    8486 */
    85 #define NUM_TLB_PER_WAY 64 /* 750 and 7400 have 128 two way TLBs */
     87#define NUM_TLB_PER_WAY 64      /* 750 and 7400 have 128 two way TLBs */
    8688#define FLUSH_EA_RANGE  (NUM_TLB_PER_WAY<<LD_PG_SIZE)
    8789
     
    109111#define PI121(ea)       (((ea)>>LD_PG_SIZE) & ((1<<LD_PI_SIZE)-1))
    110112
     113/* read VSID from segment register */
     114#ifndef DEBUG_MAIN
     115static unsigned32
     116seg2vsid (unsigned32 ea)
     117{
     118  asm volatile ("mfsrin %0, %0":"=r" (ea):"0" (ea));
     119  return ea & ((1 << LD_VSID_SIZE) - 1);
     120}
     121#else
     122#define seg2vsid(ea) VSID121(ea)
     123#endif
    111124
    112125/* Primary and secondary PTE hash functions */
     
    126139
    127140/* Horrible Macros */
    128 #ifdef DEBUG
    129141#ifdef __rtems__
    130142/* must not use printf until multitasking is up */
    131 typedef void (*PrintF)(char *,...);
    132 static PrintF whatPrintf(void)
    133 {
    134                 return _Thread_Executing ?
    135                                 (PrintF)printf :
    136                                 printk;
     143typedef void (*PrintF) (char *, ...);
     144static PrintF
     145whatPrintf (void)
     146{
     147  return _Thread_Executing ? (PrintF) printf : printk;
    137148}
    138149
     
    141152#define PRINTF(args...) printf(args)
    142153#endif
    143 #endif
    144154
    145155#ifdef DEBUG
    146 unsigned long
    147 triv121PgTblConsistency(Triv121PgTbl pt, int pass, int expect);
    148 
    149 static int consistencyPass=0;
     156unsigned long triv121PgTblConsistency (Triv121PgTbl pt, int pass, int expect);
     157
     158static int consistencyPass = 0;
    150159#define CONSCHECK(expect) triv121PgTblConsistency(&pgTbl,consistencyPass++,(expect))
    151160#else
     
    155164/**************************** TYPE DEFINITIONS ****************************/
    156165
    157 /* A PTE entry */
    158 typedef struct PTERec_ {
    159                 unsigned long v:1,    vsid:24, h:1, api: 6;
    160                 unsigned long rpn:20, pad: 3, r:1, c:1, wimg:4, marked:1, pp:2;
    161 } PTERec, *PTE;
    162 
    163166/* internal description of a trivial page table */
    164 typedef struct Triv121PgTblRec_ {
    165                 PTE                             base;
    166                 unsigned long   size;
    167                 int                             active;
     167typedef struct Triv121PgTblRec_
     168{
     169  APte base;
     170  unsigned long size;
     171  int active;
    168172} Triv121PgTblRec;
    169173
     
    172176
    173177#ifdef DEBUG_EXC
     178static void myhdl (BSP_Exception_frame * excPtr);
     179#endif
     180
     181static void dumpPte (APte pte);
     182
    174183static void
    175 myhdl(BSP_Exception_frame* excPtr);
    176 #endif
    177 
    178 #if defined(DEBUG_MAIN) || defined(DEBUG)
    179 static void
    180 dumpPte(PTE pte);
    181 #endif
    182 
    183 #ifdef DEBUG
    184 static void
    185 dumpPteg(unsigned long vsid, unsigned long pi, unsigned long hash);
     184dumpPteg (unsigned long vsid, unsigned long pi, unsigned long hash);
    186185unsigned long
    187 triv121IsRangeMapped(unsigned long start, unsigned long end);
    188 #endif
     186triv121IsRangeMapped (long vsid, unsigned long start, unsigned long end);
     187
     188static void do_dssall ();
    189189
    190190/**************************** STATIC VARIABLES ****************************/
     
    193193 * we have malloc or even RTEMS workspace available
    194194 */
    195 static Triv121PgTblRec pgTbl={0};
     195static Triv121PgTblRec pgTbl = { 0 };
    196196
    197197#ifdef DEBUG_EXC
    198 static void *ohdl;                      /* keep a pointer to the original handler */
     198static void *ohdl;              /* keep a pointer to the original handler */
    199199#endif
    200200
     
    202202
    203203/* compute the page table entry group (PTEG) of a hash */
    204 static inline PTE
    205 ptegOf(Triv121PgTbl pt, unsigned long hash)
    206 {
    207         hash &= ((1<<LD_HASH_SIZE)-1);
    208         return (PTE)(((unsigned long)pt->base) | ((hash<<LD_PTEG_SIZE) & (pt->size-1)));
     204static inline APte
     205ptegOf (Triv121PgTbl pt, unsigned long hash)
     206{
     207  hash &= ((1 << LD_HASH_SIZE) - 1);
     208  return (APte) (((unsigned long) pt->
     209                  base) | ((hash << LD_PTEG_SIZE) & (pt->size - 1)));
    209210}
    210211
     
    217218 *       be split into vsid and pi...
    218219 */
    219 static PTE
    220 alreadyMapped(Triv121PgTbl pt, long vsid, unsigned long pi)
    221 {
    222 int                             i;
    223 unsigned long   hash,api;
    224 PTE                             pte;
    225 
    226         if (!pt->size)
    227                 return 0;
    228 
    229         if (vsid<0) {
    230                 vsid=VSID121(pi);
    231                 pi=PI121(pi);
    232         }
    233 
    234         hash = PTE_HASH1(vsid,pi);
    235         api=API(pi);
    236         for (i=0, pte=ptegOf(pt,hash); i<PTE_PER_PTEG; i++,pte++)
    237                 if (pte->v && pte->vsid==vsid && pte->api==api && 0==pte->h)
    238                         return pte;
    239         /* try the secondary hash table */
    240         hash = PTE_HASH2(hash);
    241         for (i=0, pte=ptegOf(pt,hash); i<PTE_PER_PTEG; i++,pte++)
    242                 if (pte->v && pte->vsid==vsid && pte->api==api && 1==pte->h)
    243                         return pte;
    244         return 0;
     220static APte
     221alreadyMapped (Triv121PgTbl pt, long vsid, unsigned long pi)
     222{
     223  int i;
     224  unsigned long hash, api;
     225  APte pte;
     226
     227  if (!pt->size)
     228    return 0;
     229
     230  if (TRIV121_121_VSID == vsid) {
     231    vsid = VSID121 (pi);
     232    pi = PI121 (pi);
     233  } else if (TRIV121_SEG_VSID == vsid) {
     234    vsid = seg2vsid (pi);
     235    pi = PI121 (pi);
     236  }
     237
     238  hash = PTE_HASH1 (vsid, pi);
     239  api = API (pi);
     240  for (i = 0, pte = ptegOf (pt, hash); i < PTE_PER_PTEG; i++, pte++)
     241    if (pte->v && pte->vsid == vsid && pte->api == api && 0 == pte->h)
     242      return pte;
     243  /* try the secondary hash table */
     244  hash = PTE_HASH2 (hash);
     245  for (i = 0, pte = ptegOf (pt, hash); i < PTE_PER_PTEG; i++, pte++)
     246    if (pte->v && pte->vsid == vsid && pte->api == api && 1 == pte->h)
     247      return pte;
     248  return 0;
    245249}
    246250
     
    254258 *         the secondary hash, respectively.
    255259 */
    256 static PTE
    257 slotFor(Triv121PgTbl pt, unsigned long vsid, unsigned long pi)
    258 {
    259 int                             i;
    260 unsigned long   hash,api;
    261 PTE                             pte;
    262 
    263         /* primary hash */
    264         hash = PTE_HASH1(vsid,pi);
    265         api=API(pi);
    266         /* linear search thru all buckets for this hash */
    267         for (i=0, pte=ptegOf(pt,hash); i<PTE_PER_PTEG; i++,pte++) {
    268                 if (!pte->v && !pte->marked) {
    269                         /* found a free PTE; mark it as potentially used and return */
    270                         pte->h=0;       /* found by the primary hash fn */
    271                         pte->marked=1;
    272                         return pte;
    273                 }
    274         }
     260static APte
     261slotFor (Triv121PgTbl pt, unsigned long vsid, unsigned long pi)
     262{
     263  int i;
     264  unsigned long hash, api;
     265  APte pte;
     266
     267  /* primary hash */
     268  hash = PTE_HASH1 (vsid, pi);
     269  api = API (pi);
     270  /* linear search thru all buckets for this hash */
     271  for (i = 0, pte = ptegOf (pt, hash); i < PTE_PER_PTEG; i++, pte++) {
     272    if (!pte->v && !pte->marked) {
     273      /* found a free PTE; mark it as potentially used and return */
     274      pte->h = 0;               /* found by the primary hash fn */
     275      pte->marked = 1;
     276      return pte;
     277    }
     278  }
    275279
    276280#ifdef DEBUG
    277         /* Strange: if the hash table was allocated big enough,
    278         *          this should not happen (when using a 1:1 mapping)
    279         *          Give them some information...
    280         */
    281         PRINTF("## First hash bucket full - ");
    282         dumpPteg(vsid,pi,hash);
    283 #endif
    284 
    285         hash = PTE_HASH2(hash);
     281  /* Strange: if the hash table was allocated big enough,
     282  *          this should not happen (when using a 1:1 mapping)
     283  *          Give them some information...
     284  */
     285  PRINTF ("## First hash bucket full - ");
     286  dumpPteg (vsid, pi, hash);
     287#endif
     288
     289  hash = PTE_HASH2 (hash);
    286290#ifdef DEBUG
    287         PRINTF("   Secondary pteg is 0x%08x\n", (unsigned)ptegOf(pt,hash));
    288 #endif
    289         for (i=0, pte=ptegOf(pt,hash); i<PTE_PER_PTEG; i++,pte++) {
    290                 if (!pte->v && !pte->marked) {
    291                         /* mark this pte as potentially used */
    292                         pte->marked=1;
    293                         pte->h=1;
    294                         return pte;
    295                 }
    296         }
     291  PRINTF ("   Secondary pteg is 0x%08x\n", (unsigned) ptegOf (pt, hash));
     292#endif
     293  for (i = 0, pte = ptegOf (pt, hash); i < PTE_PER_PTEG; i++, pte++) {
     294    if (!pte->v && !pte->marked) {
     295      /* mark this pte as potentially used */
     296      pte->marked = 1;
     297      pte->h = 1;
     298      return pte;
     299    }
     300  }
    297301#ifdef DEBUG
    298         /* Even more strange - most likely, something is REALLY messed up */
    299         PRINTF("## Second hash bucket full - ");
    300         dumpPteg(vsid,pi,hash);
    301 #endif
    302         return 0;
     302  /* Even more strange - most likely, something is REALLY messed up */
     303  PRINTF ("## Second hash bucket full - ");
     304  dumpPteg (vsid, pi, hash);
     305#endif
     306  return 0;
    303307}
    304308
    305309/* unmark all entries */
    306310static void
    307 unmarkAll(Triv121PgTbl pt)
    308 {
    309 unsigned long   n=pt->size / sizeof(PTERec);
    310 unsigned long   i;
    311 PTE                             pte;
    312         for (i=0,pte=pt->base; i<n; i++,pte++)
    313                 pte->marked=0;
     311unmarkAll (Triv121PgTbl pt)
     312{
     313  unsigned long n = pt->size / sizeof (PTERec);
     314  unsigned long i;
     315  APte pte;
     316  for (i = 0, pte = pt->base; i < n; i++, pte++)
     317    pte->marked = 0;
    314318
    315319}
     
    325329 */
    326330unsigned long
    327 triv121PgTblLdMinSize(unsigned long size)
    328 {
    329 unsigned long i;
    330         /* round 'size' up to the next page boundary */
    331         size += (1<<LD_PG_SIZE)-1;
    332         size &= ~((1<<LD_PG_SIZE)-1);
    333         /* divide by number of PTEs  and multiply
    334         * by the size of a PTE.
    335         */
    336         size >>= LD_PG_SIZE - LD_PTE_SIZE;
    337         /* find the next power of 2 >= size */
    338         for (i=0; i<LD_PHYS_SIZE; i++) {
    339                 if ((1<<i) >= size)
    340                         break;
    341         }
    342         /* pop up to the allowed minimum, if necessary */
    343         if (i<LD_MIN_PT_SIZE)
    344                         i=LD_MIN_PT_SIZE;
    345         return i;
     331triv121PgTblLdMinSize (unsigned long size)
     332{
     333  unsigned long i;
     334  /* round 'size' up to the next page boundary */
     335  size += (1 << LD_PG_SIZE) - 1;
     336  size &= ~((1 << LD_PG_SIZE) - 1);
     337  /* divide by number of PTEs  and multiply
     338  * by the size of a PTE.
     339  */
     340  size >>= LD_PG_SIZE - LD_PTE_SIZE;
     341  /* find the next power of 2 >= size */
     342  for (i = 0; i < LD_PHYS_SIZE; i++) {
     343    if ((1 << i) >= size)
     344      break;
     345  }
     346  /* pop up to the allowed minimum, if necessary */
     347  if (i < LD_MIN_PT_SIZE)
     348    i = LD_MIN_PT_SIZE;
     349  return i;
    346350}
    347351
     
    353357 */
    354358Triv121PgTbl
    355 triv121PgTblInit(unsigned long base, unsigned ldSize)
    356 {
    357         if (pgTbl.size) {
    358                 /* already initialized */
    359                 return 0;
    360         }
    361 
    362         if (ldSize < LD_MIN_PT_SIZE)
    363                 return 0; /* too small */
    364 
    365         if (base & ((1<<ldSize)-1))
    366                 return 0; /* misaligned */
    367 
    368         /* This was tested on 604r, 750 and 7400.
    369          * On other CPUs, verify that the TLB invalidation works
    370          * for a new CPU variant and that it has hardware PTE lookup/
    371          * TLB replacement before adding it to this list.
    372          *
    373          * NOTE: The 603 features no hardware PTE lookup - and
    374          *       hence the page tables should NOT be used.
    375          *               Although lookup could be implemented in
    376          *               software this is probably not desirable
    377          *               as it could have an impact on hard realtime
    378          *               performance, screwing deterministic latency!
    379          *               (Could still be useful for debugging, though)
    380          */
    381         if      (       PPC_604         !=current_ppc_cpu &&
    382                         PPC_604e        !=current_ppc_cpu &&
    383                         PPC_604r        !=current_ppc_cpu &&
    384                         PPC_750         !=current_ppc_cpu &&
    385                         PPC_7400        !=current_ppc_cpu &&
    386                         PPC_7455        !=current_ppc_cpu )
    387                 return 0;       /* unsupported by this CPU */
    388 
    389         pgTbl.base=(PTE)base;
    390         pgTbl.size=1<<ldSize;
    391         /* clear all page table entries */
    392         memset(pgTbl.base, 0, pgTbl.size);
    393 
    394         CONSCHECK(0);
    395 
    396         /* map the page table itself 'm' and 'readonly' */
    397         if (triv121PgTblMap(&pgTbl,
    398                                                 TRIV121_121_VSID,
    399                                                 base,
    400                                                 (pgTbl.size >> LD_PG_SIZE),
    401                                                 TRIV121_ATTR_M,
    402                                                 TRIV121_PP_RO_PAGE) >= 0)
    403                 return 0;
    404 
    405         CONSCHECK((pgTbl.size>>LD_PG_SIZE));
    406 
    407         return &pgTbl;
     359triv121PgTblInit (unsigned long base, unsigned ldSize)
     360{
     361  if (pgTbl.size) {
     362    /* already initialized */
     363    return 0;
     364  }
     365
     366  if (ldSize < LD_MIN_PT_SIZE)
     367    return 0;                   /* too small */
     368
     369  if (base & ((1 << ldSize) - 1))
     370    return 0;                   /* misaligned */
     371
     372  /* This was tested on 604r, 750 and 7400.
     373   * On other CPUs, verify that the TLB invalidation works
     374   * for a new CPU variant and that it has hardware PTE lookup/
     375   * TLB replacement before adding it to this list.
     376   *
     377   * NOTE: The 603 features no hardware PTE lookup - and
     378   *       hence the page tables should NOT be used.
     379   *               Although lookup could be implemented in
     380   *               software this is probably not desirable
     381   *               as it could have an impact on hard realtime
     382   *               performance, screwing deterministic latency!
     383   *               (Could still be useful for debugging, though)
     384   */
     385  if (   PPC_604 != current_ppc_cpu
     386      && PPC_604e != current_ppc_cpu
     387      && PPC_604r != current_ppc_cpu
     388      && PPC_750  != current_ppc_cpu
     389      && PPC_7400 != current_ppc_cpu
     390      && PPC_7455 != current_ppc_cpu
     391      && PPC_7457 != current_ppc_cpu
     392     )
     393    return 0;                   /* unsupported by this CPU */
     394
     395  pgTbl.base = (APte) base;
     396  pgTbl.size = 1 << ldSize;
     397  /* clear all page table entries */
     398  memset (pgTbl.base, 0, pgTbl.size);
     399
     400  CONSCHECK (0);
     401
     402  /* map the page table itself 'm' and 'readonly' */
     403  if (triv121PgTblMap (&pgTbl,
     404                       TRIV121_121_VSID,
     405                       base,
     406                       (pgTbl.size >> LD_PG_SIZE),
     407                       TRIV121_ATTR_M, TRIV121_PP_RO_PAGE) >= 0)
     408    return 0;
     409
     410  CONSCHECK ((pgTbl.size >> LD_PG_SIZE));
     411
     412  return &pgTbl;
    408413}
    409414
     
    412417 */
    413418Triv121PgTbl
    414 triv121PgTblGet(void)
    415 {
    416         return pgTbl.size ? &pgTbl : 0;
     419triv121PgTblGet (void)
     420{
     421  return pgTbl.size ? &pgTbl : 0;
    417422}
    418423
     
    425430 */
    426431long
    427 triv121PgTblMap(
    428                                 Triv121PgTbl    pt,
    429                                 long            ovsid,
    430                                 unsigned long   start,
    431                                 unsigned long   numPages,
    432                                 unsigned                attributes,
    433                                 unsigned                protection
    434                                 )
    435 {
    436 int             i,pass;
    437 unsigned long   pi;
    438 PTE             pte;
    439 long            vsid;
    440         /* already activated - no change allowed */
    441         if (pt->active)
    442                         return -1;
    443 
    444         if (ovsid < 0) {
    445                         /* use 1:1 mapping */
    446                         ovsid = VSID121(start);
    447         }
    448 
     432triv121PgTblMap (Triv121PgTbl pt,
     433                 long ovsid,
     434                 unsigned long start,
     435                 unsigned long numPages,
     436                 unsigned attributes, unsigned protection)
     437{
     438  int i, pass;
     439  unsigned long pi;
     440  APte pte;
     441  long vsid;
    449442#ifdef DEBUG
    450         PRINTF("Mapping %i (0x%x) pages at 0x%08x for VSID 0x%08x\n",
    451                 (unsigned)numPages, (unsigned)numPages,
    452                 (unsigned)start, (unsigned)vsid);
    453 #endif
    454 
    455         /* map in two passes. During the first pass, we try
    456          * to claim entries as needed. The 'slotFor()' routine
    457          * will 'mark' the claimed entries without 'valid'ating
    458          * them.
    459          * If the mapping fails, all claimed entries are unmarked
    460          * and we return the PI for which allocation failed.
    461          *
    462          * Once we know that the allocation would succeed, we
    463          * do a second pass; during the second pass, the PTE
    464          * is actually written.
    465          *
    466          */
    467         for (pass=0; pass<2; pass++) {
    468                 /* check if we would succeed during the first pass */
    469                 for (i=0, pi=PI121(start), vsid = ovsid; i<numPages; i++,pi++) {
    470                         if ( pi >= 1<<LD_PI_SIZE ) {
    471                                vsid++;
    472                                pi = 0;
    473                        }
    474                         /* leave alone existing mappings for this EA */
    475                         if (!alreadyMapped(pt, vsid, pi)) {
    476                                 if (!(pte=slotFor(pt, vsid, pi))) {
    477                                         /* no free slot found for page index 'pi' */
    478                                         unmarkAll(pt);
    479                                         return pi;
    480                                 } else {
    481                                         /* have a free slot; marked by slotFor() */
    482                                         if (pass) {
    483                                                 /* second pass; do the real work */
    484                                                 pte->vsid=vsid;
    485                                                 /* H was set by slotFor() */
    486                                                 pte->api =API(pi);
    487                                                 /* set up 1:1 mapping */
    488                                                 pte->rpn =((((unsigned long)vsid)&((1<<(LD_PHYS_SIZE-LD_SEG_SIZE))-1))<<LD_PI_SIZE) | pi;
    489                                                 pte->wimg=attributes & 0xf;
    490                                                 pte->pp=protection&0x3;
    491                                                 /* mark it valid */
    492                                                 pte->v=1;
    493                                                 pte->marked=0;
     443  long saved_vsid = ovsid;
     444#endif
     445
     446  if (TRIV121_121_VSID == ovsid) {
     447    /* use 1:1 mapping */
     448    ovsid = VSID121 (start);
     449  } else if (TRIV121_SEG_VSID == ovsid) {
     450    ovsid = seg2vsid (start);
     451  }
     452
    494453#ifdef DEBUG
    495                                                 /* add paranoia */
    496                                                 assert(alreadyMapped(pt, vsid, pi) == pte);
    497 #endif
    498                                         }
    499                                 }
    500                         }
    501                 }
    502                 unmarkAll(pt);
    503         }
     454  PRINTF ("Mapping %i (0x%x) pages at 0x%08x for VSID 0x%08x\n",
     455          (unsigned) numPages, (unsigned) numPages,
     456          (unsigned) start, (unsigned) ovsid);
     457#endif
     458
     459  /* map in two passes. During the first pass, we try
     460   * to claim entries as needed. The 'slotFor()' routine
     461   * will 'mark' the claimed entries without 'valid'ating
     462   * them.
     463   * If the mapping fails, all claimed entries are unmarked
     464   * and we return the PI for which allocation failed.
     465   *
     466   * Once we know that the allocation would succeed, we
     467   * do a second pass; during the second pass, the PTE
     468   * is actually written.
     469   *
     470   */
     471  for (pass = 0; pass < 2; pass++) {
     472    /* check if we would succeed during the first pass */
     473    for (i = 0, pi = PI121 (start), vsid = ovsid; i < numPages; i++, pi++) {
     474      if (pi >= 1 << LD_PI_SIZE) {
     475        vsid++;
     476        pi = 0;
     477      }
     478      /* leave alone existing mappings for this EA */
     479      if (!alreadyMapped (pt, vsid, pi)) {
     480        if (!(pte = slotFor (pt, vsid, pi))) {
     481          /* no free slot found for page index 'pi' */
     482          unmarkAll (pt);
     483          return pi;
     484        } else {
     485          /* have a free slot; marked by slotFor() */
     486          if (pass) {
     487            /* second pass; do the real work */
     488            pte->vsid = vsid;
     489            /* H was set by slotFor() */
     490            pte->api = API (pi);
     491            /* set up 1:1 mapping */
     492            pte->rpn =
     493              ((((unsigned long) vsid) &
     494                ((1 << (LD_PHYS_SIZE - LD_SEG_SIZE)) -
     495                 1)) << LD_PI_SIZE) | pi;
     496            pte->wimg = attributes & 0xf;
     497            pte->pp = protection & 0x3;
     498            /* mark it valid */
     499            pte->marked = 0;
     500            if (pt->active) {
     501              unsigned32 flags;
     502              rtems_interrupt_disable (flags);
     503              /* order setting 'v' after writing everything else */
     504              asm volatile ("eieio");
     505              pte->v = 1;
     506              asm volatile ("sync");
     507              rtems_interrupt_enable (flags);
     508            } else {
     509              pte->v = 1;
     510            }
     511
    504512#ifdef DEBUG
    505         {
    506         unsigned long failedat;
    507         CONSCHECK(-1);
    508         /* double check that the requested range is mapped */
    509         failedat=triv121IsRangeMapped(start, start + (1<<LD_PG_SIZE)*numPages);
    510         if (0x0C0C != failedat) {
    511                 PRINTF("triv121 mapping failed at 0x%08x\n",(unsigned)failedat);
    512                 return PI121(failedat);
    513         }
    514         }
    515 #endif
    516         return TRIV121_MAP_SUCCESS; /* -1 !! */
     513            /* add paranoia */
     514            assert (alreadyMapped (pt, vsid, pi) == pte);
     515#endif
     516          }
     517        }
     518      }
     519    }
     520    unmarkAll (pt);
     521  }
     522#ifdef DEBUG
     523  {
     524    unsigned long failedat;
     525    CONSCHECK (-1);
     526    /* double check that the requested range is mapped */
     527    failedat =
     528      triv121IsRangeMapped (saved_vsid, start,
     529                            start + (1 << LD_PG_SIZE) * numPages);
     530    if (0x0C0C != failedat) {
     531      PRINTF ("triv121 mapping failed at 0x%08x\n", (unsigned) failedat);
     532      return PI121 (failedat);
     533    }
     534  }
     535#endif
     536  return TRIV121_MAP_SUCCESS;   /* -1 !! */
    517537}
    518538
    519539unsigned long
    520 triv121PgTblSDR1(Triv121PgTbl pt)
    521 {
    522         return (((unsigned long)pt->base) & ~(LD_MIN_PT_SIZE-1)) |
    523                    ( ((pt->size-1) >> LD_MIN_PT_SIZE) &
    524                          ((1<<(LD_HASH_SIZE-(LD_MIN_PT_SIZE-LD_PTEG_SIZE)))-1)
    525                    );
     540triv121PgTblSDR1 (Triv121PgTbl pt)
     541{
     542  return (((unsigned long) pt->base) & ~((1 << LD_MIN_PT_SIZE) - 1)) |
     543    (((pt->size - 1) >> LD_MIN_PT_SIZE) &
     544     ((1 << (LD_HASH_SIZE - (LD_MIN_PT_SIZE - LD_PTEG_SIZE))) - 1)
     545    );
    526546}
    527547
    528548void
    529 triv121PgTblActivate(Triv121PgTbl pt)
     549triv121PgTblActivate (Triv121PgTbl pt)
    530550{
    531551#ifndef DEBUG_MAIN
    532 unsigned long sdr1=triv121PgTblSDR1(pt);
    533 #endif
    534         pt->active=1;
     552  unsigned long sdr1 = triv121PgTblSDR1 (pt);
     553#endif
     554  pt->active = 1;
    535555
    536556#ifndef DEBUG_MAIN
    537557#ifdef DEBUG_EXC
    538         /* install our exception handler */
    539         ohdl=globalExceptHdl;
    540         globalExceptHdl=myhdl;
    541         __asm__ __volatile__ ("sync");
    542 #endif
    543 
    544         /* This section of assembly code takes care of the
    545          * following:
    546          * - get MSR and switch interrupts + MMU off
    547          *
    548          * - load up the segment registers with a
    549          *   1:1 effective <-> virtual mapping;
    550          *   give user & supervisor keys
    551          *
    552          * - flush all TLBs;
    553          *   NOTE: the TLB flushing code is probably
    554          *         CPU dependent!
    555          *
    556          * - setup SDR1
    557          *
    558          * - restore original MSR
    559          */
    560         __asm__ __volatile(
    561                 "       mtctr   %0\n"
    562                 /* Get MSR and switch interrupts off - just in case.
    563                  * Also switch the MMU off; the book
    564                  * says that SDR1 must not be changed with either
    565                  * MSR_IR or MSR_DR set. I would guess that it could
    566                  * be safe as long as the IBAT & DBAT mappings override
    567                  * the page table...
    568                  */
    569                 "       mfmsr   %0\n"
    570                 "       andc    %6, %0, %6\n"
    571                 "       mtmsr   %6\n"
    572                 "       isync   \n"
    573                 /* set up the segment registers */
    574                 "       li              %6, 0\n"
    575                 "1:     mtsrin  %1, %6\n"
    576                 "       addis   %6, %6, 0x1000\n"       /* address next SR */
    577                 "       addi    %1, %1, 1\n"            /* increment VSID  */
    578                 "       bdnz    1b\n"
    579                 /* Now flush all TLBs, starting with the topmost index */
    580                 "       lis             %6, %2@h\n"     
    581                 "2:     addic.  %6, %6, -%3\n"          /* address the next one (decrementing) */
    582                 "       tlbie   %6\n"                           /* invalidate & repeat */
    583                 "       bgt             2b\n"
    584                 "       tlbsync\n"
    585                 "       sync\n"
    586                 /* set up SDR1 */
    587                 "   mtspr       %4, %5\n"
    588                 /* restore original MSR  */
    589                 "       mtmsr   %0\n"
    590                 "       isync   \n"
    591                 ::"r"(16), "b"(KEY_USR | KEY_SUP),
    592                   "i"(FLUSH_EA_RANGE), "i"(1<<LD_PG_SIZE),
    593                   "i"(SDR1), "r"(sdr1),
    594                   "b"(MSR_EE | MSR_IR | MSR_DR)
    595                 : "ctr","cc");
    596 
    597         /* At this point, BAT0 is probably still active; it's the
    598          * caller's job to deactivate it...
    599          */
     558  /* install our exception handler */
     559  ohdl = globalExceptHdl;
     560  globalExceptHdl = myhdl;
     561  __asm__ __volatile__ ("sync");
     562#endif
     563
     564  /* This section of assembly code takes care of the
     565   * following:
     566   * - get MSR and switch interrupts + MMU off
     567   *
     568   * - load up the segment registers with a
     569   *   1:1 effective <-> virtual mapping;
     570   *   give user & supervisor keys
     571   *
     572   * - flush all TLBs;
     573   *   NOTE: the TLB flushing code is probably
     574   *         CPU dependent!
     575   *
     576   * - setup SDR1
     577   *
     578   * - restore original MSR
     579   */
     580  __asm__ __volatile (
     581    "   mtctr   %0\n"
     582    /* Get MSR and switch interrupts off - just in case.
     583     * Also switch the MMU off; the book
     584     * says that SDR1 must not be changed with either
     585     * MSR_IR or MSR_DR set. I would guess that it could
     586     * be safe as long as the IBAT & DBAT mappings override
     587     * the page table...
     588     */
     589    "   mfmsr   %0\n"
     590    "   andc    %6, %0, %6\n"
     591    "   mtmsr   %6\n"
     592    "   isync   \n"
     593    /* set up the segment registers */
     594    "   li              %6, 0\n"
     595    "1: mtsrin  %1, %6\n"
     596    "   addis   %6, %6, 0x1000\n" /* address next SR */
     597    "   addi    %1, %1, 1\n"      /* increment VSID  */
     598    "   bdnz    1b\n"
     599    /* Now flush all TLBs, starting with the topmost index */
     600    "   lis             %6, %2@h\n"
     601    "2: addic.  %6, %6, -%3\n"    /* address the next one (decrementing) */
     602    "   tlbie   %6\n"             /* invalidate & repeat */
     603    "   bgt             2b\n"
     604    "   eieio   \n"
     605    "   tlbsync \n"
     606    "   sync    \n"
     607    /* set up SDR1 */
     608    "   mtspr   %4, %5\n"
     609    /* restore original MSR  */
     610    "   mtmsr   %0\n"
     611    "   isync   \n"
     612      :
     613      :"r" (16), "b" (KEY_USR | KEY_SUP),
     614       "i" (FLUSH_EA_RANGE), "i" (1 << LD_PG_SIZE),
     615       "i" (SDR1), "r" (sdr1), "b" (MSR_EE | MSR_IR | MSR_DR)
     616      :"ctr", "cc"
     617  );
     618
     619  /* At this point, BAT0 is probably still active; it's the
     620   * caller's job to deactivate it...
     621   */
    600622#endif
    601623}
     
    606628#ifdef DEBUG_EXC
    607629
    608 #define BAT_VALID_BOTH  3       /* allow user + super access */
     630#define BAT_VALID_BOTH  3       /* allow user + super access */
    609631
    610632static void
    611 myhdl(BSP_Exception_frame* excPtr)
    612 {
    613 if (3==excPtr->_EXC_number) {
    614         unsigned long dsisr;
    615 
    616         /* reactivate DBAT0 and read DSISR */
    617         __asm__ __volatile__(
    618                         "mfspr %0, %1\n"
    619                         "ori    %0,%0,3\n"
    620                         "mtspr %1, %0\n"
    621                         "sync\n"
    622                         "mfspr %0, %2\n"
    623                         :"=r"(dsisr)
    624                         :"i"(DBAT0U),"i"(DSISR),"i"(BAT_VALID_BOTH)
    625         );
    626 
    627         printk("Data Access Exception (DSI) # 3\n");
    628         printk("Reactivated DBAT0 mapping\n");
    629 
    630 
    631         printk("DSISR 0x%08x\n",dsisr);
    632 
    633         printk("revectoring to prevent default handler panic().\n");
    634         printk("NOTE: exception number %i below is BOGUS\n",
    635                         ASM_DEC_VECTOR);
    636         /* make this exception 'recoverable' for
    637          * the default handler by faking a decrementer
    638          * exception.
    639          * Note that the default handler's message will be
    640          * wrong about the exception number.
    641          */
    642         excPtr->_EXC_number = ASM_DEC_VECTOR;
    643 }
     633myhdl (BSP_Exception_frame * excPtr)
     634{
     635  if (3 == excPtr->_EXC_number) {
     636    unsigned long dsisr;
     637
     638    /* reactivate DBAT0 and read DSISR */
     639    __asm__ __volatile__ (
     640      "mfspr %0, %1   \n"
     641      "ori   %0, %0, 3\n"
     642      "mtspr %1, %0   \n"
     643      "sync\n"
     644      "mfspr %0, %2\n"
     645        :"=&r" (dsisr)
     646        :"i" (DBAT0U), "i" (DSISR), "i" (BAT_VALID_BOTH)
     647    );
     648
     649    printk ("Data Access Exception (DSI) # 3\n");
     650    printk ("Reactivated DBAT0 mapping\n");
     651
     652
     653    printk ("DSISR 0x%08x\n", dsisr);
     654
     655    printk ("revectoring to prevent default handler panic().\n");
     656    printk ("NOTE: exception number %i below is BOGUS\n", ASM_DEC_VECTOR);
     657    /* make this exception 'recoverable' for
     658     * the default handler by faking a decrementer
     659     * exception.
     660     * Note that the default handler's message will be
     661     * wrong about the exception number.
     662     */
     663    excPtr->_EXC_number = ASM_DEC_VECTOR;
     664  }
    644665/* now call the original handler */
    645 ((void(*)())ohdl)(excPtr);
    646 }
    647 #endif
    648 
    649 
    650 #ifdef DEBUG
     666  ((void (*)()) ohdl) (excPtr);
     667}
     668#endif
     669
     670
    651671
    652672/* test the consistency of the page table
     
    669689 */
    670690unsigned long
    671 triv121PgTblConsistency(Triv121PgTbl pt, int pass, int expected)
    672 {
    673 PTE pte;
    674 int i;
    675 unsigned v,m;
    676 int warn=0;
    677 static int maxw=20;     /* mute after detecting this many errors */
    678 
    679         PRINTF("Checking page table at 0x%08x (size %i==0x%x)\n",
    680                         (unsigned)pt->base, (unsigned)pt->size, (unsigned)pt->size);
    681 
    682         if (!pt->base || !pt->size) {
    683                 PRINTF("Uninitialized Page Table!\n");
    684                 return 0;
    685         }
    686 
    687         v=m=0;
     691triv121PgTblConsistency (Triv121PgTbl pt, int pass, int expected)
     692{
     693  APte pte;
     694  int i;
     695  unsigned v, m;
     696  int warn = 0;
     697  static int maxw = 20;         /* mute after detecting this many errors */
     698
     699  PRINTF ("Checking page table at 0x%08x (size %i==0x%x)\n",
     700          (unsigned) pt->base, (unsigned) pt->size, (unsigned) pt->size);
     701
     702  if (!pt->base || !pt->size) {
     703    PRINTF ("Uninitialized Page Table!\n");
     704    return 0;
     705  }
     706
     707  v = m = 0;
    688708#if 1
    689         /* 10/9/2002: I had machine checks crashing after this loop
    690          *            terminated. Maybe caused by speculative loads
    691          *            from beyond the valid memory area (since the
    692          *            page hash table sits at the top of physical
    693          *            memory).
    694          *            Very bizarre - the other loops in this file
    695          *            seem to be fine. Maybe there is a compiler bug??
    696          *            For the moment, I let the loop run backwards...
    697          *
    698          *                        Also see the comment a couple of lines down.
    699          */
    700         for (i=pt->size/sizeof(PTERec)-1, pte=pt->base + i; i>=0; i--,pte--)
     709  /* 10/9/2002: I had machine checks crashing after this loop
     710   *            terminated. Maybe caused by speculative loads
     711   *            from beyond the valid memory area (since the
     712   *            page hash table sits at the top of physical
     713   *            memory).
     714   *            Very bizarre - the other loops in this file
     715   *            seem to be fine. Maybe there is a compiler bug??
     716   *            For the moment, I let the loop run backwards...
     717   *
     718   *                        Also see the comment a couple of lines down.
     719   */
     720  for (i = pt->size / sizeof (PTERec) - 1, pte = pt->base + i; i >= 0;
     721       i--, pte--)
    701722#else
    702         for (i=0, pte=pt->base; i<pt->size/sizeof(PTERec); i++,pte++)
    703 #endif
    704         {
    705                 int                             err=0;
    706                 char                    buf[500];
    707                 unsigned long   *lp=(unsigned long*)pte;
     723  for (i = 0, pte = pt->base; i < pt->size / sizeof (PTERec); i++, pte++)
     724#endif
     725  {
     726    int err = 0;
     727    char buf[500];
     728    unsigned long *lp = (unsigned long *) pte;
    708729#if 0
    709                 /* If I put this bogus while statement here (the body is
    710                  * never reached), the original loop works OK
    711                  */
    712                 while (pte >= pt->base + pt->size/sizeof(PTERec))
    713                                 /* never reached */;
    714 #endif
    715 
    716                 if ( (*lp & (0xfffff0<<7)) || *(lp+1) & 0xe00 || (pte->v && pte->marked)) {
    717                         /* check for vsid (without segment bits) == 0, unused bits == 0, valid && marked */
    718                         sprintf(buf,"invalid VSID , unused bits or v && m");
    719                         err=1;
    720                 } else {
    721                         if (pte->v) v++;
    722                         if (pte->marked) m++;
    723                 }
    724                 if (err && maxw) {
    725                         PRINTF("Pass %i -- strange PTE at 0x%08x found for page index %i == 0x%08x:\n",
    726                                 pass,(unsigned)pte,i,i);
    727                         PRINTF("Reason: %s\n",buf);
    728                         dumpPte(pte);
    729                         warn++;
    730                         maxw--;
    731                 }
    732         }
    733         if (warn) {
    734                 PRINTF("%i errors found; currently %i entries marked, %i are valid\n",
    735                         warn, m, v);
    736         }
    737         v+=m;
    738         if (maxw && expected>=0 && expected != v) {
    739                 /* number of occupied slots not what they expected */
    740                 PRINTF("Wrong # of occupied slots detected during pass");
    741             PRINTF("%i; should be %i (0x%x) is %i (0x%x)\n",
    742                                 pass, expected, (unsigned)expected, v, (unsigned)v);
    743                 maxw--;
    744         }
    745         return v;
     730    /* If I put this bogus while statement here (the body is
     731     * never reached), the original loop works OK
     732     */
     733    while (pte >= pt->base + pt->size / sizeof (PTERec))
     734      /* never reached */ ;
     735#endif
     736
     737    if ((*lp & (0xfffff0 << 7)) || *(lp + 1) & 0xe00
     738        || (pte->v && pte->marked)) {
     739      /* check for vsid (without segment bits) == 0, unused bits == 0, valid && marked */
     740      sprintf (buf, "invalid VSID , unused bits or v && m");
     741      err = 1;
     742    } else {
     743      if (pte->v)
     744        v++;
     745      if (pte->marked)
     746        m++;
     747    }
     748    if (err && maxw) {
     749      PRINTF
     750        ("Pass %i -- strange PTE at 0x%08x found for page index %i == 0x%08x:\n",
     751         pass, (unsigned) pte, i, i);
     752      PRINTF ("Reason: %s\n", buf);
     753      dumpPte (pte);
     754      warn++;
     755      maxw--;
     756    }
     757  }
     758  if (warn) {
     759    PRINTF ("%i errors found; currently %i entries marked, %i are valid\n",
     760            warn, m, v);
     761  }
     762  v += m;
     763  if (maxw && expected >= 0 && expected != v) {
     764    /* number of occupied slots not what they expected */
     765    PRINTF ("Wrong # of occupied slots detected during pass");
     766    PRINTF ("%i; should be %i (0x%x) is %i (0x%x)\n",
     767            pass, expected, (unsigned) expected, v, (unsigned) v);
     768    maxw--;
     769  }
     770  return v;
    746771}
    747772
     
    749774 * RETURNS: pte for EA or NULL if no entry was found.
    750775 */
    751 PTE
    752 triv121DumpPte(unsigned long ea)
    753 {
    754 PTE pte;
    755 
    756         pte=alreadyMapped(&pgTbl,TRIV121_121_VSID,ea);
    757 
    758         if (pte)
    759                 dumpPte(pte);
    760         return pte;
    761 }
    762 
     776APte
     777triv121DumpEa (unsigned long ea)
     778{
     779  APte pte;
     780
     781  pte =
     782    alreadyMapped (&pgTbl, pgTbl.active ? TRIV121_SEG_VSID : TRIV121_121_VSID,
     783                   ea);
     784
     785  if (pte)
     786    dumpPte (pte);
     787  return pte;
     788}
     789
     790APte
     791triv121FindPte (unsigned long vsid, unsigned long pi)
     792{
     793  return alreadyMapped (&pgTbl, vsid, pi);
     794}
     795
     796APte
     797triv121UnmapEa (unsigned long ea)
     798{
     799  unsigned32 flags;
     800  APte pte;
     801
     802  if (!pgTbl.active) {
     803    pte = alreadyMapped (&pgTbl, TRIV121_121_VSID, ea);
     804    if (pte)                    /* alreadyMapped checks for pte->v */
     805      pte->v = 0;
     806    return pte;
     807  }
     808
     809  pte = alreadyMapped (&pgTbl, TRIV121_SEG_VSID, ea);
     810
     811  if (!pte)
     812    return 0;
     813
     814  rtems_interrupt_disable (flags);
     815  pte->v = 0;
     816  do_dssall ();
     817  asm volatile ("       sync            \n\t"
     818                "       tlbie %0        \n\t"
     819                "       eieio           \n\t"
     820                "       tlbsync         \n\t"
     821                "       sync            \n\t"::"r" (ea));
     822  rtems_interrupt_enable (flags);
     823  return pte;
     824}
     825
     826/* A context synchronizing jump */
     827#define SYNC_LONGJMP(msr)                               \
     828        asm volatile(                                           \
     829                "       mtsrr1  %0                      \n\t"   \
     830                "       bl              1f                      \n\t"   \
     831                "1:     mflr    3                       \n\t"   \
     832                "       addi    3,3,1f-1b       \n\t"   \
     833                "       mtsrr0  3                       \n\t"   \
     834                "       rfi                                     \n\t"   \
     835                "1:                                             \n\t"   \
     836                :                                                               \
     837                :"r"(msr)                                               \
     838                :"3","lr")
     839
     840/* The book doesn't mention dssall when changing PTEs
     841 * but they require it for BAT changes and I guess
     842 * it makes sense in the case of PTEs as well.
     843 * Just do it to be on the safe side...
     844 */
     845static void
     846do_dssall ()
     847{
     848  /* Before changing BATs, 'dssall' must be issued.
     849   * We check MSR for MSR_VE and issue a 'dssall' if
     850   * MSR_VE is set hoping that
     851   *  a) on non-altivec CPUs MSR_VE reads as zero
     852   *  b) all altivec CPUs use the same bit
     853   */
     854  if (_read_MSR () & MSR_VE) {
     855    /* this construct is needed because we don't know
     856     * if this file is compiled with -maltivec.
     857     * (I plan to add altivec support outside of
     858     * RTEMS core and hence I'd rather not
     859     * rely on consistent compiler flags).
     860     */
     861#define DSSALL  0x7e00066c      /* dssall opcode */
     862    asm volatile ("     .long %0"::"i" (DSSALL));
     863#undef  DSSALL
     864  }
     865}
     866
     867APte
     868triv121ChangeEaAttributes (unsigned long ea, int wimg, int pp)
     869{
     870  APte pte;
     871  unsigned long msr;
     872
     873  if (!pgTbl.active) {
     874    pte = alreadyMapped (&pgTbl, TRIV121_121_VSID, ea);
     875    if (!pte)
     876      return 0;
     877    if (wimg > 0)
     878      pte->wimg = wimg;
     879    if (pp > 0)
     880      pte->pp = pp;
     881    return pte;
     882  }
     883
     884  pte = alreadyMapped (&pgTbl, TRIV121_SEG_VSID, ea);
     885
     886  if (!pte)
     887    return 0;
     888
     889  if (wimg < 0 && pp < 0)
     890    return pte;
     891
     892  asm volatile ("mfmsr %0":"=r" (msr));
     893
     894  /* switch MMU and IRQs off */
     895  SYNC_LONGJMP (msr & ~(MSR_EE | MSR_DR | MSR_IR));
     896
     897  pte->v = 0;
     898  do_dssall ();
     899  asm volatile ("sync");
     900  if (wimg >= 0)
     901    pte->wimg = wimg;
     902  if (pp >= 0)
     903    pte->pp = pp;
     904  asm volatile ("tlbie %0; eieio"::"r" (ea));
     905  pte->v = 1;
     906  asm volatile ("tlbsync; sync");
     907
     908  /* restore, i.e., switch MMU and IRQs back on */
     909  SYNC_LONGJMP (msr);
     910
     911  return pte;
     912}
     913
     914static void
     915pgtblChangePP (Triv121PgTbl pt, int pp)
     916{
     917  unsigned long n = pt->size >> LD_PG_SIZE;
     918  unsigned long b, i;
     919
     920  for (i = 0, b = (unsigned long) pt->base; i < n;
     921       i++, b += (1 << LD_PG_SIZE)) {
     922    triv121ChangeEaAttributes (b, -1, pp);
     923  }
     924}
     925
     926void
     927triv121MakePgTblRW ()
     928{
     929  pgtblChangePP (&pgTbl, TRIV121_PP_RW_PAGE);
     930}
     931
     932void
     933triv121MakePgTblRO ()
     934{
     935  pgtblChangePP (&pgTbl, TRIV121_PP_RO_PAGE);
     936}
     937
     938long
     939triv121DumpPte (APte pte)
     940{
     941  if (pte)
     942    dumpPte (pte);
     943  return 0;
     944}
     945
     946
     947#ifdef DEBUG
    763948/* Dump an entire PTEG */
    764949
    765950static void
    766 dumpPteg(unsigned long vsid, unsigned long pi, unsigned long hash)
    767 {
    768 PTE pte=ptegOf(&pgTbl,hash);
    769 int i;
    770         PRINTF("hash 0x%08x, pteg 0x%08x (vsid 0x%08x, pi 0x%08x)\n",
    771                         (unsigned)hash, (unsigned)pte,
    772                         (unsigned)vsid, (unsigned)pi);
    773         for (i=0; i<PTE_PER_PTEG; i++,pte++) {
    774                 PRINTF("pte 0x%08x is 0x%08x : 0x%08x\n",
    775                         (unsigned)pte,
    776                         (unsigned)*(unsigned long*)pte,
    777                         (unsigned)*(((unsigned long*)pte)+1));
    778         }
    779 }
    780  
     951dumpPteg (unsigned long vsid, unsigned long pi, unsigned long hash)
     952{
     953  APte pte = ptegOf (&pgTbl, hash);
     954  int i;
     955  PRINTF ("hash 0x%08x, pteg 0x%08x (vsid 0x%08x, pi 0x%08x)\n",
     956          (unsigned) hash, (unsigned) pte, (unsigned) vsid, (unsigned) pi);
     957  for (i = 0; i < PTE_PER_PTEG; i++, pte++) {
     958    PRINTF ("pte 0x%08x is 0x%08x : 0x%08x\n",
     959            (unsigned) pte,
     960            (unsigned) *(unsigned long *) pte,
     961            (unsigned) *(((unsigned long *) pte) + 1));
     962  }
     963}
     964#endif
     965
    781966/* Verify that a range of EAs is mapped the page table
     967 * (if vsid has one of the special values -- otherwise,
     968 * start/end are page indices).
    782969 *
    783970 * RETURNS: address of the first page for which no
     
    789976 */
    790977unsigned long
    791 triv121IsRangeMapped(unsigned long start, unsigned long end)
    792 {
    793         start&=~((1<<LD_PG_SIZE)-1);
    794         while (start < end) {
    795                 if (!alreadyMapped(&pgTbl,TRIV121_121_VSID,start))
    796                         return start;
    797                 start+=1<<LD_PG_SIZE;
    798         }
    799         return 0x0C0C; /* OKOK - not on a page boundary */
    800 }
    801 
    802 #endif
    803 
    804 
    805 #if defined(DEBUG_MAIN) || defined(DEBUG)
     978triv121IsRangeMapped (long vsid, unsigned long start, unsigned long end)
     979{
     980  start &= ~((1 << LD_PG_SIZE) - 1);
     981  while (start < end) {
     982    if (!alreadyMapped (&pgTbl, vsid, start))
     983      return start;
     984    start += 1 << LD_PG_SIZE;
     985  }
     986  return 0x0C0C;                /* OKOK - not on a page boundary */
     987}
     988
     989
    806990#include <stdlib.h>
    807991
    808992/* print a PTE */
    809993static void
    810 dumpPte(PTE pte)
    811 {
    812         if (0==((unsigned long)pte & ((1<<LD_PTEG_SIZE)-1)))
    813                 PRINTF("PTEG--");
    814         else
    815                 PRINTF("......");
    816         if (pte->v) {
    817                 PRINTF("VSID: 0x%08x H:%1i API: 0x%02x\n",
    818                                         pte->vsid, pte->h, pte->api);
    819                 PRINTF("      ");
    820                 PRINTF("RPN:  0x%08x WIMG: 0x%1x, (m %1i), pp: 0x%1x\n",
    821                                         pte->rpn, pte->wimg, pte->marked, pte->pp);
    822         } else {
    823                 PRINTF("xxxxxx\n");
    824                 PRINTF("      ");
    825                 PRINTF("xxxxxx\n");
    826         }
     994dumpPte (APte pte)
     995{
     996  if (0 == ((unsigned long) pte & ((1 << LD_PTEG_SIZE) - 1)))
     997    PRINTF ("PTEG--");
     998  else
     999    PRINTF ("......");
     1000  if (pte->v) {
     1001    PRINTF ("VSID: 0x%08x H:%1i API: 0x%02x\n", pte->vsid, pte->h, pte->api);
     1002    PRINTF ("      ");
     1003    PRINTF ("RPN:  0x%08x WIMG: 0x%1x, (m %1i), pp: 0x%1x\n",
     1004            pte->rpn, pte->wimg, pte->marked, pte->pp);
     1005  } else {
     1006    PRINTF ("xxxxxx\n");
     1007    PRINTF ("      ");
     1008    PRINTF ("xxxxxx\n");
     1009  }
    8271010}
    8281011
     
    8351018 */
    8361019int
    837 triv121PgTblDump(Triv121PgTbl pt, unsigned from, unsigned to)
    838 {
    839 int i;
    840 PTE     pte;
    841         PRINTF("Dumping PT [size 0x%08x == %i] at 0x%08x\n",
    842                         (unsigned)pt->size, (unsigned)pt->size, (unsigned)pt->base);
    843         if (from> pt->size>>LD_PTE_SIZE)
    844                 from=0;
    845         if (to  > pt->size>>LD_PTE_SIZE)
    846                 to=(pt->size>>LD_PTE_SIZE);
    847         for (i=from,pte=pt->base+from; i<(long)to; i++, pte++) {
    848                 dumpPte(pte);
    849         }
    850         return 0;
     1020triv121PgTblDump (Triv121PgTbl pt, unsigned from, unsigned to)
     1021{
     1022  int i;
     1023  APte pte;
     1024  PRINTF ("Dumping PT [size 0x%08x == %i] at 0x%08x\n",
     1025          (unsigned) pt->size, (unsigned) pt->size, (unsigned) pt->base);
     1026  if (from > pt->size >> LD_PTE_SIZE)
     1027    from = 0;
     1028  if (to > pt->size >> LD_PTE_SIZE)
     1029    to = (pt->size >> LD_PTE_SIZE);
     1030  for (i = from, pte = pt->base + from; i < (long) to; i++, pte++) {
     1031    dumpPte (pte);
     1032  }
     1033  return 0;
    8511034}
    8521035
     
    8571040
    8581041int
    859 main(int argc, char **argv)
    860 {
    861 unsigned long   base,start,numPages;
    862 unsigned long   size=1<<LD_DBG_PT_SIZE;
    863 Triv121PgTbl    pt;
    864 
    865         base=(unsigned long)malloc(size<<1);
    866 
    867         assert(base);
    868 
    869         /* align pt */
    870         base += size-1;
    871         base &= ~(size-1);
    872 
    873         assert(pt=triv121PgTblInit(base,LD_DBG_PT_SIZE));
    874 
    875         triv121PgTblDump(pt,(unsigned)-1, (unsigned)-1);
    876         do {
    877                 do {
    878                 PRINTF("Start Address:"); fflush(stdout);
    879                 } while (1!=scanf("%i",&start));
    880                 do {
    881                 PRINTF("# pages:"); fflush(stdout);
    882                 } while (1!=scanf("%i",&numPages));
    883         } while (TRIV121_MAP_SUCCESS==triv121PgTblMap(pt,TRIV121_121_VSID,start,numPages,
    884                                                         TRIV121_ATTR_IO_PAGE,2) &&
    885                         0==triv121PgTblDump(pt,(unsigned)-1,(unsigned)-1));
    886 }
    887 #endif
    888 #endif
     1042main (int argc, char **argv)
     1043{
     1044  unsigned long base, start, numPages;
     1045  unsigned long size = 1 << LD_DBG_PT_SIZE;
     1046  Triv121PgTbl pt;
     1047
     1048  base = (unsigned long) malloc (size << 1);
     1049
     1050  assert (base);
     1051
     1052  /* align pt */
     1053  base += size - 1;
     1054  base &= ~(size - 1);
     1055
     1056  assert (pt = triv121PgTblInit (base, LD_DBG_PT_SIZE));
     1057
     1058  triv121PgTblDump (pt, (unsigned) -1, (unsigned) -1);
     1059  do {
     1060    do {
     1061      PRINTF ("Start Address:");
     1062      fflush (stdout);
     1063    } while (1 != scanf ("%i", &start));
     1064    do {
     1065      PRINTF ("# pages:");
     1066      fflush (stdout);
     1067    } while (1 != scanf ("%i", &numPages));
     1068  } while (TRIV121_MAP_SUCCESS ==
     1069           triv121PgTblMap (pt, TRIV121_121_VSID, start, numPages,
     1070                            TRIV121_ATTR_IO_PAGE, 2)
     1071           && 0 == triv121PgTblDump (pt, (unsigned) -1, (unsigned) -1));
     1072}
     1073#endif
  • c/src/lib/libcpu/powerpc/mpc6xx/mmu/pte121.h

    rec58ea04 r1b1b43cc  
    1414 *    2) provide more effective-address space in case
    1515 *       the BATs are not enough
     16 *    3) allow 'alias' mappings. Such aliases can only use
     17 *       the upper bits of the VSID since VSID & 0xf and the
     18 *       PI are always mapped 1:1 to the RPN.
    1619 * LIMITATIONS:
    17  *    -  once activated, the page table cannot be changed
    1820 *    -  no PTE replacement (makes no sense in a real-time
    1921 *       environment, anyway) -> the page table just MUST
    2022 *       be big enough!.
    2123 *    -  only one page table supported.
    22  */
    23 
    24 /* Author: Till Straumann <strauman@slac.stanford.edu>, 4/2002 */
     24 *    -  no locking implemented. If multiple threads modify
     25 *       the page table, it is the user's responsibility to
     26 *       implement exclusive access.
     27 */
     28
     29/* Author: Till Straumann <strauman@slac.stanford.edu>, 4/2002 - 2004 */
     30
     31/* I don't include mmu.h here because it says it's derived from linux
     32 * and I want to avoid licensing problems
     33 */
    2534
    2635/* Abstract handle for a page table */
    2736typedef struct Triv121PgTblRec_ *Triv121PgTbl;
     37
     38/* A PTE entry */
     39typedef struct PTERec_ {
     40  volatile unsigned long v:1,    vsid:24, h:1, api: 6;
     41  volatile unsigned long rpn:20, pad: 3, r:1, c:1, wimg:4, marked:1, pp:2;
     42} PTERec, *APte;
    2843
    2944/* Initialize a trivial page table
     
    4257 *            it can still be corrupted by PCI bus masters
    4358 *            (like DMA engines, [VME] bridges etc.) and
    44  *                        even by this CPU if either the MMU is off
    45  *                        or if there is a DBAT mapping granting write
     59 *            even by this CPU if either the MMU is off
     60 *            or if there is a DBAT mapping granting write
    4661 *            access...
    4762 */
     
    5772 *          memory (assuming 'memsize' is a power of two):
    5873 *
    59  *      ldSize = triv121PgTblLdMinSize(memsize);
    60  *  memsize -= (1<<ldSize);     / * reduce memory available to RTEMS * /
     74 *  ldSize = triv121PgTblLdMinSize(memsize);
     75 *  memsize -= (1<<ldSize);  / * reduce memory available to RTEMS * /
    6176 *  pgTbl  = triv121PgTblInit(memsize,ldSize);
    6277 *
     
    8297long
    8398triv121PgTblMap(
    84                                 Triv121PgTbl  pgTbl,                    /* handle, returned by Init or Get */
    85 
    86                                 long          vsid,                             /* vsid for this mapping (contains topmost 4 bits of EA);
    87                                                                                                 *
    88                                                                                                 * NOTE: it is allowed to pass a VSID < 0 to tell this
    89                                                                                                 *       routine it should use a VSID corresponding to a
    90                                                                                                 *       1:1:1  effective - virtual - physical  mapping
    91                                                                                                 */
    92 
    93                                 unsigned long start,                    /* segment offset (lowermost 28 bits of EA) of address range
    94                                                                                                 *
    95                                                                                                 * NOTE: if VSID < 0 (TRIV121_121_VSID), 'start' is inter-
    96                                                                                                 *       preted as an effective address (EA), i.e. all 32
    97                                                                                                 *       bits are used - the most significant four going into
    98                                                                                                 *       to the VSID...
    99                                                                                                 */
    100 
    101                                 unsigned long numPages,                 /* number of pages to map */
    102 
    103                                 unsigned wimgAttr,                              /* 'wimg' attributes
    104                                                                                                 * (Write thru, cache Inhibit, coherent Memory,
    105                                                                                                 *  Guarded memory)
    106                                                                                                 */
    107 
    108                                 unsigned protection                             /* 'pp' access protection: Super      User
    109                                                                                                 *
    110                                                                                                 *   0                      r/w       none
    111                                                                                                 *   1                      r/w       ro   
    112                                                                                                 *   2                      r/w       r/w
    113                                                                                                 *   3                      ro        ro
    114                                                                                                 */
    115                                 );
    116 
    117 #define TRIV121_ATTR_W  8       
    118 #define TRIV121_ATTR_I  4
    119 #define TRIV121_ATTR_M  2
    120 #define TRIV121_ATTR_G  1
     99  Triv121PgTbl  pgTbl,     /* handle, returned by Init or Get */
     100
     101  long          vsid,      /* vsid for this mapping (contains topmost 4 bits of EA);
     102                            *
     103                            * NOTE: it is allowed to pass a VSID < 0 to tell this
     104                            *       routine it should use a VSID corresponding to a
     105                            *       1:1:1  effective - virtual - physical  mapping
     106                            */
     107
     108  unsigned long start,     /* segment offset (lowermost 28 bits of EA) of address range
     109                            *
     110                            * NOTE: if VSID < 0 (TRIV121_121_VSID), 'start' is inter-
     111                            *       preted as an effective address (EA), i.e. all 32
     112                            *       bits are used - the most significant four going into
     113                            *       to the VSID...
     114                            */
     115
     116  unsigned long numPages,  /* number of pages to map */
     117
     118  unsigned wimgAttr,       /* 'wimg' attributes
     119                            * (Write thru, cache Inhibit, coherent Memory,
     120                            *  Guarded memory)
     121                            */
     122
     123  unsigned protection      /* 'pp' access protection: Super      User
     124                            *
     125                            *   0                      r/w       none
     126                            *   1                      r/w       ro   
     127                            *   2                      r/w       r/w
     128                            *   3                      ro        ro
     129                            */
     130);
     131
     132#define TRIV121_ATTR_W  8
     133#define TRIV121_ATTR_I  4
     134#define TRIV121_ATTR_M  2
     135#define TRIV121_ATTR_G  1
    121136
    122137/* for I/O pages (e.g. PCI, VME addresses) use cache inhibited
    123138 * and guarded pages. RTM about the 'eieio' instruction!
    124139 */
    125 #define TRIV121_ATTR_IO_PAGE    (TRIV121_ATTR_I|TRIV121_ATTR_G)
    126 
    127 #define TRIV121_PP_RO_PAGE              (3)  /* read-only for everyone */
    128 #define TRIV121_PP_RW_PAGE              (2)  /* read-write for everyone */
    129 
    130 #define TRIV121_121_VSID                (-1) /* use 1:1 effective<->virtual address mapping */
    131 
    132 #define TRIV121_MAP_SUCCESS             (-1) /* triv121PgTblMap() returns this on SUCCESS */
     140#define TRIV121_ATTR_IO_PAGE    (TRIV121_ATTR_I|TRIV121_ATTR_G)
     141
     142#define TRIV121_PP_RO_PAGE      (1)  /* read-only for key = 1, unlocked by key=0 */
     143#define TRIV121_PP_RW_PAGE      (2)  /* read-write for key = 1/0                 */
     144
     145#define TRIV121_121_VSID        (-1) /* use 1:1 effective<->virtual address mapping */
     146#define TRIV121_SEG_VSID        (-2) /* lookup VSID in the segment register         */
     147
     148#define TRIV121_MAP_SUCCESS     (-1) /* triv121PgTblMap() returns this on SUCCESS */
    133149
    134150/* get a handle to the one and only page table
     
    149165/*
    150166 * Activate the page table:
    151  *      - set up the segment registers for a 1:1 effective <-> virtual address mapping,
     167 *  - set up the segment registers for a 1:1 effective <-> virtual address mapping,
    152168 *    give user and supervisor keys.
    153169 *  - set up the SDR1 register
     
    163179triv121PgTblActivate(Triv121PgTbl pgTbl);
    164180
     181/* Find the PTE for a EA and print its contents to stdout
     182 * RETURNS: pte for EA or NULL if no entry was found.
     183 */
     184APte
     185triv121DumpEa(unsigned long ea);
     186
     187/* Find and return a PTE for a vsid/pi combination
     188 * RETURNS: pte or NULL if no entry was found
     189 */
     190APte
     191triv121FindPte(unsigned long vsid, unsigned long pi);
     192
     193/*
     194 * Unmap an effective address
     195 *
     196 * RETURNS: pte that mapped the ea or NULL if no
     197 *          mapping existed.
     198 */
     199APte
     200triv121UnmapEa(unsigned long ea);
     201
     202/*
     203 * Change the WIMG and PP attributes of the page containing 'ea'
     204 *
     205 * NOTES:   The 'wimg' and 'pp' may be <0 to indicate that no
     206 *          change is desired.
     207 *
     208 * RETURNS: Pointer to modified PTE or NULL if 'ea' is not mapped.
     209 */
     210APte
     211triv121ChangeEaAttributes(unsigned long ea, int wimg, int pp);
     212
     213/* Make the whole page table writable
     214 * NOTES:   If the page table has not been initialized yet,
     215 *          this routine has no effect (i.e., after
     216 *          initialization the page table will still be read-only).
     217 */
     218void
     219triv121MakePgTblRW();
     220
     221/* Make the whole page table read-only
     222 */
     223void
     224triv121MakePgTblRO();
     225
     226/* Dump a pte to stdout */
     227long
     228triv121DumpPte(APte pte);
     229
    165230#endif
Note: See TracChangeset for help on using the changeset viewer.