diff options
Diffstat (limited to 'arch/powerpc/kernel/head_8xx.S')
-rw-r--r-- | arch/powerpc/kernel/head_8xx.S | 70 |
1 files changed, 47 insertions, 23 deletions
diff --git a/arch/powerpc/kernel/head_8xx.S b/arch/powerpc/kernel/head_8xx.S index 3ef743fa5d7c..1f1a04b5c2a4 100644 --- a/arch/powerpc/kernel/head_8xx.S +++ b/arch/powerpc/kernel/head_8xx.S | |||
@@ -71,9 +71,6 @@ _ENTRY(_start); | |||
71 | * in the first level table, but that would require many changes to the | 71 | * in the first level table, but that would require many changes to the |
72 | * Linux page directory/table functions that I don't want to do right now. | 72 | * Linux page directory/table functions that I don't want to do right now. |
73 | * | 73 | * |
74 | * I used to use SPRG2 for a temporary register in the TLB handler, but it | ||
75 | * has since been put to other uses. I now use a hack to save a register | ||
76 | * and the CCR at memory location 0.....Someday I'll fix this..... | ||
77 | * -- Dan | 74 | * -- Dan |
78 | */ | 75 | */ |
79 | .globl __start | 76 | .globl __start |
@@ -302,8 +299,13 @@ InstructionTLBMiss: | |||
302 | DO_8xx_CPU6(0x3f80, r3) | 299 | DO_8xx_CPU6(0x3f80, r3) |
303 | mtspr SPRN_M_TW, r10 /* Save a couple of working registers */ | 300 | mtspr SPRN_M_TW, r10 /* Save a couple of working registers */ |
304 | mfcr r10 | 301 | mfcr r10 |
302 | #ifdef CONFIG_8xx_CPU6 | ||
305 | stw r10, 0(r0) | 303 | stw r10, 0(r0) |
306 | stw r11, 4(r0) | 304 | stw r11, 4(r0) |
305 | #else | ||
306 | mtspr SPRN_DAR, r10 | ||
307 | mtspr SPRN_SPRG2, r11 | ||
308 | #endif | ||
307 | mfspr r10, SPRN_SRR0 /* Get effective address of fault */ | 309 | mfspr r10, SPRN_SRR0 /* Get effective address of fault */ |
308 | #ifdef CONFIG_8xx_CPU15 | 310 | #ifdef CONFIG_8xx_CPU15 |
309 | addi r11, r10, 0x1000 | 311 | addi r11, r10, 0x1000 |
@@ -318,12 +320,16 @@ InstructionTLBMiss: | |||
318 | /* If we are faulting a kernel address, we have to use the | 320 | /* If we are faulting a kernel address, we have to use the |
319 | * kernel page tables. | 321 | * kernel page tables. |
320 | */ | 322 | */ |
323 | #ifdef CONFIG_MODULES | ||
324 | /* Only modules will cause ITLB Misses as we always | ||
325 | * pin the first 8MB of kernel memory */ | ||
321 | andi. r11, r10, 0x0800 /* Address >= 0x80000000 */ | 326 | andi. r11, r10, 0x0800 /* Address >= 0x80000000 */ |
322 | beq 3f | 327 | beq 3f |
323 | lis r11, swapper_pg_dir@h | 328 | lis r11, swapper_pg_dir@h |
324 | ori r11, r11, swapper_pg_dir@l | 329 | ori r11, r11, swapper_pg_dir@l |
325 | rlwimi r10, r11, 0, 2, 19 | 330 | rlwimi r10, r11, 0, 2, 19 |
326 | 3: | 331 | 3: |
332 | #endif | ||
327 | lwz r11, 0(r10) /* Get the level 1 entry */ | 333 | lwz r11, 0(r10) /* Get the level 1 entry */ |
328 | rlwinm. r10, r11,0,0,19 /* Extract page descriptor page address */ | 334 | rlwinm. r10, r11,0,0,19 /* Extract page descriptor page address */ |
329 | beq 2f /* If zero, don't try to find a pte */ | 335 | beq 2f /* If zero, don't try to find a pte */ |
@@ -339,31 +345,35 @@ InstructionTLBMiss: | |||
339 | mfspr r11, SPRN_MD_TWC /* ....and get the pte address */ | 345 | mfspr r11, SPRN_MD_TWC /* ....and get the pte address */ |
340 | lwz r10, 0(r11) /* Get the pte */ | 346 | lwz r10, 0(r11) /* Get the pte */ |
341 | 347 | ||
348 | #ifdef CONFIG_SWAP | ||
342 | andi. r11, r10, _PAGE_ACCESSED | _PAGE_PRESENT | 349 | andi. r11, r10, _PAGE_ACCESSED | _PAGE_PRESENT |
343 | cmpwi cr0, r11, _PAGE_ACCESSED | _PAGE_PRESENT | 350 | cmpwi cr0, r11, _PAGE_ACCESSED | _PAGE_PRESENT |
344 | bne- cr0, 2f | 351 | bne- cr0, 2f |
345 | 352 | #endif | |
346 | /* Clear PP lsb, 0x400 */ | ||
347 | rlwinm r10, r10, 0, 22, 20 | ||
348 | |||
349 | /* The Linux PTE won't go exactly into the MMU TLB. | 353 | /* The Linux PTE won't go exactly into the MMU TLB. |
350 | * Software indicator bits 22 and 28 must be clear. | 354 | * Software indicator bits 21 and 28 must be clear. |
351 | * Software indicator bits 24, 25, 26, and 27 must be | 355 | * Software indicator bits 24, 25, 26, and 27 must be |
352 | * set. All other Linux PTE bits control the behavior | 356 | * set. All other Linux PTE bits control the behavior |
353 | * of the MMU. | 357 | * of the MMU. |
354 | */ | 358 | */ |
355 | li r11, 0x00f0 | 359 | li r11, 0x00f0 |
356 | rlwimi r10, r11, 0, 24, 28 /* Set 24-27, clear 28 */ | 360 | rlwimi r10, r11, 0, 0x07f8 /* Set 24-27, clear 21-23,28 */ |
357 | DO_8xx_CPU6(0x2d80, r3) | 361 | DO_8xx_CPU6(0x2d80, r3) |
358 | mtspr SPRN_MI_RPN, r10 /* Update TLB entry */ | 362 | mtspr SPRN_MI_RPN, r10 /* Update TLB entry */ |
359 | 363 | ||
360 | mfspr r10, SPRN_M_TW /* Restore registers */ | 364 | /* Restore registers */ |
365 | #ifndef CONFIG_8xx_CPU6 | ||
366 | mfspr r10, SPRN_DAR | ||
367 | mtcr r10 | ||
368 | mtspr SPRN_DAR, r11 /* Tag DAR */ | ||
369 | mfspr r11, SPRN_SPRG2 | ||
370 | #else | ||
361 | lwz r11, 0(r0) | 371 | lwz r11, 0(r0) |
362 | mtcr r11 | 372 | mtcr r11 |
363 | lwz r11, 4(r0) | 373 | lwz r11, 4(r0) |
364 | #ifdef CONFIG_8xx_CPU6 | ||
365 | lwz r3, 8(r0) | 374 | lwz r3, 8(r0) |
366 | #endif | 375 | #endif |
376 | mfspr r10, SPRN_M_TW | ||
367 | rfi | 377 | rfi |
368 | 2: | 378 | 2: |
369 | mfspr r11, SPRN_SRR1 | 379 | mfspr r11, SPRN_SRR1 |
@@ -373,13 +383,20 @@ InstructionTLBMiss: | |||
373 | rlwinm r11, r11, 0, 0xffff | 383 | rlwinm r11, r11, 0, 0xffff |
374 | mtspr SPRN_SRR1, r11 | 384 | mtspr SPRN_SRR1, r11 |
375 | 385 | ||
376 | mfspr r10, SPRN_M_TW /* Restore registers */ | 386 | /* Restore registers */ |
387 | #ifndef CONFIG_8xx_CPU6 | ||
388 | mfspr r10, SPRN_DAR | ||
389 | mtcr r10 | ||
390 | li r11, 0x00f0 | ||
391 | mtspr SPRN_DAR, r11 /* Tag DAR */ | ||
392 | mfspr r11, SPRN_SPRG2 | ||
393 | #else | ||
377 | lwz r11, 0(r0) | 394 | lwz r11, 0(r0) |
378 | mtcr r11 | 395 | mtcr r11 |
379 | lwz r11, 4(r0) | 396 | lwz r11, 4(r0) |
380 | #ifdef CONFIG_8xx_CPU6 | ||
381 | lwz r3, 8(r0) | 397 | lwz r3, 8(r0) |
382 | #endif | 398 | #endif |
399 | mfspr r10, SPRN_M_TW | ||
383 | b InstructionAccess | 400 | b InstructionAccess |
384 | 401 | ||
385 | . = 0x1200 | 402 | . = 0x1200 |
@@ -390,8 +407,13 @@ DataStoreTLBMiss: | |||
390 | DO_8xx_CPU6(0x3f80, r3) | 407 | DO_8xx_CPU6(0x3f80, r3) |
391 | mtspr SPRN_M_TW, r10 /* Save a couple of working registers */ | 408 | mtspr SPRN_M_TW, r10 /* Save a couple of working registers */ |
392 | mfcr r10 | 409 | mfcr r10 |
410 | #ifdef CONFIG_8xx_CPU6 | ||
393 | stw r10, 0(r0) | 411 | stw r10, 0(r0) |
394 | stw r11, 4(r0) | 412 | stw r11, 4(r0) |
413 | #else | ||
414 | mtspr SPRN_DAR, r10 | ||
415 | mtspr SPRN_SPRG2, r11 | ||
416 | #endif | ||
395 | mfspr r10, SPRN_M_TWB /* Get level 1 table entry address */ | 417 | mfspr r10, SPRN_M_TWB /* Get level 1 table entry address */ |
396 | 418 | ||
397 | /* If we are faulting a kernel address, we have to use the | 419 | /* If we are faulting a kernel address, we have to use the |
@@ -438,15 +460,14 @@ DataStoreTLBMiss: | |||
438 | * r11 = ((r10 & PRESENT) & ((r10 & ACCESSED) >> 5)); | 460 | * r11 = ((r10 & PRESENT) & ((r10 & ACCESSED) >> 5)); |
439 | * r10 = (r10 & ~PRESENT) | r11; | 461 | * r10 = (r10 & ~PRESENT) | r11; |
440 | */ | 462 | */ |
463 | #ifdef CONFIG_SWAP | ||
441 | rlwinm r11, r10, 32-5, _PAGE_PRESENT | 464 | rlwinm r11, r10, 32-5, _PAGE_PRESENT |
442 | and r11, r11, r10 | 465 | and r11, r11, r10 |
443 | rlwimi r10, r11, 0, _PAGE_PRESENT | 466 | rlwimi r10, r11, 0, _PAGE_PRESENT |
444 | 467 | #endif | |
445 | /* Honour kernel RO, User NA */ | 468 | /* Honour kernel RO, User NA */ |
446 | /* 0x200 == Extended encoding, bit 22 */ | 469 | /* 0x200 == Extended encoding, bit 22 */ |
447 | /* r11 = (r10 & _PAGE_USER) >> 2 */ | 470 | rlwimi r10, r10, 32-2, 0x200 /* Copy USER to bit 22, 0x200 */ |
448 | rlwinm r11, r10, 32-2, 0x200 | ||
449 | or r10, r11, r10 | ||
450 | /* r11 = (r10 & _PAGE_RW) >> 1 */ | 471 | /* r11 = (r10 & _PAGE_RW) >> 1 */ |
451 | rlwinm r11, r10, 32-1, 0x200 | 472 | rlwinm r11, r10, 32-1, 0x200 |
452 | or r10, r11, r10 | 473 | or r10, r11, r10 |
@@ -460,18 +481,24 @@ DataStoreTLBMiss: | |||
460 | * of the MMU. | 481 | * of the MMU. |
461 | */ | 482 | */ |
462 | 2: li r11, 0x00f0 | 483 | 2: li r11, 0x00f0 |
463 | mtspr SPRN_DAR,r11 /* Tag DAR */ | ||
464 | rlwimi r10, r11, 0, 24, 28 /* Set 24-27, clear 28 */ | 484 | rlwimi r10, r11, 0, 24, 28 /* Set 24-27, clear 28 */ |
465 | DO_8xx_CPU6(0x3d80, r3) | 485 | DO_8xx_CPU6(0x3d80, r3) |
466 | mtspr SPRN_MD_RPN, r10 /* Update TLB entry */ | 486 | mtspr SPRN_MD_RPN, r10 /* Update TLB entry */ |
467 | 487 | ||
468 | mfspr r10, SPRN_M_TW /* Restore registers */ | 488 | /* Restore registers */ |
489 | #ifndef CONFIG_8xx_CPU6 | ||
490 | mfspr r10, SPRN_DAR | ||
491 | mtcr r10 | ||
492 | mtspr SPRN_DAR, r11 /* Tag DAR */ | ||
493 | mfspr r11, SPRN_SPRG2 | ||
494 | #else | ||
495 | mtspr SPRN_DAR, r11 /* Tag DAR */ | ||
469 | lwz r11, 0(r0) | 496 | lwz r11, 0(r0) |
470 | mtcr r11 | 497 | mtcr r11 |
471 | lwz r11, 4(r0) | 498 | lwz r11, 4(r0) |
472 | #ifdef CONFIG_8xx_CPU6 | ||
473 | lwz r3, 8(r0) | 499 | lwz r3, 8(r0) |
474 | #endif | 500 | #endif |
501 | mfspr r10, SPRN_M_TW | ||
475 | rfi | 502 | rfi |
476 | 503 | ||
477 | /* This is an instruction TLB error on the MPC8xx. This could be due | 504 | /* This is an instruction TLB error on the MPC8xx. This could be due |
@@ -683,9 +710,6 @@ start_here: | |||
683 | tophys(r4,r2) | 710 | tophys(r4,r2) |
684 | addi r4,r4,THREAD /* init task's THREAD */ | 711 | addi r4,r4,THREAD /* init task's THREAD */ |
685 | mtspr SPRN_SPRG_THREAD,r4 | 712 | mtspr SPRN_SPRG_THREAD,r4 |
686 | li r3,0 | ||
687 | /* XXX What is that for ? SPRG2 appears otherwise unused on 8xx */ | ||
688 | mtspr SPRN_SPRG2,r3 /* 0 => r1 has kernel sp */ | ||
689 | 713 | ||
690 | /* stack */ | 714 | /* stack */ |
691 | lis r1,init_thread_union@ha | 715 | lis r1,init_thread_union@ha |