source: rtems/c/src/lib/libcpu/powerpc/mpc6xx/mmu/pte121.c @ d49389a

4.104.114.84.95
Last change on this file since d49389a was d49389a, checked in by Joel Sherrill <joel.sherrill@…>, on 02/20/03 at 22:07:22

2003-02-20 Till Straumann <strauman@…>

PR 349/bsps

  • mpc6xx/exceptions/raw_exception.c, mpc6xx/mmu/bat.c, mpc6xx/mmu/pte121.c, shared/include/cpuIdent.c, shared/include/cpuIdent.h, shared/src/Makefile.am, shared/src/stack.c, shared/src/stackTrace.h, powerpc/registers.h:
    • undo improper 'fix' who broke mpc604r identification
    • fix: 7400 identification PVR value was wrong
    • enhance 'setdbat()' to switch OFF a given BAT if called with 0 size
    • fix: page table support bugfix
    • enhancement: provide routines to take and print stack trace snapshots
    • add definitions for HID1 and DABR SPRs
  • Property mode set to 100644
File size: 22.3 KB
RevLine 
[11f894cc]1/* $Id$ */
2
3/* Trivial page table setup for RTEMS
4 * Purpose: allow write protection of text/ro-data
5 *
6 * Author: Till Straumann <strauman@slac.stanford.edu>, 4/2002
7 */
8
9/* 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 */
13
14#ifdef  DEBUG_MAIN
15#undef  DEBUG           /* must not use these together with DEBUG_MAIN */
16#undef  DEBUG_EXC
17#endif
18
19/***************************** INCLUDE HEADERS ****************************/
20
21#ifndef DEBUG_MAIN
22#include <rtems.h>
23#include <rtems/bspIo.h>
[c0af822e]24#include <libcpu/cpuIdent.h>
[11f894cc]25#ifdef  DEBUG_EXC
[d49389a]26#include <bsp.h>
[11f894cc]27#include <bsp/vectors.h>
28#include <libcpu/raw_exception.h>
29#endif
30#endif
31
32#include <stdio.h>
33#include <assert.h>
[d5fa21ef]34#include <string.h>
[11f894cc]35
36#include "pte121.h"
37
38/************************** CONSTANT DEFINITIONS **************************/
39
40/* Base 2 logs of some sizes */
41
42#ifndef DEBUG_MAIN
43
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 */
51
52#else /* DEBUG_MAIN */
53
54/* 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 */
62
63#endif /* DEBUG_MAIN */
64
65/* Derived sizes */
66
67/* Size of a page index */
68#define LD_PI_SIZE              ((LD_SEG_SIZE) - (LD_PG_SIZE))
69
70/* Number of PTEs in a PTEG */
71#define PTE_PER_PTEG    (1<<((LD_PTEG_SIZE)-(LD_PTE_SIZE)))
72
73/* Segment register bits */
74#define KEY_SUP                 (1<<30) /* supervisor mode key */
75#define KEY_USR                 (1<<29) /* user mode key */
76
77/* The range of effective addresses to scan with 'tlbie'
78 * instructions in order to flush all TLBs.
79 * On the 750 and 7400, there are 128 two way I and D TLBs,
80 * indexed by EA[14:19]. Hence calling
81 *        tlbie rx
82 * where rx scans 0x00000, 0x01000, 0x02000, ... 0x3f000
83 * is sufficient to do the job
84 */
85#define NUM_TLB_PER_WAY 64 /* 750 and 7400 have 128 two way TLBs */
86#define FLUSH_EA_RANGE  (NUM_TLB_PER_WAY<<LD_PG_SIZE)
87
88/*************************** MACRO DEFINITIONS ****************************/
89
90/* Macros to split a (32bit) 'effective' address into
91 * VSID (virtual segment id) and PI (page index)
92 * using a 1:1 mapping of 'effective' to 'virtual'
93 * addresses.
94 *
95 * For 32bit addresses this looks like follows
96 * (each 'x' or '0' stands for a 'nibble' [4bits]):
97 *
98 *         32bit effective address (EA)
99 *
100 *              x x x x x x x x
101 *               |       |
102 *    0 0 0 0 0 x|x x x x|x x x
103 *       VSID    |  PI   |  PO (page offset)
104 *               |       |
105 */
106/* 1:1 VSID of an EA  */
107#define VSID121(ea) (((ea)>>LD_SEG_SIZE) & ((1<<(LD_PHYS_SIZE-LD_SEG_SIZE))-1))
108/* page index of an EA */
109#define PI121(ea)       (((ea)>>LD_PG_SIZE) & ((1<<LD_PI_SIZE)-1))
110
111
112/* Primary and secondary PTE hash functions */
113
114/* Compute the primary hash from a VSID and a PI */
115#define PTE_HASH1(vsid, pi) (((vsid)^(pi))&((1<<LD_HASH_SIZE)-1))
116
117/* Compute the secondary hash from a primary hash */
118#define PTE_HASH2(hash1) ((~(hash1))&((1<<LD_HASH_SIZE)-1))
119
120/* Extract the abbreviated page index (which is the
121 * part of the PI which does not go into the hash
122 * under all circumstances [10 bits to -> 6bit API])
123 */
124#define API(pi) ((pi)>>((LD_MIN_PT_SIZE)-(LD_PTEG_SIZE)))
125
126
127/* Horrible Macros */
[d49389a]128#ifdef __rtems__
[11f894cc]129/* must not use printf until multitasking is up */
130typedef void (*PrintF)(char *,...);
131static PrintF whatPrintf(void)
132{
133                return _Thread_Executing ?
134                                (PrintF)printf :
135                                printk;
136}
137
138#define PRINTF(args...) ((void)(whatPrintf())(args))
139#else
140#define PRINTF(args...) printf(args)
141#endif
142
143#ifdef DEBUG
144unsigned long
145triv121PgTblConsistency(Triv121PgTbl pt, int pass, int expect);
146
147static int consistencyPass=0;
148#define CONSCHECK(expect) triv121PgTblConsistency(&pgTbl,consistencyPass++,(expect))
149#else
150#define CONSCHECK(expect) do {} while (0)
151#endif
152
153/**************************** TYPE DEFINITIONS ****************************/
154
155/* A PTE entry */
156typedef struct PTERec_ {
157                unsigned long v:1,    vsid:24, h:1, api: 6;
158                unsigned long rpn:20, pad: 3, r:1, c:1, wimg:4, marked:1, pp:2;
159} PTERec, *PTE;
160
161/* internal description of a trivial page table */
162typedef struct Triv121PgTblRec_ {
163                PTE                             base;
164                unsigned long   size;
165                int                             active;
166} Triv121PgTblRec;
167
168
169/************************** FORWARD DECLARATIONS *************************/
170
171#ifdef DEBUG_EXC
172static void
173myhdl(BSP_Exception_frame* excPtr);
174#endif
175
176#if defined(DEBUG_MAIN) || defined(DEBUG)
177static void
178dumpPte(PTE pte);
179#endif
180
181#ifdef DEBUG
182static void
183dumpPteg(unsigned long vsid, unsigned long pi, unsigned long hash);
184unsigned long
185triv121IsRangeMapped(unsigned long start, unsigned long end);
186#endif
187
188/**************************** STATIC VARIABLES ****************************/
189
190/* dont malloc - we might have to use this before
191 * we have malloc or even RTEMS workspace available
192 */
193static Triv121PgTblRec pgTbl={0};
194
195#ifdef DEBUG_EXC
196static void *ohdl;                      /* keep a pointer to the original handler */
197#endif
198
199/*********************** INLINES & PRIVATE ROUTINES ***********************/
200
201/* compute the page table entry group (PTEG) of a hash */
202static inline PTE
203ptegOf(Triv121PgTbl pt, unsigned long hash)
204{
205        hash &= ((1<<LD_HASH_SIZE)-1);
206        return (PTE)(((unsigned long)pt->base) | ((hash<<LD_PTEG_SIZE) & (pt->size-1)));
207}
208
209/* see if a vsid/pi combination is already mapped
210 *
211 * RETURNS: PTE of mapping / NULL if none exists
212 *
213 * NOTE: a vsid<0 is legal and will tell this
214 *       routine that 'pi' is actually an EA to
215 *       be split into vsid and pi...
216 */
217static PTE
218alreadyMapped(Triv121PgTbl pt, long vsid, unsigned long pi)
219{
220int                             i;
221unsigned long   hash,api;
222PTE                             pte;
223
224        if (!pt->size)
225                return 0;
226
227        if (vsid<0) {
228                vsid=VSID121(pi);
229                pi=PI121(pi);
230        }
231
232        hash = PTE_HASH1(vsid,pi);
233        api=API(pi);
234        for (i=0, pte=ptegOf(pt,hash); i<PTE_PER_PTEG; i++,pte++)
235                if (pte->v && pte->vsid==vsid && pte->api==api && 0==pte->h)
236                        return pte;
237        /* try the secondary hash table */
238        hash = PTE_HASH2(hash);
239        for (i=0, pte=ptegOf(pt,hash); i<PTE_PER_PTEG; i++,pte++)
240                if (pte->v && pte->vsid==vsid && pte->api==api && 1==pte->h)
241                        return pte;
242        return 0;
243}
244
245/* find the first available slot for  vsid/pi
246 *
247 * NOTE: it is NOT legal to pass a vsid<0 / EA combination.
248 *
249 * RETURNS free slot with the 'marked' field set. The 'h'
250 *         field is set to 0 or one, depending on whether
251 *         the slot was allocated by using the primary or
252 *         the secondary hash, respectively.
253 */
254static PTE
255slotFor(Triv121PgTbl pt, unsigned long vsid, unsigned long pi)
256{
257int                             i;
258unsigned long   hash,api;
259PTE                             pte;
260
261        /* primary hash */
262        hash = PTE_HASH1(vsid,pi);
263        api=API(pi);
264        /* linear search thru all buckets for this hash */
265        for (i=0, pte=ptegOf(pt,hash); i<PTE_PER_PTEG; i++,pte++) {
266                if (!pte->v && !pte->marked) {
267                        /* found a free PTE; mark it as potentially used and return */
268                        pte->h=0;       /* found by the primary hash fn */
269                        pte->marked=1;
270                        return pte;
271                }
272        }
273
274#ifdef DEBUG
275        /* Strange: if the hash table was allocated big enough,
276         *          this should not happen (when using a 1:1 mapping)
277         *          Give them some information...
278         */
279        PRINTF("## First hash bucket full - ");
280        dumpPteg(vsid,pi,hash);
281#endif
282
283        hash = PTE_HASH2(hash);
284#ifdef DEBUG
285        PRINTF("   Secondary pteg is 0x%08x\n", (unsigned)ptegOf(pt,hash));
286#endif
287        for (i=0, pte=ptegOf(pt,hash); i<PTE_PER_PTEG; i++,pte++) {
288                if (!pte->v && !pte->marked) {
289                        /* mark this pte as potentially used */
290                        pte->marked=1;
291                        pte->h=1;
292                        return pte;
293                }
294        }
295#ifdef DEBUG
296        /* Even more strange - most likely, something is REALLY messed up */
297        PRINTF("## Second hash bucket full - ");
298        dumpPteg(vsid,pi,hash);
299#endif
300        return 0;
301}
302
303/* unmark all entries */
304static void
305unmarkAll(Triv121PgTbl pt)
306{
307unsigned long   n=pt->size / sizeof(PTERec);
308unsigned long   i;
309PTE                             pte;
310        for (i=0,pte=pt->base; i<n; i++,pte++)
311                pte->marked=0;
312
313}
314
315/* calculate the minimal size of a page/hash table
316 * to map a range of 'size' bytes in EA space.
317 *
318 * RETURNS: size in 'number of bits', i.e. the
319 *          integer part of LOGbase2(minsize)
320 *          is returned.
321 * NOTE:        G3/G4 machines need at least 16 bits
322 *          (64k).
323 */
324unsigned long
325triv121PgTblLdMinSize(unsigned long size)
326{
327unsigned long i;
328        /* round 'size' up to the next page boundary */
329        size += (1<<LD_PG_SIZE)-1;
330        size &= ~((1<<LD_PG_SIZE)-1);
331        /* divide by number of PTEs  and multiply
332         * by the size of a PTE.
333         */
334        size >>= LD_PG_SIZE - LD_PTE_SIZE;
335        /* find the next power of 2 >= size */
336        for (i=0; i<LD_PHYS_SIZE; i++) {
337                if ((1<<i) >= size)
338                        break;
339        }
340        /* pop up to the allowed minimum, if necessary */
341        if (i<LD_MIN_PT_SIZE)
342                        i=LD_MIN_PT_SIZE;
343        return i;
344}
345
346/* initialize a trivial page table of 2^ldSize bytes
347 * at 'base' in memory.
348 *
349 * RETURNS:     OPAQUE HANDLE (not the hash table address)
350 *          or NULL on failure.
351 */
352Triv121PgTbl
353triv121PgTblInit(unsigned long base, unsigned ldSize)
354{
355        if (pgTbl.size) {
356                /* already initialized */
357                return 0;
358        }
359
360        if (ldSize < LD_MIN_PT_SIZE)
361                return 0; /* too small */
362
363        if (base & ((1<<ldSize)-1))
364                return 0; /* misaligned */
365
[d49389a]366        /* This was tested on 604r, 750 and 7400.
367         * On other CPUs, verify that the TLB invalidation works
[11f894cc]368         * for a new CPU variant and that it has hardware PTE lookup/
369         * TLB replacement before adding it to this list.
370         *
371         * NOTE: The 603 features no hardware PTE lookup - and
372         *       hence the page tables should NOT be used.
373         *               Although lookup could be implemented in
374         *               software this is probably not desirable
375         *               as it could have an impact on hard realtime
376         *               performance, screwing deterministic latency!
377         *               (Could still be useful for debugging, though)
378         */
379        if      (       PPC_604         !=current_ppc_cpu &&
380                        PPC_604e        !=current_ppc_cpu &&
381                        PPC_604r        !=current_ppc_cpu &&
382                        PPC_750         !=current_ppc_cpu &&
383                        PPC_7400        !=current_ppc_cpu )
384                return 0;       /* unsupported by this CPU */
385
386        pgTbl.base=(PTE)base;
387        pgTbl.size=1<<ldSize;
388        /* clear all page table entries */
389        memset(pgTbl.base, 0, pgTbl.size);
390
391        CONSCHECK(0);
392
393        /* map the page table itself 'm' and 'readonly' */
394        if (triv121PgTblMap(&pgTbl,
395                                                TRIV121_121_VSID,
396                                                base,
397                                                (pgTbl.size >> LD_PG_SIZE),
398                                                TRIV121_ATTR_M,
399                                                TRIV121_PP_RO_PAGE) >= 0)
400                return 0;
401
402        CONSCHECK((pgTbl.size>>LD_PG_SIZE));
403
404        return &pgTbl;
405}
406
407/* return the handle of the (one and only) page table
408 * or NULL if none has been initialized yet.
409 */
410Triv121PgTbl
411triv121PgTblGet(void)
412{
413        return pgTbl.size ? &pgTbl : 0;
414}
415
416/* NOTE: this routine returns -1 on success;
417 *       on failure, the page table index for
418 *       which no PTE could be allocated is returned
419 *
420 * (Consult header about argument/return value
421 * description)
422 */
423long
424triv121PgTblMap(
425                                Triv121PgTbl    pt,
426                                long                    vsid,
427                                unsigned long   start,
428                                unsigned long   numPages,
429                                unsigned                attributes,
430                                unsigned                protection
431                                )
432{
433int                             i,pass;
434unsigned long   pi;
435PTE                             pte;
436
437        /* already activated - no change allowed */
438        if (pt->active)
439                        return -1;
440
441        if (vsid < 0) {
442                        /* use 1:1 mapping */
443                        vsid = VSID121(start);
444        }
445
446#ifdef DEBUG
447        PRINTF("Mapping %i (0x%x) pages at 0x%08x for VSID 0x%08x\n",
448                (unsigned)numPages, (unsigned)numPages,
449                (unsigned)start, (unsigned)vsid);
450#endif
451
452        /* map in two passes. During the first pass, we try
453         * to claim entries as needed. The 'slotFor()' routine
454         * will 'mark' the claimed entries without 'valid'ating
455         * them.
456         * If the mapping fails, all claimed entries are unmarked
457         * and we return the PI for which allocation failed.
458         *
459         * Once we know that the allocation would succeed, we
460         * do a second pass; during the second pass, the PTE
461         * is actually written.
462         *
463         */
464        for (pass=0; pass<2; pass++) {
465                /* check if we would succeed during the first pass */
466                for (i=0, pi=PI121(start); i<numPages; i++,pi++) {
467                        /* leave alone existing mappings for this EA */
468                        if (!alreadyMapped(pt, vsid, pi)) {
469                                if (!(pte=slotFor(pt, vsid, pi))) {
470                                        /* no free slot found for page index 'pi' */
471                                        unmarkAll(pt);
472                                        return pi;
473                                } else {
474                                        /* have a free slot; marked by slotFor() */
475                                        if (pass) {
476                                                /* second pass; do the real work */
477                                                pte->vsid=vsid;
478                                                /* H was set by slotFor() */
479                                                pte->api =API(pi);
480                                                /* set up 1:1 mapping */
481                                                pte->rpn =((((unsigned long)vsid)&((1<<(LD_PHYS_SIZE-LD_SEG_SIZE))-1))<<LD_PI_SIZE) | pi;
482                                                pte->wimg=attributes & 0xf;
483                                                pte->pp=protection&0x3;
484                                                /* mark it valid */
485                                                pte->v=1;
486                                                pte->marked=0;
487#ifdef DEBUG
488                                                /* add paranoia */
489                                                assert(alreadyMapped(pt, vsid, pi) == pte);
490#endif
491                                        }
492                                }
493                        }
494                }
495                unmarkAll(pt);
496        }
497#ifdef DEBUG
498        {
499        unsigned long failedat;
500        CONSCHECK(-1);
501        /* double check that the requested range is mapped */
502        failedat=triv121IsRangeMapped(start, start + (1<<LD_PG_SIZE)*numPages);
503        if (0x0C0C != failedat) {
504                PRINTF("triv121 mapping failed at 0x%08x\n",(unsigned)failedat);
505                return PI121(failedat);
506        }
507        }
508#endif
509        return TRIV121_MAP_SUCCESS; /* -1 !! */
510}
511
512unsigned long
513triv121PgTblSDR1(Triv121PgTbl pt)
514{
515        return (((unsigned long)pt->base) & ~(LD_MIN_PT_SIZE-1)) |
516                   ( ((pt->size-1) >> LD_MIN_PT_SIZE) &
517                         ((1<<(LD_HASH_SIZE-(LD_MIN_PT_SIZE-LD_PTEG_SIZE)))-1)
518                   );
519}
520
521void
522triv121PgTblActivate(Triv121PgTbl pt)
523{
524#ifndef DEBUG_MAIN
525unsigned long sdr1=triv121PgTblSDR1(pt);
526#endif
527        pt->active=1;
528
529#ifndef DEBUG_MAIN
530#ifdef DEBUG_EXC
531        /* install our exception handler */
532        ohdl=globalExceptHdl;
533        globalExceptHdl=myhdl;
534        __asm__ __volatile__ ("sync");
535#endif
536
537        /* This section of assembly code takes care of the
538         * following:
539         * - get MSR and switch interrupts + MMU off
540         *
541         * - load up the segment registers with a
542         *   1:1 effective <-> virtual mapping;
543         *   give user & supervisor keys
544         *
545         * - flush all TLBs;
546         *   NOTE: the TLB flushing code is probably
547         *         CPU dependent!
548         *
549         * - setup SDR1
550         *
551         * - restore original MSR
552         */
553        __asm__ __volatile(
554                "       mtctr   %0\n"
555                /* Get MSR and switch interrupts off - just in case.
556                 * Also switch the MMU off; the book
557                 * says that SDR1 must not be changed with either
558                 * MSR_IR or MSR_DR set. I would guess that it could
559                 * be safe as long as the IBAT & DBAT mappings override
560                 * the page table...
561                 */
562                "       mfmsr   %0\n"
563                "       andc    %6, %0, %6\n"
564                "       mtmsr   %6\n"
565                "       isync   \n"
566                /* set up the segment registers */
567                "       li              %6, 0\n"
568                "1:     mtsrin  %1, %6\n"
569                "       addis   %6, %6, 0x1000\n"       /* address next SR */
570                "       addi    %1, %1, 1\n"            /* increment VSID  */
571                "       bdnz    1b\n"
572                /* Now flush all TLBs, starting with the topmost index */
573                "       lis             %6, %2@h\n"     
574                "2:     addic.  %6, %6, -%3\n"          /* address the next one (decrementing) */
575                "       tlbie   %6\n"                           /* invalidate & repeat */
576                "       bgt             2b\n"
577                "       tlbsync\n"
578                "       sync\n"
579                /* set up SDR1 */
580                "   mtspr       %4, %5\n"
581                /* restore original MSR  */
582                "       mtmsr   %0\n"
583                "       isync   \n"
584                ::"r"(16), "b"(KEY_USR | KEY_SUP),
585                  "i"(FLUSH_EA_RANGE), "i"(1<<LD_PG_SIZE),
586                  "i"(SDR1), "r"(sdr1),
587                  "b"(MSR_EE | MSR_IR | MSR_DR)
588                : "ctr","cc");
589
590        /* At this point, BAT0 is probably still active; it's the
591         * caller's job to deactivate it...
592         */
593#endif
594}
595
596/**************************  DEBUGGING ROUTINES  *************************/
597
598/* Exception handler to catch page faults */
599#ifdef DEBUG_EXC
600
601#define BAT_VALID_BOTH  3       /* allow user + super access */
602
603static void
604myhdl(BSP_Exception_frame* excPtr)
605{
606if (3==excPtr->_EXC_number) {
607        unsigned long dsisr;
608
609        /* reactivate DBAT0 and read DSISR */
610        __asm__ __volatile__(
611                        "mfspr %0, %1\n"
612                        "ori    %0,%0,3\n"
613                        "mtspr %1, %0\n"
614                        "sync\n"
615                        "mfspr %0, %2\n"
616                        :"=r"(dsisr)
617                        :"i"(DBAT0U),"i"(DSISR),"i"(BAT_VALID_BOTH)
618        );
619
620        printk("Data Access Exception (DSI) # 3\n");
621        printk("Reactivated DBAT0 mapping\n");
622
623
624        printk("DSISR 0x%08x\n",dsisr);
625
626        printk("revectoring to prevent default handler panic().\n");
627        printk("NOTE: exception number %i below is BOGUS\n",
628                        ASM_DEC_VECTOR);
629        /* make this exception 'recoverable' for
630         * the default handler by faking a decrementer
631         * exception.
632         * Note that the default handler's message will be
633         * wrong about the exception number.
634         */
635        excPtr->_EXC_number = ASM_DEC_VECTOR;
636}
637/* now call the original handler */
638((void(*)())ohdl)(excPtr);
639}
640#endif
641
642
643#ifdef DEBUG
644
645/* test the consistency of the page table
646 *
647 * 'pass' is merely a number which will be printed
648 * by this routine, so the caller may give some
649 * context information.
650 *
651 * 'expected' is the number of valid (plus 'marked')
652 * entries the caller believes the page table should
653 * have. This routine complains if its count differs.
654 *
655 * It basically verifies that the topmost 20bits
656 * of all VSIDs as well as the unused bits are all
657 * zero. Then it counts all valid and all 'marked'
658 * entries, adding them up and comparing them to the
659 * 'expected' number of occupied slots.
660 *
661 * RETURNS: total number of valid plus 'marked' slots.
662 */
663unsigned long
664triv121PgTblConsistency(Triv121PgTbl pt, int pass, int expected)
665{
666PTE pte;
667int i;
668unsigned v,m;
669int warn=0;
670static int maxw=20;     /* mute after detecting this many errors */
671
672        PRINTF("Checking page table at 0x%08x (size %i==0x%x)\n",
673                        (unsigned)pt->base, (unsigned)pt->size, (unsigned)pt->size);
674
675        if (!pt->base || !pt->size) {
676                PRINTF("Uninitialized Page Table!\n");
677                return 0;
678        }
679
680        v=m=0;
[d49389a]681#if 1
682        /* 10/9/2002: I had machine checks crashing after this loop
683         *            terminated. Maybe caused by speculative loads
684         *            from beyond the valid memory area (since the
685         *            page hash table sits at the top of physical
686         *            memory).
687         *            Very bizarre - the other loops in this file
688         *            seem to be fine. Maybe there is a compiler bug??
689         *            For the moment, I let the loop run backwards...
690         *
691         *                        Also see the comment a couple of lines down.
692         */
693        for (i=pt->size/sizeof(PTERec)-1, pte=pt->base + i; i>=0; i--,pte--)
694#else
695        for (i=0, pte=pt->base; i<pt->size/sizeof(PTERec); i++,pte++)
696#endif
697        {
[11f894cc]698                int                             err=0;
699                char                    buf[500];
700                unsigned long   *lp=(unsigned long*)pte;
[d49389a]701#if 0
702                /* If I put this bogus while statement here (the body is
703                 * never reached), the original loop works OK
704                 */
705                while (pte >= pt->base + pt->size/sizeof(PTERec))
706                                /* never reached */;
707#endif
708
[11f894cc]709                if ( (*lp & (0xfffff0<<7)) || *(lp+1) & 0xe00 || (pte->v && pte->marked)) {
710                        /* check for vsid (without segment bits) == 0, unused bits == 0, valid && marked */
711                        sprintf(buf,"invalid VSID , unused bits or v && m");
712                        err=1;
713                } else {
714                        if (pte->v) v++;
715                        if (pte->marked) m++;
716                }
717                if (err && maxw) {
718                        PRINTF("Pass %i -- strange PTE at 0x%08x found for page index %i == 0x%08x:\n",
719                                pass,(unsigned)pte,i,i);
720                        PRINTF("Reason: %s\n",buf);
721                        dumpPte(pte);
722                        warn++;
723                        maxw--;
724                }
725        }
726        if (warn) {
727                PRINTF("%i errors found; currently %i entries marked, %i are valid\n",
728                        warn, m, v);
729        }
730        v+=m;
731        if (maxw && expected>=0 && expected != v) {
732                /* number of occupied slots not what they expected */
733                PRINTF("Wrong # of occupied slots detected during pass");
734            PRINTF("%i; should be %i (0x%x) is %i (0x%x)\n",
735                                pass, expected, (unsigned)expected, v, (unsigned)v);
736                maxw--;
737        }
738        return v;
739}
740
741/* Find the PTE for a EA and print its contents
742 * RETURNS: pte for EA or NULL if no entry was found.
743 */
744PTE
745triv121DumpPte(unsigned long ea)
746{
747PTE pte;
748
749        pte=alreadyMapped(&pgTbl,TRIV121_121_VSID,ea);
750
751        if (pte)
752                dumpPte(pte);
753        return pte;
754}
755
756/* Dump an entire PTEG */
757
758static void
759dumpPteg(unsigned long vsid, unsigned long pi, unsigned long hash)
760{
761PTE pte=ptegOf(&pgTbl,hash);
762int i;
763        PRINTF("hash 0x%08x, pteg 0x%08x (vsid 0x%08x, pi 0x%08x)\n",
764                        (unsigned)hash, (unsigned)pte,
765                        (unsigned)vsid, (unsigned)pi);
766        for (i=0; i<PTE_PER_PTEG; i++,pte++) {
767                PRINTF("pte 0x%08x is 0x%08x : 0x%08x\n",
768                        (unsigned)pte,
769                        (unsigned)*(unsigned long*)pte,
770                        (unsigned)*(((unsigned long*)pte)+1));
771        }
772}
773 
774/* Verify that a range of EAs is mapped the page table
775 *
776 * RETURNS: address of the first page for which no
777 *          PTE was found (i.e. page index * page size)
778 *         
779 *          ON SUCCESS, the special value 0x0C0C ("OKOK")
780 *          [which is not page aligned and hence is not
781 *          a valid page address].
782 */
783unsigned long
784triv121IsRangeMapped(unsigned long start, unsigned long end)
785{
786        start&=~((1<<LD_PG_SIZE)-1);
787        while (start < end) {
788                if (!alreadyMapped(&pgTbl,TRIV121_121_VSID,start))
789                        return start;
790                start+=1<<LD_PG_SIZE;
791        }
792        return 0x0C0C; /* OKOK - not on a page boundary */
793}
794
795#endif
796
797
798#if defined(DEBUG_MAIN) || defined(DEBUG)
799#include <stdlib.h>
800
801/* print a PTE */
802static void
803dumpPte(PTE pte)
804{
805        if (0==((unsigned long)pte & ((1<<LD_PTEG_SIZE)-1)))
806                PRINTF("PTEG--");
807        else
808                PRINTF("......");
809        if (pte->v) {
810                PRINTF("VSID: 0x%08x H:%1i API: 0x%02x\n",
811                                        pte->vsid, pte->h, pte->api);
812                PRINTF("      ");
813                PRINTF("RPN:  0x%08x WIMG: 0x%1x, (m %1i), pp: 0x%1x\n",
814                                        pte->rpn, pte->wimg, pte->marked, pte->pp);
815        } else {
816                PRINTF("xxxxxx\n");
817                PRINTF("      ");
818                PRINTF("xxxxxx\n");
819        }
820}
821
822
823/* dump page table entries from index 'from' to 'to'
824 * The special values (unsigned)-1 are allowed which
825 * cause the routine to dump the entire table.
826 *
827 * RETURNS 0
828 */
829int
830triv121PgTblDump(Triv121PgTbl pt, unsigned from, unsigned to)
831{
832int i;
833PTE     pte;
834        PRINTF("Dumping PT [size 0x%08x == %i] at 0x%08x\n",
835                        (unsigned)pt->size, (unsigned)pt->size, (unsigned)pt->base);
836        if (from> pt->size>>LD_PTE_SIZE)
837                from=0;
838        if (to  > pt->size>>LD_PTE_SIZE)
839                to=(pt->size>>LD_PTE_SIZE);
840        for (i=from,pte=pt->base+from; i<(long)to; i++, pte++) {
841                dumpPte(pte);
842        }
843        return 0;
844}
845
846
847#if defined(DEBUG_MAIN)
848
849#define LD_DBG_PT_SIZE  LD_MIN_PT_SIZE
850
851int
852main(int argc, char **argv)
853{
854unsigned long   base,start,numPages;
855unsigned long   size=1<<LD_DBG_PT_SIZE;
856Triv121PgTbl    pt;
857
858        base=(unsigned long)malloc(size<<1);
859
860        assert(base);
861
862        /* align pt */
863        base += size-1;
864        base &= ~(size-1);
865
866        assert(pt=triv121PgTblInit(base,LD_DBG_PT_SIZE));
867
868        triv121PgTblDump(pt,(unsigned)-1, (unsigned)-1);
869        do {
870                do {
871                PRINTF("Start Address:"); fflush(stdout);
872                } while (1!=scanf("%i",&start));
873                do {
874                PRINTF("# pages:"); fflush(stdout);
875                } while (1!=scanf("%i",&numPages));
876        } while (TRIV121_MAP_SUCCESS==triv121PgTblMap(pt,TRIV121_121_VSID,start,numPages,
877                                                        TRIV121_ATTR_IO_PAGE,2) &&
878                        0==triv121PgTblDump(pt,(unsigned)-1,(unsigned)-1));
879}
880#endif
881#endif
Note: See TracBrowser for help on using the repository browser.