1 | This patch (against rtems-ss-20020301) adds |
---|
2 | several enhancements to libcpu/powerpc: |
---|
3 | |
---|
4 | Author: 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 | |
---|
41 | Index: c/src/exec/score/cpu/powerpc/rtems/score/ppc.h |
---|
42 | =================================================================== |
---|
43 | RCS file: /afs/slac/g/spear/cvsrep/rtems/src/c/src/exec/score/cpu/powerpc/rtems/score/ppc.h,v |
---|
44 | retrieving revision 1.1.1.1 |
---|
45 | retrieving revision 1.2 |
---|
46 | diff -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 |
---|
66 | Index: c/src/lib/libcpu/powerpc/configure.ac |
---|
67 | =================================================================== |
---|
68 | RCS file: /afs/slac/g/spear/cvsrep/rtems/src/c/src/lib/libcpu/powerpc/configure.ac,v |
---|
69 | retrieving revision 1.1.1.2 |
---|
70 | retrieving revision 1.2 |
---|
71 | diff -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" \ |
---|
94 | Index: c/src/lib/libcpu/powerpc/mpc6xx/exceptions/raw_exception.c |
---|
95 | =================================================================== |
---|
96 | RCS file: /afs/slac/g/spear/cvsrep/rtems/src/c/src/lib/libcpu/powerpc/mpc6xx/exceptions/raw_exception.c,v |
---|
97 | retrieving revision 1.1.1.1 |
---|
98 | retrieving revision 1.2 |
---|
99 | diff -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; |
---|
112 | Index: c/src/lib/libcpu/powerpc/mpc6xx/mmu/Makefile.am |
---|
113 | =================================================================== |
---|
114 | RCS file: /afs/slac/g/spear/cvsrep/rtems/src/c/src/lib/libcpu/powerpc/mpc6xx/mmu/Makefile.am,v |
---|
115 | retrieving revision 1.1.1.1 |
---|
116 | retrieving revision 1.2 |
---|
117 | diff -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 |
---|
164 | Index: c/src/lib/libcpu/powerpc/mpc6xx/mmu/bat.c |
---|
165 | =================================================================== |
---|
166 | RCS file: /afs/slac/g/spear/cvsrep/rtems/src/c/src/lib/libcpu/powerpc/mpc6xx/mmu/bat.c,v |
---|
167 | retrieving revision 1.1.1.1 |
---|
168 | retrieving revision 1.2 |
---|
169 | diff -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; |
---|
182 | Index: c/src/lib/libcpu/powerpc/mpc6xx/mmu/mmuAsm.S |
---|
183 | =================================================================== |
---|
184 | RCS file: /afs/slac/g/spear/cvsrep/rtems/src/c/src/lib/libcpu/powerpc/mpc6xx/mmu/mmuAsm.S,v |
---|
185 | retrieving revision 1.1.1.1 |
---|
186 | retrieving revision 1.7 |
---|
187 | diff -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 |
---|
635 | Index: c/src/lib/libcpu/powerpc/mpc6xx/mmu/pte121.c |
---|
636 | =================================================================== |
---|
637 | RCS file: pte121.c |
---|
638 | diff -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 |
---|
1500 | Index: c/src/lib/libcpu/powerpc/mpc6xx/mmu/pte121.h |
---|
1501 | =================================================================== |
---|
1502 | RCS file: pte121.h |
---|
1503 | diff -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 |
---|
1674 | Index: c/src/lib/libcpu/powerpc/shared/include/cpu.h |
---|
1675 | =================================================================== |
---|
1676 | RCS file: /afs/slac/g/spear/cvsrep/rtems/src/c/src/lib/libcpu/powerpc/shared/include/cpu.h,v |
---|
1677 | retrieving revision 1.1.1.2 |
---|
1678 | retrieving revision 1.4 |
---|
1679 | diff -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 | /* |
---|
1712 | Index: c/src/lib/libcpu/powerpc/shared/include/cpuIdent.c |
---|
1713 | =================================================================== |
---|
1714 | RCS file: /afs/slac/g/spear/cvsrep/rtems/src/c/src/lib/libcpu/powerpc/shared/include/cpuIdent.c,v |
---|
1715 | retrieving revision 1.1.1.2 |
---|
1716 | retrieving revision 1.4 |
---|
1717 | diff -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); |
---|