Ticket #213: ppc7400.diff

File ppc7400.diff, 49.9 KB (added by strauman, on 12/03/06 at 13:31:13)

ppc7400.diff

Line 
1This patch (against rtems-ss-20020301) adds
2several enhancements to libcpu/powerpc:
3
4Author: Till Straumann <strauman@slac.stanford.edu>, 3/2002
5
6- support for the MPC74000 (AKA G4); there is no
7  AltiVec support yet, however.
8
9- the cache flushing assembly code uses
10  hardware-flush on the G4. Also, a couple
11  of hardcoded numerical values were replaced
12  by more readable symbolic constants.
13
14- extended interrupt-disabled code section
15  so enclose the entire cache flush/invalidate
16  procedure (as recommended by the book). This
17  is not (latency) critical as it is only used by
18  init code but prevents possible corruption.
19
20- Trivial page table support as been added.
21  (1:1 effective-virtual-physical address mapping)
22  (useful only on CPUs which feature
23  hardware TLB replacement, i.e. >604).
24  This allows for write-protecting memory
25  regions, e.g. text/ro-data which makes
26  catching corruptors a lot easier. It also
27  frees one DBAT/IBAT and gives more flexibility
28  for setting up address maps :-)
29
30- setdbat() allows changing BAT0 also
31  (since the BSP may use a page table, BAT0
32  could be available...).
33
34- asm_setdbatX() violated the SVR ABI by using
35  r20 as a scratch register; changed for r0
36
37- according to the book, a context synchronizing
38  instruction is necessary prior to and after
39  changing a DBAT -> isync added
40
41Index: c/src/exec/score/cpu/powerpc/rtems/score/ppc.h
42===================================================================
43RCS file: /afs/slac/g/spear/cvsrep/rtems/src/c/src/exec/score/cpu/powerpc/rtems/score/ppc.h,v
44retrieving revision 1.1.1.1
45retrieving revision 1.2
46diff -c -r1.1.1.1 -r1.2
47*** c/src/exec/score/cpu/powerpc/rtems/score/ppc.h      2002/03/07 01:51:21     1.1.1.1
48--- c/src/exec/score/cpu/powerpc/rtems/score/ppc.h      2002/03/07 03:21:00     1.2
49***************
50*** 278,283 ****
51--- 278,291 ----
52  #define PPC_I_CACHE           16384
53  #define PPC_D_CACHE           16384
54 
55+ #elif defined(mpc7400)
56+
57+ #define CPU_MODEL_NAME  "PowerPC 7400"
58+
59+ #define PPC_ALIGNMENT         8
60+ #define PPC_I_CACHE           32768
61+ #define PPC_D_CACHE           32768
62+
63  #elif defined(mpc8260)
64  /*
65   *  Added by Andy Dachs <a.dachs@sstl.co.uk> 23/11/2000
66Index: c/src/lib/libcpu/powerpc/configure.ac
67===================================================================
68RCS file: /afs/slac/g/spear/cvsrep/rtems/src/c/src/lib/libcpu/powerpc/configure.ac,v
69retrieving revision 1.1.1.2
70retrieving revision 1.2
71diff -c -r1.1.1.2 -r1.2
72*** c/src/lib/libcpu/powerpc/configure.ac       2001/12/15 00:16:04     1.1.1.2
73--- c/src/lib/libcpu/powerpc/configure.ac       2002/03/27 21:11:08     1.2
74***************
75*** 28,33 ****
76--- 28,34 ----
77  RTEMS_CHECK_BSP_CACHE(RTEMS_BSP)
78 
79  AM_CONDITIONAL(shared, test "$RTEMS_CPU_MODEL" = "mpc750" \
80+ || test "$RTEMS_CPU_MODEL" = "mpc7400" \
81  || test "$RTEMS_CPU_MODEL" = "ppc603e" \
82  || test "$RTEMS_CPU_MODEL" = "mpc604" \
83  || test "$RTEMS_CPU_MODEL" = "mpc6xx" \
84***************
85*** 40,45 ****
86--- 41,47 ----
87  AM_CONDITIONAL(mpc505, test "$RTEMS_CPU_MODEL" = "mpc505")
88  AM_CONDITIONAL(mpc6xx, test "$RTEMS_CPU_MODEL" = "mpc6xx" \
89  || test "$RTEMS_CPU_MODEL" = "mpc604" \
90+ || test "$RTEMS_CPU_MODEL" = "mpc7400" \
91  || test "$RTEMS_CPU_MODEL" = "mpc750" )
92  AM_CONDITIONAL(mpc8xx, test "$RTEMS_CPU_MODEL" = "mpc8xx" \
93  || test "$RTEMS_CPU_MODEL" = "mpc821" \
94Index: c/src/lib/libcpu/powerpc/mpc6xx/exceptions/raw_exception.c
95===================================================================
96RCS file: /afs/slac/g/spear/cvsrep/rtems/src/c/src/lib/libcpu/powerpc/mpc6xx/exceptions/raw_exception.c,v
97retrieving revision 1.1.1.1
98retrieving revision 1.2
99diff -c -r1.1.1.1 -r1.2
100*** c/src/lib/libcpu/powerpc/mpc6xx/exceptions/raw_exception.c  2001/12/14 22:52:52     1.1.1.1
101--- c/src/lib/libcpu/powerpc/mpc6xx/exceptions/raw_exception.c  2001/12/14 23:52:11     1.2
102***************
103*** 114,119 ****
104--- 114,120 ----
105  int mpc60x_vector_is_valid(rtems_vector vector)
106  {
107       switch (current_ppc_cpu) {
108+       case PPC_7400:
109          case PPC_750:
110              if (!mpc750_vector_is_valid(vector)) {
111                  return 0;
112Index: c/src/lib/libcpu/powerpc/mpc6xx/mmu/Makefile.am
113===================================================================
114RCS file: /afs/slac/g/spear/cvsrep/rtems/src/c/src/lib/libcpu/powerpc/mpc6xx/mmu/Makefile.am,v
115retrieving revision 1.1.1.1
116retrieving revision 1.2
117diff -c -r1.1.1.1 -r1.2
118*** c/src/lib/libcpu/powerpc/mpc6xx/mmu/Makefile.am     2001/12/14 22:52:53     1.1.1.1
119--- c/src/lib/libcpu/powerpc/mpc6xx/mmu/Makefile.am     2002/04/16 21:15:43     1.2
120***************
121*** 6,18 ****
122 
123  PGM = $(ARCH)/mmu.rel
124 
125! C_FILES = bat.c
126 
127  S_FILES = mmuAsm.S
128 
129  include_libcpudir = $(includedir)/libcpu
130 
131! include_libcpu_HEADERS = bat.h
132 
133  mmu_rel_OBJECTS = $(C_FILES:%.c=$(ARCH)/%.o) $(S_FILES:%.S=$(ARCH)/%.o)
134 
135--- 6,18 ----
136 
137  PGM = $(ARCH)/mmu.rel
138 
139! C_FILES = bat.c pte121.c
140 
141  S_FILES = mmuAsm.S
142 
143  include_libcpudir = $(includedir)/libcpu
144 
145! include_libcpu_HEADERS = bat.h pte121.h
146 
147  mmu_rel_OBJECTS = $(C_FILES:%.c=$(ARCH)/%.o) $(S_FILES:%.S=$(ARCH)/%.o)
148 
149***************
150*** 39,44 ****
151 
152  .PRECIOUS: $(PGM)
153 
154! EXTRA_DIST = bat.c bat.h mmuAsm.S
155 
156  include $(top_srcdir)/../../../../../automake/local.am
157--- 39,44 ----
158 
159  .PRECIOUS: $(PGM)
160 
161! EXTRA_DIST = bat.c bat.h mmuAsm.S pte121.c pte121.h
162 
163  include $(top_srcdir)/../../../../../automake/local.am
164Index: c/src/lib/libcpu/powerpc/mpc6xx/mmu/bat.c
165===================================================================
166RCS file: /afs/slac/g/spear/cvsrep/rtems/src/c/src/lib/libcpu/powerpc/mpc6xx/mmu/bat.c,v
167retrieving revision 1.1.1.1
168retrieving revision 1.2
169diff -c -r1.1.1.1 -r1.2
170*** c/src/lib/libcpu/powerpc/mpc6xx/mmu/bat.c   2001/12/14 22:52:53     1.1.1.1
171--- c/src/lib/libcpu/powerpc/mpc6xx/mmu/bat.c   2002/04/12 00:23:45     1.2
172***************
173*** 55,60 ****
174--- 55,61 ----
175    bat_addrs[bat_index].limit = virt + ((bl + 1) << 17) - 1;
176    bat_addrs[bat_index].phys = phys;
177    switch (bat_index) {
178+   case 0 : asm_setdbat1(bat.word[0], bat.word[1]); break;
179    case 1 : asm_setdbat1(bat.word[0], bat.word[1]); break;
180    case 2 : asm_setdbat2(bat.word[0], bat.word[1]); break;
181    case 3 : asm_setdbat3(bat.word[0], bat.word[1]); break;
182Index: c/src/lib/libcpu/powerpc/mpc6xx/mmu/mmuAsm.S
183===================================================================
184RCS file: /afs/slac/g/spear/cvsrep/rtems/src/c/src/lib/libcpu/powerpc/mpc6xx/mmu/mmuAsm.S,v
185retrieving revision 1.1.1.1
186retrieving revision 1.7
187diff -c -r1.1.1.1 -r1.7
188*** c/src/lib/libcpu/powerpc/mpc6xx/mmu/mmuAsm.S        2001/12/14 22:52:53     1.1.1.1
189--- c/src/lib/libcpu/powerpc/mpc6xx/mmu/mmuAsm.S        2002/05/02 22:29:20     1.7
190***************
191*** 12,17 ****
192--- 12,18 ----
193   *  found in found in the file LICENSE in this distribution or at
194   *  http://www.OARcorp.com/rtems/license.html.
195   *   
196+  *  T. Straumann - 11/2001: added support for 7400 (no AltiVec yet)
197   */
198 
199  #include <libcpu/cpu.h>
200***************
201*** 19,67 ****
202  #include <rtems/score/targopts.h>
203  #include "asm.h"
204 
205  /*
206   * Each setdbat routine start by invalidating the DBAT as some
207   * proc (604e) request the valid bit set to 0 before accepting
208   * to write in BAT
209   */
210 
211        .globl  asm_setdbat1
212        .type   asm_setdbat1,@function
213  asm_setdbat1:
214!       li      r20,0
215!       SYNC
216!       mtspr   DBAT1U,r20
217!       mtspr   DBAT1L,r20
218!       SYNC
219        mtspr DBAT1L, r4
220        mtspr DBAT1U, r3
221!       SYNC
222        blr
223 
224        .globl  asm_setdbat2
225        .type   asm_setdbat2,@function
226  asm_setdbat2:
227!       li      r20,0
228!       SYNC
229!       mtspr   DBAT2U,r20
230!       mtspr   DBAT2L,r20
231!       SYNC
232        mtspr DBAT2L, r4
233        mtspr DBAT2U, r3
234!       SYNC
235        blr
236 
237        .globl  asm_setdbat3
238        .type   asm_setdbat3,@function
239  asm_setdbat3:
240!       li      r20,0
241!       SYNC
242!       mtspr   DBAT3U,r20
243!       mtspr   DBAT3L,r20
244!       SYNC
245        mtspr DBAT3L, r4
246        mtspr DBAT3U, r3
247!       SYNC
248        blr
249               
250        .globl L1_caches_enables
251--- 20,127 ----
252  #include <rtems/score/targopts.h>
253  #include "asm.h"
254 
255+ /* Unfortunately, the CPU types defined in cpu.h are
256+  * an 'enum' type and hence not available :-(
257+  */
258+ #define PPC_601   0x1
259+ #define PPC_603   0x3
260+ #define PPC_604   0x4
261+ #define PPC_603e  0x6
262+ #define PPC_603ev 0x7
263+ #define PPC_750   0x8
264+ #define PPC_604e  0x9
265+ #define PPC_604r  0xA
266+ #define PPC_7400  0xC
267+ #define PPC_620   0x16
268+ #define PPC_860   0x50
269+ #define PPC_821   PPC_860
270+ #define PPC_8260  0x81
271+
272+ /* ALTIVEC instructions (not recognized by off-the shelf gcc yet) */
273+ #define DSSALL        .long   0x7e00066c              /* DSSALL altivec instruction opcode */
274+
275+ /* A couple of defines to make the code more readable */
276+ #define CACHE_LINE_SIZE 32
277+
278+ #ifndef MSSCR0
279+ #define MSSCR0   1014
280+ #else
281+ #warning MSSCR0 seems to be known, update __FILE__
282+ #endif
283+
284+ #define DL1HWF        (1<<(31-8))
285+ #define L2HWF (1<<(31-20))
286+
287+
288+
289  /*
290   * Each setdbat routine start by invalidating the DBAT as some
291   * proc (604e) request the valid bit set to 0 before accepting
292   * to write in BAT
293   */
294 
295+       .globl  asm_setdbat0
296+       .type   asm_setdbat0,@function
297+ asm_setdbat0:
298+       li      r0,0
299+       sync
300+       isync
301+       mtspr   DBAT0U,r0
302+       mtspr   DBAT0L,r0
303+       sync
304+       isync
305+       mtspr DBAT0L, r4
306+       mtspr DBAT0U, r3
307+       sync
308+       isync
309+       blr
310+
311        .globl  asm_setdbat1
312        .type   asm_setdbat1,@function
313  asm_setdbat1:
314!       li      r0,0
315!       sync
316!       isync
317!       mtspr   DBAT1U,r0
318!       mtspr   DBAT1L,r0
319!       sync
320!       isync
321        mtspr DBAT1L, r4
322        mtspr DBAT1U, r3
323!       sync
324!       isync
325        blr
326 
327        .globl  asm_setdbat2
328        .type   asm_setdbat2,@function
329  asm_setdbat2:
330!       li      r0,0
331!       sync
332!       isync
333!       mtspr   DBAT2U,r0
334!       mtspr   DBAT2L,r0
335!       sync
336!       isync
337        mtspr DBAT2L, r4
338        mtspr DBAT2U, r3
339!       sync
340!       isync
341        blr
342 
343        .globl  asm_setdbat3
344        .type   asm_setdbat3,@function
345  asm_setdbat3:
346!       li      r0,0
347!       sync
348!       isync
349!       mtspr   DBAT3U,r0
350!       mtspr   DBAT3L,r0
351!       sync
352!       isync
353        mtspr DBAT3L, r4
354        mtspr DBAT3U, r3
355!       sync
356!       isync
357        blr
358               
359        .globl L1_caches_enables
360***************
361*** 73,79 ****
362         */
363        mfspr   r9,PVR
364        rlwinm  r9,r9,16,16,31
365!       cmpi    0,r9,1
366        beq     4f                      /* not needed for 601 */
367        mfspr   r11,HID0
368        andi.   r0,r11,HID0_DCE
369--- 133,139 ----
370         */
371        mfspr   r9,PVR
372        rlwinm  r9,r9,16,16,31
373!       cmpi    0,r9,PPC_601
374        beq     4f                      /* not needed for 601 */
375        mfspr   r11,HID0
376        andi.   r0,r11,HID0_DCE
377***************
378*** 88,99 ****
379        mtspr   HID0,r11                /* enable caches */
380        sync
381        isync
382!       cmpi    0,r9,4                  /* check for 604 */
383!       cmpi    1,r9,9                  /* or 604e */
384!       cmpi    2,r9,10                 /* or mach5 */
385        cror    2,2,6
386        cror    2,2,10
387        bne     4f
388        ori     r11,r11,HID0_SIED|HID0_BHTE /* for 604[e], enable */
389        bne     2,5f
390        ori     r11,r11,HID0_BTCD
391--- 148,166 ----
392        mtspr   HID0,r11                /* enable caches */
393        sync
394        isync
395!       cmpi    0,r9,PPC_604    /* check for 604 */
396!       cmpi    1,r9,PPC_604e   /* or 604e */
397!       cmpi    2,r9,PPC_604r   /* or mach5 */
398        cror    2,2,6
399        cror    2,2,10
400+       cmpi    1,r9,PPC_750    /* or 750 */
401+       cror    2,2,6
402+       cmpi    1,r9,PPC_7400   /* or 7400 */
403+       bne     3f
404+       ori     r11,r11,HID0_BTIC       /* enable branch tgt cache on 7400 */
405+ 3:    cror    2,2,6
406        bne     4f
407+       /* on 7400 SIED is actually SGE (store gathering enable) */
408        ori     r11,r11,HID0_SIED|HID0_BHTE /* for 604[e], enable */
409        bne     2,5f
410        ori     r11,r11,HID0_BTCD
411***************
412*** 104,116 ****
413        .globl get_L2CR
414        .type  get_L2CR, @function     
415  get_L2CR:     
416!       /* Make sure this is a 750 chip */
417        mfspr   r3,PVR
418        rlwinm  r3,r3,16,16,31
419!       cmplwi  r3,0x0008
420        li      r3,0
421!       bnelr
422       
423        /* Return the L2CR contents */
424        mfspr   r3,L2CR
425        blr
426--- 171,187 ----
427        .globl get_L2CR
428        .type  get_L2CR, @function     
429  get_L2CR:     
430!       /* Make sure this is a > 750 chip */
431        mfspr   r3,PVR
432        rlwinm  r3,r3,16,16,31
433!       cmplwi  r3,PPC_750      /* it's a 750 */
434!       beq     1f
435!       cmplwi  r3,PPC_7400     /* it's a 7400 */
436!       beq     1f
437        li      r3,0
438!       blr
439       
440+ 1:
441        /* Return the L2CR contents */
442        mfspr   r3,L2CR
443        blr
444***************
445*** 147,157 ****
446         *the L2 cache instead of to main memory.
447         */
448       
449!       /* Make sure this is a 750 chip */
450!       mfspr   r4,PVR
451!       rlwinm  r4,r4,16,16,31
452!       cmplwi  r4,0x0008
453        beq     thisIs750
454        li      r3,-1
455        blr
456       
457--- 218,230 ----
458         *the L2 cache instead of to main memory.
459         */
460       
461!       /* Make sure this is a > 750 chip */
462!       mfspr   r0,PVR
463!       rlwinm  r0,r0,16,16,31
464!       cmplwi  r0,PPC_750
465        beq     thisIs750
466+       cmplwi  r0,PPC_7400
467+       beq     thisIs750
468        li      r3,-1
469        blr
470       
471***************
472*** 162,214 ****
473       
474        /* See if we want to perform a global inval this time. */
475        rlwinm  r6,r3,0,10,10           /* r6 contains the new invalidate bit */
476!       rlwinm. r5,r3,0,0,0             /* r5 contains the new enable bit */
477        rlwinm  r3,r3,0,11,9            /* Turn off the invalidate bit */
478        rlwinm  r3,r3,0,1,31            /* Turn off the enable bit */
479!       or      r3,r3,r4                /* Keep the enable bit the same as it was for now. */
480!       bne     dontDisableCache        /* Only disable the cache if L2CRApply has the enable bit off */
481 
482  disableCache:
483        /* Disable the cache.  First, we turn off data relocation. */
484!       mfmsr   r7
485!       rlwinm  r4,r7,0,28,26           /* Turn off DR bit */
486!       rlwinm  r4,r4,0,17,15           /* Turn off EE bit - an external exception while we are flushing
487!                                          the cache is fatal (comment this line and see!) */
488!       sync
489        mtmsr   r4
490!       sync
491       
492        /*
493                Now, read the first 2MB of memory to put new data in the cache.
494                (Actually we only need the size of the L2 cache plus
495                the size of the L1 cache, but 2MB will cover everything just to be safe).
496        */
497!       lis     r4,0x0001
498        mtctr   r4
499!       li      r4,0
500  loadLoop:
501        lwzx    r0,r0,r4
502!       addi    r4,r4,0x0020            /* Go to start of next cache line */
503        bdnz    loadLoop
504       
505        /* Now, flush the first 2MB of memory */
506!       lis     r4,0x0001
507        mtctr   r4
508!       li      r4,0
509        sync
510  flushLoop:
511        dcbf    r0,r4
512!       addi    r4,r4,0x0020    /* Go to start of next cache line */
513        bdnz    flushLoop
514       
515        /* Turn off the L2CR enable bit. */
516        rlwinm  r3,r3,0,1,31
517       
518-       /* Reenable data relocation. */
519-       sync
520-       mtmsr   r7
521-       sync
522-       
523  dontDisableCache:
524        /* Set up the L2CR configuration bits */
525        sync
526--- 235,308 ----
527       
528        /* See if we want to perform a global inval this time. */
529        rlwinm  r6,r3,0,10,10           /* r6 contains the new invalidate bit */
530!       rlwinm. r5,r3,0,0,0                     /* r5 contains the new enable bit */
531        rlwinm  r3,r3,0,11,9            /* Turn off the invalidate bit */
532        rlwinm  r3,r3,0,1,31            /* Turn off the enable bit */
533!       or              r3,r3,r4                        /* Keep the enable bit the same as it was for now. */
534!       mfmsr   r7                                      /* shut off interrupts around critical flush/invalidate sections */
535!       rlwinm  r4,r7,0,17,15           /* Turn off EE bit - an external exception while we are flushing
536!                                                                  the cache is fatal (comment this line and see!) */
537!       mtmsr   r4
538!       bne             dontDisableCache        /* Only disable the cache if L2CRApply has the enable bit off */
539 
540+       cmplwi  r0,PPC_7400                     /* > 7400 ? */
541+       bne             disableCache            /* use traditional method */
542+
543+       /* On the 7400, they recommend using the hardware flush feature */
544+       DSSALL                                          /* stop all data streams */
545+       sync
546+       /* we wouldn't have to flush L1, but for sake of consistency with the other code we do it anyway */
547+       mfspr   r4, MSSCR0
548+       oris    r4, r4, DL1HWF@h
549+       mtspr   MSSCR0, r4
550+       sync
551+       /* L1 flushed */
552+       mfspr   r4, L2CR
553+       ori             r4, r4, L2HWF
554+       mtspr   L2CR, r4
555+       sync
556+       /* L2 flushed */
557+       b               flushDone
558+
559  disableCache:
560        /* Disable the cache.  First, we turn off data relocation. */
561!       rlwinm  r4,r4,0,28,26           /* Turn off DR bit */
562        mtmsr   r4
563!       isync                                           /* make sure memory accesses have completed */
564       
565        /*
566                Now, read the first 2MB of memory to put new data in the cache.
567                (Actually we only need the size of the L2 cache plus
568                the size of the L1 cache, but 2MB will cover everything just to be safe).
569        */
570!       lis             r4,0x0001
571        mtctr   r4
572!       li              r4,0
573  loadLoop:
574        lwzx    r0,r0,r4
575!       addi    r4,r4,CACHE_LINE_SIZE   /* Go to start of next cache line */
576        bdnz    loadLoop
577       
578        /* Now, flush the first 2MB of memory */
579!       lis             r4,0x0001
580        mtctr   r4
581!       li              r4,0
582        sync
583  flushLoop:
584        dcbf    r0,r4
585!       addi    r4,r4,CACHE_LINE_SIZE   /* Go to start of next cache line */
586        bdnz    flushLoop
587+       sync
588+
589+       rlwinm  r4,r7,0,17,15           /* still mask EE but reenable data relocation */
590+       mtmsr   r4
591+       isync
592+
593+ flushDone:
594       
595        /* Turn off the L2CR enable bit. */
596        rlwinm  r3,r3,0,1,31
597       
598  dontDisableCache:
599        /* Set up the L2CR configuration bits */
600        sync
601***************
602*** 220,229 ****
603        /* Perform a global invalidation */
604        oris    r3,r3,0x0020
605        sync
606!       mtspr   1017,r3
607        sync
608! invalCompleteLoop:                    /* Wait for the invalidation to complete */
609!       mfspr   r3,1017
610        rlwinm. r4,r3,0,31,31
611        bne     invalCompleteLoop
612       
613--- 314,323 ----
614        /* Perform a global invalidation */
615        oris    r3,r3,0x0020
616        sync
617!       mtspr   L2CR,r3
618        sync
619! invalCompleteLoop:                            /* Wait for the invalidation to complete */
620!       mfspr   r3,L2CR
621        rlwinm. r4,r3,0,31,31
622        bne     invalCompleteLoop
623       
624***************
625*** 233,238 ****
626--- 327,334 ----
627        sync
628       
629  noInval:
630+       /* re-enable interrupts, i.e. restore original MSR */
631+       mtmsr   r7                                      /* (no sync needed) */
632        /* See if we need to enable the cache */
633        cmplwi  r5,0
634        beqlr
635Index: c/src/lib/libcpu/powerpc/mpc6xx/mmu/pte121.c
636===================================================================
637RCS file: pte121.c
638diff -N pte121.c
639*** /dev/null   Thu Aug 24 02:00:32 2000
640--- /tmp/cvsMH6ZTw      Sun May  5 11:22:45 2002
641***************
642*** 0 ****
643--- 1,856 ----
644+ /* $Id: pte121.c,v 1.1 2002/04/16 21:15:42 till Exp $ */
645+
646+ /* Trivial page table setup for RTEMS
647+  * Purpose: allow write protection of text/ro-data
648+  *
649+  * Author: Till Straumann <strauman@slac.stanford.edu>, 4/2002
650+  */
651+
652+ /* Chose debugging options */
653+ #undef  DEBUG_MAIN    /* create a standalone (host) program for basic testing */
654+ #undef  DEBUG         /* target debugging and consistency checking */
655+ #undef  DEBUG_EXC     /* add exception handler which reenables BAT0 and recovers from a page fault */
656+
657+ #ifdef        DEBUG_MAIN
658+ #undef        DEBUG           /* must not use these together with DEBUG_MAIN */
659+ #undef        DEBUG_EXC
660+ #endif
661+
662+ /***************************** INCLUDE HEADERS ****************************/
663+
664+ #ifndef DEBUG_MAIN
665+ #include <rtems.h>
666+ #include <rtems/bspIo.h>
667+ #include <libcpu/cpu.h>
668+ #include <bsp.h>
669+ #ifdef        DEBUG_EXC
670+ #include <bsp/vectors.h>
671+ #include <libcpu/raw_exception.h>
672+ #endif
673+ #endif
674+
675+ #include <stdio.h>
676+ #include <assert.h>
677+
678+ #include "pte121.h"
679+
680+ /************************** CONSTANT DEFINITIONS **************************/
681+
682+ /* Base 2 logs of some sizes */
683+
684+ #ifndef DEBUG_MAIN
685+
686+ #define       LD_PHYS_SIZE    32              /* physical address space */
687+ #define LD_PG_SIZE            12              /* page size */
688+ #define LD_PTEG_SIZE  6               /* PTEG size */
689+ #define LD_PTE_SIZE           3               /* PTE size  */
690+ #define LD_SEG_SIZE           28              /* segment size */
691+ #define LD_MIN_PT_SIZE        16              /* minimal size of a page table */
692+ #define LD_HASH_SIZE  19              /* lengh of a hash */
693+
694+ #else /* DEBUG_MAIN */
695+
696+ /* Reduced 'fantasy' sizes for testing */
697+ #define       LD_PHYS_SIZE    32              /* physical address space */
698+ #define LD_PG_SIZE            6               /* page size */
699+ #define LD_PTEG_SIZE  5               /* PTEG size */
700+ #define LD_PTE_SIZE           3               /* PTE size  */
701+ #define LD_SEG_SIZE           28              /* segment size */
702+ #define LD_MIN_PT_SIZE        7               /* minimal size of a page table */
703+ #define LD_HASH_SIZE  19              /* lengh of a hash */
704+
705+ #endif /* DEBUG_MAIN */
706+
707+ /* Derived sizes */
708+
709+ /* Size of a page index */
710+ #define LD_PI_SIZE            ((LD_SEG_SIZE) - (LD_PG_SIZE))
711+
712+ /* Number of PTEs in a PTEG */
713+ #define PTE_PER_PTEG  (1<<((LD_PTEG_SIZE)-(LD_PTE_SIZE)))
714+
715+ /* Segment register bits */
716+ #define KEY_SUP                       (1<<30) /* supervisor mode key */
717+ #define KEY_USR                       (1<<29) /* user mode key */
718+
719+ /* The range of effective addresses to scan with 'tlbie'
720+  * instructions in order to flush all TLBs.
721+  * On the 750 and 7400, there are 128 two way I and D TLBs,
722+  * indexed by EA[14:19]. Hence calling
723+  *      tlbie rx
724+  * where rx scans 0x00000, 0x01000, 0x02000, ... 0x3f000
725+  * is sufficient to do the job
726+  */
727+ #define NUM_TLB_PER_WAY 64 /* 750 and 7400 have 128 two way TLBs */
728+ #define FLUSH_EA_RANGE        (NUM_TLB_PER_WAY<<LD_PG_SIZE)
729+
730+ /*************************** MACRO DEFINITIONS ****************************/
731+
732+ /* Macros to split a (32bit) 'effective' address into
733+  * VSID (virtual segment id) and PI (page index)
734+  * using a 1:1 mapping of 'effective' to 'virtual'
735+  * addresses.
736+  *
737+  * For 32bit addresses this looks like follows
738+  * (each 'x' or '0' stands for a 'nibble' [4bits]):
739+  *
740+  *         32bit effective address (EA)
741+  *
742+  *              x x x x x x x x
743+  *               |       |
744+  *    0 0 0 0 0 x|x x x x|x x x
745+  *       VSID    |  PI   |  PO (page offset)
746+  *               |       |
747+  */
748+ /* 1:1 VSID of an EA  */
749+ #define VSID121(ea) (((ea)>>LD_SEG_SIZE) & ((1<<(LD_PHYS_SIZE-LD_SEG_SIZE))-1))
750+ /* page index of an EA */
751+ #define PI121(ea)     (((ea)>>LD_PG_SIZE) & ((1<<LD_PI_SIZE)-1))
752+
753+
754+ /* Primary and secondary PTE hash functions */
755+
756+ /* Compute the primary hash from a VSID and a PI */
757+ #define PTE_HASH1(vsid, pi) (((vsid)^(pi))&((1<<LD_HASH_SIZE)-1))
758+
759+ /* Compute the secondary hash from a primary hash */
760+ #define PTE_HASH2(hash1) ((~(hash1))&((1<<LD_HASH_SIZE)-1))
761+
762+ /* Extract the abbreviated page index (which is the
763+  * part of the PI which does not go into the hash
764+  * under all circumstances [10 bits to -> 6bit API])
765+  */
766+ #define API(pi)       ((pi)>>((LD_MIN_PT_SIZE)-(LD_PTEG_SIZE)))
767+
768+
769+ /* Horrible Macros */
770+ #ifdef __rtems
771+ /* must not use printf until multitasking is up */
772+ typedef void (*PrintF)(char *,...);
773+ static PrintF whatPrintf(void)
774+ {
775+               return _Thread_Executing ?
776+                               (PrintF)printf :
777+                               printk;
778+ }
779+
780+ #define PRINTF(args...) ((void)(whatPrintf())(args))
781+ #else
782+ #define PRINTF(args...) printf(args)
783+ #endif
784+
785+ #ifdef DEBUG
786+ unsigned long
787+ triv121PgTblConsistency(Triv121PgTbl pt, int pass, int expect);
788+
789+ static int consistencyPass=0;
790+ #define CONSCHECK(expect) triv121PgTblConsistency(&pgTbl,consistencyPass++,(expect))
791+ #else
792+ #define CONSCHECK(expect) do {} while (0)
793+ #endif
794+
795+ /**************************** TYPE DEFINITIONS ****************************/
796+
797+ /* A PTE entry */
798+ typedef struct PTERec_ {
799+               unsigned long v:1,    vsid:24, h:1, api: 6;
800+               unsigned long rpn:20, pad: 3, r:1, c:1, wimg:4, marked:1, pp:2;
801+ } PTERec, *PTE;
802+
803+ /* internal description of a trivial page table */
804+ typedef struct Triv121PgTblRec_ {
805+               PTE                             base;
806+               unsigned long   size;
807+               int                             active;
808+ } Triv121PgTblRec;
809+
810+
811+ /************************** FORWARD DECLARATIONS *************************/
812+
813+ #ifdef DEBUG_EXC
814+ static void
815+ myhdl(BSP_Exception_frame* excPtr);
816+ #endif
817+
818+ #if defined(DEBUG_MAIN) || defined(DEBUG)
819+ static void
820+ dumpPte(PTE pte);
821+ #endif
822+
823+ #ifdef DEBUG
824+ static void
825+ dumpPteg(unsigned long vsid, unsigned long pi, unsigned long hash);
826+ unsigned long
827+ triv121IsRangeMapped(unsigned long start, unsigned long end);
828+ #endif
829+
830+ /**************************** STATIC VARIABLES ****************************/
831+
832+ /* dont malloc - we might have to use this before
833+  * we have malloc or even RTEMS workspace available
834+  */
835+ static Triv121PgTblRec pgTbl={0};
836+
837+ #ifdef DEBUG_EXC
838+ static void *ohdl;                    /* keep a pointer to the original handler */
839+ #endif
840+
841+ /*********************** INLINES & PRIVATE ROUTINES ***********************/
842+
843+ /* compute the page table entry group (PTEG) of a hash */
844+ static inline PTE
845+ ptegOf(Triv121PgTbl pt, unsigned long hash)
846+ {
847+       hash &= ((1<<LD_HASH_SIZE)-1);
848+       return (PTE)(((unsigned long)pt->base) | ((hash<<LD_PTEG_SIZE) & (pt->size-1)));
849+ }
850+
851+ /* see if a vsid/pi combination is already mapped
852+  *
853+  * RETURNS: PTE of mapping / NULL if none exists
854+  *
855+  * NOTE: a vsid<0 is legal and will tell this
856+  *       routine that 'pi' is actually an EA to
857+  *       be split into vsid and pi...
858+  */
859+ static PTE
860+ alreadyMapped(Triv121PgTbl pt, long vsid, unsigned long pi)
861+ {
862+ int                           i;
863+ unsigned long hash,api;
864+ PTE                           pte;
865+
866+       if (!pt->size)
867+               return 0;
868+
869+       if (vsid<0) {
870+               vsid=VSID121(pi);
871+               pi=PI121(pi);
872+       }
873+
874+       hash = PTE_HASH1(vsid,pi);
875+       api=API(pi);
876+       for (i=0, pte=ptegOf(pt,hash); i<PTE_PER_PTEG; i++,pte++)
877+               if (pte->v && pte->vsid==vsid && pte->api==api && 0==pte->h)
878+                       return pte;
879+       /* try the secondary hash table */
880+       hash = PTE_HASH2(hash);
881+       for (i=0, pte=ptegOf(pt,hash); i<PTE_PER_PTEG; i++,pte++)
882+               if (pte->v && pte->vsid==vsid && pte->api==api && 1==pte->h)
883+                       return pte;
884+       return 0;
885+ }
886+
887+ /* find the first available slot for  vsid/pi
888+  *
889+  * NOTE: it is NOT legal to pass a vsid<0 / EA combination.
890+  *
891+  * RETURNS free slot with the 'marked' field set. The 'h'
892+  *         field is set to 0 or one, depending on whether
893+  *         the slot was allocated by using the primary or
894+  *         the secondary hash, respectively.
895+  */
896+ static PTE
897+ slotFor(Triv121PgTbl pt, unsigned long vsid, unsigned long pi)
898+ {
899+ int                           i;
900+ unsigned long hash,api;
901+ PTE                           pte;
902+
903+       /* primary hash */
904+       hash = PTE_HASH1(vsid,pi);
905+       api=API(pi);
906+       /* linear search thru all buckets for this hash */
907+       for (i=0, pte=ptegOf(pt,hash); i<PTE_PER_PTEG; i++,pte++) {
908+               if (!pte->v && !pte->marked) {
909+                       /* found a free PTE; mark it as potentially used and return */
910+                       pte->h=0;       /* found by the primary hash fn */
911+                       pte->marked=1;
912+                       return pte;
913+               }
914+       }
915+
916+ #ifdef DEBUG
917+       /* Strange: if the hash table was allocated big enough,
918+        *          this should not happen (when using a 1:1 mapping)
919+        *          Give them some information...
920+        */
921+       PRINTF("## First hash bucket full - ");
922+       dumpPteg(vsid,pi,hash);
923+ #endif
924+
925+       hash = PTE_HASH2(hash);
926+ #ifdef DEBUG
927+       PRINTF("   Secondary pteg is 0x%08x\n", (unsigned)ptegOf(pt,hash));
928+ #endif
929+       for (i=0, pte=ptegOf(pt,hash); i<PTE_PER_PTEG; i++,pte++) {
930+               if (!pte->v && !pte->marked) {
931+                       /* mark this pte as potentially used */
932+                       pte->marked=1;
933+                       pte->h=1;
934+                       return pte;
935+               }
936+       }
937+ #ifdef DEBUG
938+       /* Even more strange - most likely, something is REALLY messed up */
939+       PRINTF("## Second hash bucket full - ");
940+       dumpPteg(vsid,pi,hash);
941+ #endif
942+       return 0;
943+ }
944+
945+ /* unmark all entries */
946+ static void
947+ unmarkAll(Triv121PgTbl pt)
948+ {
949+ unsigned long n=pt->size / sizeof(PTERec);
950+ unsigned long i;
951+ PTE                           pte;
952+       for (i=0,pte=pt->base; i<n; i++,pte++)
953+               pte->marked=0;
954+
955+ }
956+
957+ /* calculate the minimal size of a page/hash table
958+  * to map a range of 'size' bytes in EA space.
959+  *
960+  * RETURNS: size in 'number of bits', i.e. the
961+  *          integer part of LOGbase2(minsize)
962+  *          is returned.
963+  * NOTE:      G3/G4 machines need at least 16 bits
964+  *          (64k).
965+  */
966+ unsigned long
967+ triv121PgTblLdMinSize(unsigned long size)
968+ {
969+ unsigned long i;
970+       /* round 'size' up to the next page boundary */
971+       size += (1<<LD_PG_SIZE)-1;
972+       size &= ~((1<<LD_PG_SIZE)-1);
973+       /* divide by number of PTEs  and multiply
974+        * by the size of a PTE.
975+        */
976+       size >>= LD_PG_SIZE - LD_PTE_SIZE;
977+       /* find the next power of 2 >= size */
978+       for (i=0; i<LD_PHYS_SIZE; i++) {
979+               if ((1<<i) >= size)
980+                       break;
981+       }
982+       /* pop up to the allowed minimum, if necessary */
983+       if (i<LD_MIN_PT_SIZE)
984+                       i=LD_MIN_PT_SIZE;
985+       return i;
986+ }
987+
988+ /* initialize a trivial page table of 2^ldSize bytes
989+  * at 'base' in memory.
990+  *
991+  * RETURNS:   OPAQUE HANDLE (not the hash table address)
992+  *          or NULL on failure.
993+  */
994+ Triv121PgTbl
995+ triv121PgTblInit(unsigned long base, unsigned ldSize)
996+ {
997+       if (pgTbl.size) {
998+               /* already initialized */
999+               return 0;
1000+       }
1001+
1002+       if (ldSize < LD_MIN_PT_SIZE)
1003+               return 0; /* too small */
1004+
1005+       if (base & ((1<<ldSize)-1))
1006+               return 0; /* misaligned */
1007+
1008+       /* This should work on a 604, but I couldn't test (I did
1009+        * on 750 and 7400). Verify that the TLB invalidation works
1010+        * for a new CPU variant and that it has hardware PTE lookup/
1011+        * TLB replacement before adding it to this list.
1012+        *
1013+        * NOTE: The 603 features no hardware PTE lookup - and
1014+        *       hence the page tables should NOT be used.
1015+        *               Although lookup could be implemented in
1016+        *               software this is probably not desirable
1017+        *               as it could have an impact on hard realtime
1018+        *               performance, screwing deterministic latency!
1019+        *               (Could still be useful for debugging, though)
1020+        */
1021+       if      (       PPC_604         !=current_ppc_cpu &&
1022+                       PPC_604e        !=current_ppc_cpu &&
1023+                       PPC_604r        !=current_ppc_cpu &&
1024+                       PPC_750         !=current_ppc_cpu &&
1025+                       PPC_7400        !=current_ppc_cpu )
1026+               return 0;       /* unsupported by this CPU */
1027+
1028+       pgTbl.base=(PTE)base;
1029+       pgTbl.size=1<<ldSize;
1030+       /* clear all page table entries */
1031+       memset(pgTbl.base, 0, pgTbl.size);
1032+
1033+       CONSCHECK(0);
1034+
1035+       /* map the page table itself 'm' and 'readonly' */
1036+       if (triv121PgTblMap(&pgTbl,
1037+                                               TRIV121_121_VSID,
1038+                                               base,
1039+                                               (pgTbl.size >> LD_PG_SIZE),
1040+                                               TRIV121_ATTR_M,
1041+                                               TRIV121_PP_RO_PAGE) >= 0)
1042+               return 0;
1043+
1044+       CONSCHECK((pgTbl.size>>LD_PG_SIZE));
1045+
1046+       return &pgTbl;
1047+ }
1048+
1049+ /* return the handle of the (one and only) page table
1050+  * or NULL if none has been initialized yet.
1051+  */
1052+ Triv121PgTbl
1053+ triv121PgTblGet(void)
1054+ {
1055+       return pgTbl.size ? &pgTbl : 0;
1056+ }
1057+
1058+ /* NOTE: this routine returns -1 on success;
1059+  *       on failure, the page table index for
1060+  *       which no PTE could be allocated is returned
1061+  *
1062+  * (Consult header about argument/return value
1063+  * description)
1064+  */
1065+ long
1066+ triv121PgTblMap(
1067+                               Triv121PgTbl    pt,
1068+                               long                    vsid,
1069+                               unsigned long   start,
1070+                               unsigned long   numPages,
1071+                               unsigned                attributes,
1072+                               unsigned                protection
1073+                               )
1074+ {
1075+ int                           i,pass;
1076+ unsigned long pi;
1077+ PTE                           pte;
1078+
1079+       /* already activated - no change allowed */
1080+       if (pt->active)
1081+                       return -1;
1082+
1083+       if (vsid < 0) {
1084+                       /* use 1:1 mapping */
1085+                       vsid = VSID121(start);
1086+       }
1087+
1088+ #ifdef DEBUG
1089+       PRINTF("Mapping %i (0x%x) pages at 0x%08x for VSID 0x%08x\n",
1090+               (unsigned)numPages, (unsigned)numPages,
1091+               (unsigned)start, (unsigned)vsid);
1092+ #endif
1093+
1094+       /* map in two passes. During the first pass, we try
1095+        * to claim entries as needed. The 'slotFor()' routine
1096+        * will 'mark' the claimed entries without 'valid'ating
1097+        * them.
1098+        * If the mapping fails, all claimed entries are unmarked
1099+        * and we return the PI for which allocation failed.
1100+        *
1101+        * Once we know that the allocation would succeed, we
1102+        * do a second pass; during the second pass, the PTE
1103+        * is actually written.
1104+        *
1105+        */
1106+       for (pass=0; pass<2; pass++) {
1107+               /* check if we would succeed during the first pass */
1108+               for (i=0, pi=PI121(start); i<numPages; i++,pi++) {
1109+                       /* leave alone existing mappings for this EA */
1110+                       if (!alreadyMapped(pt, vsid, pi)) {
1111+                               if (!(pte=slotFor(pt, vsid, pi))) {
1112+                                       /* no free slot found for page index 'pi' */
1113+                                       unmarkAll(pt);
1114+                                       return pi;
1115+                               } else {
1116+                                       /* have a free slot; marked by slotFor() */
1117+                                       if (pass) {
1118+                                               /* second pass; do the real work */
1119+                                               pte->vsid=vsid;
1120+                                               /* H was set by slotFor() */
1121+                                               pte->api =API(pi);
1122+                                               /* set up 1:1 mapping */
1123+                                               pte->rpn =((((unsigned long)vsid)&((1<<(LD_PHYS_SIZE-LD_SEG_SIZE))-1))<<LD_PI_SIZE) | pi;
1124+                                               pte->wimg=attributes & 0xf;
1125+                                               pte->pp=protection&0x3;
1126+                                               /* mark it valid */
1127+                                               pte->v=1;
1128+                                               pte->marked=0;
1129+ #ifdef DEBUG
1130+                                               /* add paranoia */
1131+                                               assert(alreadyMapped(pt, vsid, pi) == pte);
1132+ #endif
1133+                                       }
1134+                               }
1135+                       }
1136+               }
1137+               unmarkAll(pt);
1138+       }
1139+ #ifdef DEBUG
1140+       {
1141+       unsigned long failedat;
1142+       CONSCHECK(-1);
1143+       /* double check that the requested range is mapped */
1144+       failedat=triv121IsRangeMapped(start, start + (1<<LD_PG_SIZE)*numPages);
1145+       if (0x0C0C != failedat) {
1146+               PRINTF("triv121 mapping failed at 0x%08x\n",(unsigned)failedat);
1147+               return PI121(failedat);
1148+       }
1149+       }
1150+ #endif
1151+       return TRIV121_MAP_SUCCESS; /* -1 !! */
1152+ }
1153+
1154+ unsigned long
1155+ triv121PgTblSDR1(Triv121PgTbl pt)
1156+ {
1157+       return (((unsigned long)pt->base) & ~(LD_MIN_PT_SIZE-1)) |
1158+                  ( ((pt->size-1) >> LD_MIN_PT_SIZE) &
1159+                        ((1<<(LD_HASH_SIZE-(LD_MIN_PT_SIZE-LD_PTEG_SIZE)))-1)
1160+                  );
1161+ }
1162+
1163+ void
1164+ triv121PgTblActivate(Triv121PgTbl pt)
1165+ {
1166+ #ifndef DEBUG_MAIN
1167+ unsigned long sdr1=triv121PgTblSDR1(pt);
1168+ #endif
1169+       pt->active=1;
1170+
1171+ #ifndef DEBUG_MAIN
1172+ #ifdef DEBUG_EXC
1173+       /* install our exception handler */
1174+       ohdl=globalExceptHdl;
1175+       globalExceptHdl=myhdl;
1176+       __asm__ __volatile__ ("sync");
1177+ #endif
1178+
1179+       /* This section of assembly code takes care of the
1180+        * following:
1181+        * - get MSR and switch interrupts + MMU off
1182+        *
1183+        * - load up the segment registers with a
1184+        *   1:1 effective <-> virtual mapping;
1185+        *   give user & supervisor keys
1186+        *
1187+        * - flush all TLBs;
1188+        *   NOTE: the TLB flushing code is probably
1189+        *         CPU dependent!
1190+        *
1191+        * - setup SDR1
1192+        *
1193+        * - restore original MSR
1194+        */
1195+       __asm__ __volatile(
1196+               "       mtctr   %0\n"
1197+               /* Get MSR and switch interrupts off - just in case.
1198+                * Also switch the MMU off; the book
1199+                * says that SDR1 must not be changed with either
1200+                * MSR_IR or MSR_DR set. I would guess that it could
1201+                * be safe as long as the IBAT & DBAT mappings override
1202+                * the page table...
1203+                */
1204+               "       mfmsr   %0\n"
1205+               "       andc    %6, %0, %6\n"
1206+               "       mtmsr   %6\n"
1207+               "       isync   \n"
1208+               /* set up the segment registers */
1209+               "       li              %6, 0\n"
1210+               "1:     mtsrin  %1, %6\n"
1211+               "       addis   %6, %6, 0x1000\n"       /* address next SR */
1212+               "       addi    %1, %1, 1\n"            /* increment VSID  */
1213+               "       bdnz    1b\n"
1214+               /* Now flush all TLBs, starting with the topmost index */
1215+               "       lis             %6, %2@h\n"     
1216+               "2:     addic.  %6, %6, -%3\n"          /* address the next one (decrementing) */
1217+               "       tlbie   %6\n"                           /* invalidate & repeat */
1218+               "       bgt             2b\n"
1219+               "       tlbsync\n"
1220+               "       sync\n"
1221+               /* set up SDR1 */
1222+               "   mtspr       %4, %5\n"
1223+               /* restore original MSR  */
1224+               "       mtmsr   %0\n"
1225+               "       isync   \n"
1226+               ::"r"(16), "b"(KEY_USR | KEY_SUP),
1227+                 "i"(FLUSH_EA_RANGE), "i"(1<<LD_PG_SIZE),
1228+                 "i"(SDR1), "r"(sdr1),
1229+                 "b"(MSR_EE | MSR_IR | MSR_DR)
1230+               : "ctr","cc");
1231+
1232+       /* At this point, BAT0 is probably still active; it's the
1233+        * caller's job to deactivate it...
1234+        */
1235+ #endif
1236+ }
1237+
1238+ /**************************  DEBUGGING ROUTINES  *************************/
1239+
1240+ /* Exception handler to catch page faults */
1241+ #ifdef DEBUG_EXC
1242+
1243+ #define BAT_VALID_BOTH        3       /* allow user + super access */
1244+
1245+ static void
1246+ myhdl(BSP_Exception_frame* excPtr)
1247+ {
1248+ if (3==excPtr->_EXC_number) {
1249+       unsigned long dsisr;
1250+
1251+       /* reactivate DBAT0 and read DSISR */
1252+       __asm__ __volatile__(
1253+                       "mfspr %0, %1\n"
1254+                       "ori    %0,%0,3\n"
1255+                       "mtspr %1, %0\n"
1256+                       "sync\n"
1257+                       "mfspr %0, %2\n"
1258+                       :"=r"(dsisr)
1259+                       :"i"(DBAT0U),"i"(DSISR),"i"(BAT_VALID_BOTH)
1260+       );
1261+
1262+       printk("Data Access Exception (DSI) # 3\n");
1263+       printk("Reactivated DBAT0 mapping\n");
1264+
1265+
1266+       printk("DSISR 0x%08x\n",dsisr);
1267+
1268+       printk("revectoring to prevent default handler panic().\n");
1269+       printk("NOTE: exception number %i below is BOGUS\n",
1270+                       ASM_DEC_VECTOR);
1271+       /* make this exception 'recoverable' for
1272+        * the default handler by faking a decrementer
1273+        * exception.
1274+        * Note that the default handler's message will be
1275+        * wrong about the exception number.
1276+        */
1277+       excPtr->_EXC_number = ASM_DEC_VECTOR;
1278+ }
1279+ /* now call the original handler */
1280+ ((void(*)())ohdl)(excPtr);
1281+ }
1282+ #endif
1283+
1284+
1285+ #ifdef DEBUG
1286+
1287+ /* test the consistency of the page table
1288+  *
1289+  * 'pass' is merely a number which will be printed
1290+  * by this routine, so the caller may give some
1291+  * context information.
1292+  *
1293+  * 'expected' is the number of valid (plus 'marked')
1294+  * entries the caller believes the page table should
1295+  * have. This routine complains if its count differs.
1296+  *
1297+  * It basically verifies that the topmost 20bits
1298+  * of all VSIDs as well as the unused bits are all
1299+  * zero. Then it counts all valid and all 'marked'
1300+  * entries, adding them up and comparing them to the
1301+  * 'expected' number of occupied slots.
1302+  *
1303+  * RETURNS: total number of valid plus 'marked' slots.
1304+  */
1305+ unsigned long
1306+ triv121PgTblConsistency(Triv121PgTbl pt, int pass, int expected)
1307+ {
1308+ PTE pte;
1309+ int i;
1310+ unsigned v,m;
1311+ int warn=0;
1312+ static int maxw=20;   /* mute after detecting this many errors */
1313+
1314+       PRINTF("Checking page table at 0x%08x (size %i==0x%x)\n",
1315+                       (unsigned)pt->base, (unsigned)pt->size, (unsigned)pt->size);
1316+
1317+       if (!pt->base || !pt->size) {
1318+               PRINTF("Uninitialized Page Table!\n");
1319+               return 0;
1320+       }
1321+
1322+       v=m=0;
1323+       for (i=0, pte=pt->base; i<pt->size/sizeof(PTERec); i++,pte++) {
1324+               int                             err=0;
1325+               char                    buf[500];
1326+               unsigned long   *lp=(unsigned long*)pte;
1327+               if ( (*lp & (0xfffff0<<7)) || *(lp+1) & 0xe00 || (pte->v && pte->marked)) {
1328+                       /* check for vsid (without segment bits) == 0, unused bits == 0, valid && marked */
1329+                       sprintf(buf,"invalid VSID , unused bits or v && m");
1330+                       err=1;
1331+               } else {
1332+                       if (pte->v) v++;
1333+                       if (pte->marked) m++;
1334+               }
1335+               if (err && maxw) {
1336+                       PRINTF("Pass %i -- strange PTE at 0x%08x found for page index %i == 0x%08x:\n",
1337+                               pass,(unsigned)pte,i,i);
1338+                       PRINTF("Reason: %s\n",buf);
1339+                       dumpPte(pte);
1340+                       warn++;
1341+                       maxw--;
1342+               }
1343+       }
1344+       if (warn) {
1345+               PRINTF("%i errors found; currently %i entries marked, %i are valid\n",
1346+                       warn, m, v);
1347+       }
1348+       v+=m;
1349+       if (maxw && expected>=0 && expected != v) {
1350+               /* number of occupied slots not what they expected */
1351+               PRINTF("Wrong # of occupied slots detected during pass");
1352+           PRINTF("%i; should be %i (0x%x) is %i (0x%x)\n",
1353+                               pass, expected, (unsigned)expected, v, (unsigned)v);
1354+               maxw--;
1355+       }
1356+       return v;
1357+ }
1358+
1359+ /* Find the PTE for a EA and print its contents
1360+  * RETURNS: pte for EA or NULL if no entry was found.
1361+  */
1362+ PTE
1363+ triv121DumpPte(unsigned long ea)
1364+ {
1365+ PTE pte;
1366+
1367+       pte=alreadyMapped(&pgTbl,TRIV121_121_VSID,ea);
1368+
1369+       if (pte)
1370+               dumpPte(pte);
1371+       return pte;
1372+ }
1373+
1374+ /* Dump an entire PTEG */
1375+
1376+ static void
1377+ dumpPteg(unsigned long vsid, unsigned long pi, unsigned long hash)
1378+ {
1379+ PTE pte=ptegOf(&pgTbl,hash);
1380+ int i;
1381+       PRINTF("hash 0x%08x, pteg 0x%08x (vsid 0x%08x, pi 0x%08x)\n",
1382+                       (unsigned)hash, (unsigned)pte,
1383+                       (unsigned)vsid, (unsigned)pi);
1384+       for (i=0; i<PTE_PER_PTEG; i++,pte++) {
1385+               PRINTF("pte 0x%08x is 0x%08x : 0x%08x\n",
1386+                       (unsigned)pte,
1387+                       (unsigned)*(unsigned long*)pte,
1388+                       (unsigned)*(((unsigned long*)pte)+1));
1389+       }
1390+ }
1391
1392+ /* Verify that a range of EAs is mapped the page table
1393+  *
1394+  * RETURNS: address of the first page for which no
1395+  *          PTE was found (i.e. page index * page size)
1396+  *         
1397+  *          ON SUCCESS, the special value 0x0C0C ("OKOK")
1398+  *          [which is not page aligned and hence is not
1399+  *          a valid page address].
1400+  */
1401+ unsigned long
1402+ triv121IsRangeMapped(unsigned long start, unsigned long end)
1403+ {
1404+       start&=~((1<<LD_PG_SIZE)-1);
1405+       while (start < end) {
1406+               if (!alreadyMapped(&pgTbl,TRIV121_121_VSID,start))
1407+                       return start;
1408+               start+=1<<LD_PG_SIZE;
1409+       }
1410+       return 0x0C0C; /* OKOK - not on a page boundary */
1411+ }
1412+
1413+ #endif
1414+
1415+
1416+ #if defined(DEBUG_MAIN) || defined(DEBUG)
1417+ #include <stdlib.h>
1418+
1419+ /* print a PTE */
1420+ static void
1421+ dumpPte(PTE pte)
1422+ {
1423+       if (0==((unsigned long)pte & ((1<<LD_PTEG_SIZE)-1)))
1424+               PRINTF("PTEG--");
1425+       else
1426+               PRINTF("......");
1427+       if (pte->v) {
1428+               PRINTF("VSID: 0x%08x H:%1i API: 0x%02x\n",
1429+                                       pte->vsid, pte->h, pte->api);
1430+               PRINTF("      ");
1431+               PRINTF("RPN:  0x%08x WIMG: 0x%1x, (m %1i), pp: 0x%1x\n",
1432+                                       pte->rpn, pte->wimg, pte->marked, pte->pp);
1433+       } else {
1434+               PRINTF("xxxxxx\n");
1435+               PRINTF("      ");
1436+               PRINTF("xxxxxx\n");
1437+       }
1438+ }
1439+
1440+
1441+ /* dump page table entries from index 'from' to 'to'
1442+  * The special values (unsigned)-1 are allowed which
1443+  * cause the routine to dump the entire table.
1444+  *
1445+  * RETURNS 0
1446+  */
1447+ int
1448+ triv121PgTblDump(Triv121PgTbl pt, unsigned from, unsigned to)
1449+ {
1450+ int i;
1451+ PTE   pte;
1452+       PRINTF("Dumping PT [size 0x%08x == %i] at 0x%08x\n",
1453+                       (unsigned)pt->size, (unsigned)pt->size, (unsigned)pt->base);
1454+       if (from> pt->size>>LD_PTE_SIZE)
1455+               from=0;
1456+       if (to  > pt->size>>LD_PTE_SIZE)
1457+               to=(pt->size>>LD_PTE_SIZE);
1458+       for (i=from,pte=pt->base+from; i<(long)to; i++, pte++) {
1459+               dumpPte(pte);
1460+       }
1461+       return 0;
1462+ }
1463+
1464+
1465+ #if defined(DEBUG_MAIN)
1466+
1467+ #define LD_DBG_PT_SIZE        LD_MIN_PT_SIZE
1468+
1469+ int
1470+ main(int argc, char **argv)
1471+ {
1472+ unsigned long base,start,numPages;
1473+ unsigned long size=1<<LD_DBG_PT_SIZE;
1474+ Triv121PgTbl  pt;
1475+
1476+       base=(unsigned long)malloc(size<<1);
1477+
1478+       assert(base);
1479+
1480+       /* align pt */
1481+       base += size-1;
1482+       base &= ~(size-1);
1483+
1484+       assert(pt=triv121PgTblInit(base,LD_DBG_PT_SIZE));
1485+
1486+       triv121PgTblDump(pt,(unsigned)-1, (unsigned)-1);
1487+       do {
1488+               do {
1489+               PRINTF("Start Address:"); fflush(stdout);
1490+               } while (1!=scanf("%i",&start));
1491+               do {
1492+               PRINTF("# pages:"); fflush(stdout);
1493+               } while (1!=scanf("%i",&numPages));
1494+       } while (TRIV121_MAP_SUCCESS==triv121PgTblMap(pt,TRIV121_121_VSID,start,numPages,
1495+                                                       TRIV121_ATTR_IO_PAGE,2) &&
1496+                       0==triv121PgTblDump(pt,(unsigned)-1,(unsigned)-1));
1497+ }
1498+ #endif
1499+ #endif
1500Index: c/src/lib/libcpu/powerpc/mpc6xx/mmu/pte121.h
1501===================================================================
1502RCS file: pte121.h
1503diff -N pte121.h
1504*** /dev/null   Thu Aug 24 02:00:32 2000
1505--- /tmp/cvsGZfDRM      Sun May  5 11:22:45 2002
1506***************
1507*** 0 ****
1508--- 1,165 ----
1509+ #ifndef PPC_TRIVIAL_PTE_MAPPING_H
1510+ #define PPC_TRIVIAL_PTE_MAPPING_H
1511+ /* $Id: pte121.h,v 1.4 2002/04/16 21:12:52 till Exp $ */
1512+
1513+ /* Rudimentary page/hash table support for Powerpc
1514+  *
1515+  * A simple, static (i.e. no 'per-process' virtual
1516+  * address space etc.) page table providing
1517+  * one-to-one effective <-> virtual <-> physical
1518+  * address mapping.
1519+  *
1520+  * PURPOSE:
1521+  *    1) allow write-protection of text/read-only data areas
1522+  *    2) provide more effective-address space in case
1523+  *       the BATs are not enough
1524+  * LIMITATIONS:
1525+  *    -  once activated, the page table cannot be changed
1526+  *    -  no PTE replacement (makes no sense in a real-time
1527+  *       environment, anyway) -> the page table just MUST
1528+  *       be big enough!.
1529+  *    -  only one page table supported.
1530+  */
1531+
1532+ /* Author: Till Straumann <strauman@slac.stanford.edu>, 4/2002 */
1533+
1534+ /* Abstract handle for a page table */
1535+ typedef struct Triv121PgTblRec_ *Triv121PgTbl;
1536+
1537+ /* Initialize a trivial page table
1538+  * using 2^ldSize bytes of memory starting at
1539+  * 'base'.
1540+  *
1541+  * RETURNS: a handle to the internal data structure
1542+  *          used to manage the page table. NULL on
1543+  *          error.
1544+  *         
1545+  * NOTES:   - 'base' must be aligned to the size
1546+  *          - minimal ldSize is 16 (== 64k)
1547+  *          - this routine maps the page table itself
1548+  *            with read-only access. While this prevents
1549+  *            the CPU from overwriting the page table,
1550+  *            it can still be corrupted by PCI bus masters
1551+  *            (like DMA engines, [VME] bridges etc.) and
1552+  *                      even by this CPU if either the MMU is off
1553+  *                      or if there is a DBAT mapping granting write
1554+  *            access...
1555+  */
1556+ Triv121PgTbl
1557+ triv121PgTblInit(unsigned long base, unsigned ldSize);
1558+
1559+ /* get the log2 of the minimal page table size needed
1560+  * for mapping 'size' bytes.
1561+  *
1562+  * EXAMPLE: create a page table which maps the entire
1563+  *          physical memory. The page table itself shall
1564+  *          be allocated at the top of the available
1565+  *          memory (assuming 'memsize' is a power of two):
1566+  *
1567+  *    ldSize = triv121PgTblLdMinSize(memsize);
1568+  *  memsize -= (1<<ldSize);   / * reduce memory available to RTEMS * /
1569+  *  pgTbl  = triv121PgTblInit(memsize,ldSize);
1570+  *
1571+  */
1572+ unsigned long
1573+ triv121PgTblLdMinSize(unsigned long size);
1574+
1575+ /* Map an address range 1:1 in pgTbl with the given protection;
1576+  *
1577+  * RETURNS: -1 (TRIV121_MAP_SUCCESS) on success; the page index
1578+  *          for which no PTE could be allocated, on failure.
1579+  *
1580+  * NOTES:   - This routine returns MINUS ONE ON SUCCESS
1581+  *          - (parts) of a mapping which overlap with
1582+  *            already existing PTEs are silently ignored.
1583+  *
1584+  *            Therefore, you can e.g. first create
1585+  *            a couple of write protected maps and
1586+  *            finally map the entire memory r/w. This
1587+  *            will leave the write protected maps
1588+  *            intact.
1589+  */
1590+ long
1591+ triv121PgTblMap(
1592+                               Triv121PgTbl  pgTbl,                    /* handle, returned by Init or Get */
1593+
1594+                               long          vsid,                             /* vsid for this mapping (contains topmost 4 bits of EA);
1595+                                                                                                *
1596+                                                                                                * NOTE: it is allowed to pass a VSID < 0 to tell this
1597+                                                                                                *       routine it should use a VSID corresponding to a
1598+                                                                                                *       1:1:1  effective - virtual - physical  mapping
1599+                                                                                                */
1600+
1601+                               unsigned long start,                    /* segment offset (lowermost 28 bits of EA) of address range
1602+                                                                                                *
1603+                                                                                                * NOTE: if VSID < 0 (TRIV121_121_VSID), 'start' is inter-
1604+                                                                                                *       preted as an effective address (EA), i.e. all 32
1605+                                                                                                *       bits are used - the most significant four going into
1606+                                                                                                *       to the VSID...
1607+                                                                                                */
1608+
1609+                               unsigned long numPages,                 /* number of pages to map */
1610+
1611+                               unsigned wimgAttr,                              /* 'wimg' attributes
1612+                                                                                                * (Write thru, cache Inhibit, coherent Memory,
1613+                                                                                                *  Guarded memory)
1614+                                                                                                */
1615+
1616+                               unsigned protection                             /* 'pp' access protection: Super      User
1617+                                                                                                *
1618+                                                                                                *   0                      r/w       none
1619+                                                                                                *   1                      r/w       ro   
1620+                                                                                                *   2                      r/w       r/w
1621+                                                                                                *   3                      ro        ro
1622+                                                                                                */
1623+                               );
1624+
1625+ #define TRIV121_ATTR_W        8       
1626+ #define TRIV121_ATTR_I        4
1627+ #define TRIV121_ATTR_M        2
1628+ #define TRIV121_ATTR_G        1
1629+
1630+ /* for I/O pages (e.g. PCI, VME addresses) use cache inhibited
1631+  * and guarded pages. RTM about the 'eieio' instruction!
1632+  */
1633+ #define TRIV121_ATTR_IO_PAGE  (TRIV121_ATTR_I|TRIV121_ATTR_G)
1634+
1635+ #define TRIV121_PP_RO_PAGE            (3)  /* read-only for everyone */
1636+ #define TRIV121_PP_RW_PAGE            (2)  /* read-write for everyone */
1637+
1638+ #define TRIV121_121_VSID              (-1) /* use 1:1 effective<->virtual address mapping */
1639+
1640+ #define TRIV121_MAP_SUCCESS           (-1) /* triv121PgTblMap() returns this on SUCCESS */
1641+
1642+ /* get a handle to the one and only page table
1643+  * (must have been initialized/allocated)
1644+  *
1645+  * RETURNS: NULL if the page table has not been initialized/allocated.
1646+  */
1647+ Triv121PgTbl
1648+ triv121PgTblGet(void);
1649+
1650+ /*
1651+  * compute the SDR1 register value for the page table
1652+  */
1653+
1654+ unsigned long
1655+ triv121PgTblSDR1(Triv121PgTbl pgTbl);
1656+
1657+ /*
1658+  * Activate the page table:
1659+  *    - set up the segment registers for a 1:1 effective <-> virtual address mapping,
1660+  *    give user and supervisor keys.
1661+  *  - set up the SDR1 register
1662+  *  - flush all tlbs
1663+  *  - 'lock' pgTbl, i.e. prevent all further modifications.
1664+  *
1665+  * NOTE: This routine does not change any BATs. Since these
1666+  *       have priority over the page table, the user
1667+  *       may have to switch overlapping BATs OFF in order
1668+  *       for the page table mappings to take effect.
1669+  */
1670+ void
1671+ triv121PgTblActivate(Triv121PgTbl pgTbl);
1672+
1673+ #endif
1674Index: c/src/lib/libcpu/powerpc/shared/include/cpu.h
1675===================================================================
1676RCS file: /afs/slac/g/spear/cvsrep/rtems/src/c/src/lib/libcpu/powerpc/shared/include/cpu.h,v
1677retrieving revision 1.1.1.2
1678retrieving revision 1.4
1679diff -c -r1.1.1.2 -r1.4
1680*** c/src/lib/libcpu/powerpc/shared/include/cpu.h       2001/12/15 00:16:26     1.1.1.2
1681--- c/src/lib/libcpu/powerpc/shared/include/cpu.h       2002/04/11 20:07:31     1.4
1682***************
1683*** 68,73 ****
1684--- 68,74 ----
1685  #define HID0_ICFI     (1<<11)         /* Instruction Cache Flash Invalidate */
1686  #define HID0_DCI      (1<<10)         /* Data Cache Invalidate */
1687  #define HID0_SIED     (1<<7)          /* Serial Instruction Execution [Disable] */
1688+ #define HID0_BTIC     (1<<5)          /* Branch Target Instruction Cache [Enable] */
1689  #define HID0_BHTE     (1<<2)          /* Branch History Table Enable */
1690  #define HID0_BTCD     (1<<1)          /* Branch target cache disable */
1691 
1692***************
1693*** 185,190 ****
1694--- 186,192 ----
1695    PPC_750     = 0x8,
1696    PPC_604e    = 0x9,
1697    PPC_604r    = 0xA,
1698+   PPC_7400    = 0xC,
1699    PPC_620     = 0x16,
1700    PPC_860     = 0x50,
1701    PPC_821     = PPC_860,
1702***************
1703*** 196,201 ****
1704--- 198,204 ----
1705 
1706  extern ppc_cpu_id_t get_ppc_cpu_type();
1707  extern ppc_cpu_id_t current_ppc_cpu;
1708+ extern char *get_ppc_cpu_type_name(ppc_cpu_id_t cpu);
1709  extern ppc_cpu_revision_t get_ppc_cpu_revision();
1710  extern ppc_cpu_revision_t current_ppc_revision;
1711  /*
1712Index: c/src/lib/libcpu/powerpc/shared/include/cpuIdent.c
1713===================================================================
1714RCS file: /afs/slac/g/spear/cvsrep/rtems/src/c/src/lib/libcpu/powerpc/shared/include/cpuIdent.c,v
1715retrieving revision 1.1.1.2
1716retrieving revision 1.4
1717diff -c -r1.1.1.2 -r1.4
1718*** c/src/lib/libcpu/powerpc/shared/include/cpuIdent.c  2002/03/07 01:54:15     1.1.1.2
1719--- c/src/lib/libcpu/powerpc/shared/include/cpuIdent.c  2002/04/11 20:07:33     1.4
1720***************
1721*** 25,34 ****
1722  ppc_cpu_id_t current_ppc_cpu = PPC_UNKNOWN;
1723  ppc_cpu_revision_t current_ppc_revision = 0xff;
1724 
1725  ppc_cpu_id_t get_ppc_cpu_type()
1726  {
1727    unsigned int pvr = (_read_PVR() >> 16);
1728-
1729    current_ppc_cpu = (ppc_cpu_id_t) pvr;
1730    switch (pvr) {
1731      case PPC_601:
1732--- 25,53 ----
1733  ppc_cpu_id_t current_ppc_cpu = PPC_UNKNOWN;
1734  ppc_cpu_revision_t current_ppc_revision = 0xff;
1735 
1736+ char *get_ppc_cpu_type_name(ppc_cpu_id_t cpu)
1737+ {
1738+   switch (cpu) {
1739+     case PPC_601:             return "MPC601";
1740+     case PPC_603:             return "MPC603";
1741+     case PPC_603ev:           return "MPC603ev";
1742+     case PPC_604:             return "MPC604";
1743+     case PPC_750:             return "MPC750";
1744+     case PPC_7400:            return "MPC7400";
1745+     case PPC_604e:            return "MPC604e";
1746+     case PPC_604r:            return "MPC604r";
1747+     case PPC_620:             return "MPC620";
1748+     case PPC_860:             return "MPC860";
1749+     case PPC_8260:            return "MPC8260";
1750+     default:
1751+       printk("Unknown CPU value of 0x%x. Please add it to <libcpu/powerpc/shared/cpu.h>\n", cpu );
1752+   }
1753+   return "UNKNOWN";
1754+ }
1755+
1756  ppc_cpu_id_t get_ppc_cpu_type()
1757  {
1758    unsigned int pvr = (_read_PVR() >> 16);
1759    current_ppc_cpu = (ppc_cpu_id_t) pvr;
1760    switch (pvr) {
1761      case PPC_601:
1762***************
1763*** 36,54 ****
1764      case PPC_603ev:
1765      case PPC_604:
1766      case PPC_750:
1767      case PPC_604e:
1768      case PPC_604r:
1769      case PPC_620:
1770      case PPC_860:
1771      case PPC_8260:
1772-       current_ppc_cpu = (ppc_cpu_id_t) pvr;
1773        return current_ppc_cpu;
1774      default:
1775        printk("Unknown PVR value of 0x%x. Please add it to <libcpu/powerpc/shared/cpu.h>\n", pvr );
1776      return PPC_UNKNOWN;
1777    }
1778-   
1779  }
1780  ppc_cpu_revision_t get_ppc_cpu_revision()
1781  {
1782    ppc_cpu_revision_t rev = (ppc_cpu_revision_t) (_read_PVR() & 0xffff);
1783--- 55,73 ----
1784      case PPC_603ev:
1785      case PPC_604:
1786      case PPC_750:
1787+     case PPC_7400:
1788      case PPC_604e:
1789      case PPC_604r:
1790      case PPC_620:
1791      case PPC_860:
1792      case PPC_8260:
1793        return current_ppc_cpu;
1794      default:
1795        printk("Unknown PVR value of 0x%x. Please add it to <libcpu/powerpc/shared/cpu.h>\n", pvr );
1796      return PPC_UNKNOWN;
1797    }
1798  }
1799+
1800  ppc_cpu_revision_t get_ppc_cpu_revision()
1801  {
1802    ppc_cpu_revision_t rev = (ppc_cpu_revision_t) (_read_PVR() & 0xffff);