diff options
Diffstat (limited to 'arch/powerpc/kernel/exceptions-64e.S')
-rw-r--r-- | arch/powerpc/kernel/exceptions-64e.S | 204 |
1 files changed, 197 insertions, 7 deletions
diff --git a/arch/powerpc/kernel/exceptions-64e.S b/arch/powerpc/kernel/exceptions-64e.S index 5c43063d2506..d24d4400cc79 100644 --- a/arch/powerpc/kernel/exceptions-64e.S +++ b/arch/powerpc/kernel/exceptions-64e.S | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <asm/cputable.h> | 17 | #include <asm/cputable.h> |
18 | #include <asm/setup.h> | 18 | #include <asm/setup.h> |
19 | #include <asm/thread_info.h> | 19 | #include <asm/thread_info.h> |
20 | #include <asm/reg_a2.h> | ||
20 | #include <asm/exception-64e.h> | 21 | #include <asm/exception-64e.h> |
21 | #include <asm/bug.h> | 22 | #include <asm/bug.h> |
22 | #include <asm/irqflags.h> | 23 | #include <asm/irqflags.h> |
@@ -252,9 +253,6 @@ exception_marker: | |||
252 | .balign 0x1000 | 253 | .balign 0x1000 |
253 | .globl interrupt_base_book3e | 254 | .globl interrupt_base_book3e |
254 | interrupt_base_book3e: /* fake trap */ | 255 | interrupt_base_book3e: /* fake trap */ |
255 | /* Note: If real debug exceptions are supported by the HW, the vector | ||
256 | * below will have to be patched up to point to an appropriate handler | ||
257 | */ | ||
258 | EXCEPTION_STUB(0x000, machine_check) /* 0x0200 */ | 256 | EXCEPTION_STUB(0x000, machine_check) /* 0x0200 */ |
259 | EXCEPTION_STUB(0x020, critical_input) /* 0x0580 */ | 257 | EXCEPTION_STUB(0x020, critical_input) /* 0x0580 */ |
260 | EXCEPTION_STUB(0x040, debug_crit) /* 0x0d00 */ | 258 | EXCEPTION_STUB(0x040, debug_crit) /* 0x0d00 */ |
@@ -271,8 +269,13 @@ interrupt_base_book3e: /* fake trap */ | |||
271 | EXCEPTION_STUB(0x1a0, watchdog) /* 0x09f0 */ | 269 | EXCEPTION_STUB(0x1a0, watchdog) /* 0x09f0 */ |
272 | EXCEPTION_STUB(0x1c0, data_tlb_miss) | 270 | EXCEPTION_STUB(0x1c0, data_tlb_miss) |
273 | EXCEPTION_STUB(0x1e0, instruction_tlb_miss) | 271 | EXCEPTION_STUB(0x1e0, instruction_tlb_miss) |
272 | EXCEPTION_STUB(0x260, perfmon) | ||
274 | EXCEPTION_STUB(0x280, doorbell) | 273 | EXCEPTION_STUB(0x280, doorbell) |
275 | EXCEPTION_STUB(0x2a0, doorbell_crit) | 274 | EXCEPTION_STUB(0x2a0, doorbell_crit) |
275 | EXCEPTION_STUB(0x2c0, guest_doorbell) | ||
276 | EXCEPTION_STUB(0x2e0, guest_doorbell_crit) | ||
277 | EXCEPTION_STUB(0x300, hypercall) | ||
278 | EXCEPTION_STUB(0x320, ehpriv) | ||
276 | 279 | ||
277 | .globl interrupt_end_book3e | 280 | .globl interrupt_end_book3e |
278 | interrupt_end_book3e: | 281 | interrupt_end_book3e: |
@@ -379,7 +382,7 @@ interrupt_end_book3e: | |||
379 | mfspr r13,SPRN_SPRG_PACA /* get our PACA */ | 382 | mfspr r13,SPRN_SPRG_PACA /* get our PACA */ |
380 | b system_call_common | 383 | b system_call_common |
381 | 384 | ||
382 | /* Auxillary Processor Unavailable Interrupt */ | 385 | /* Auxiliary Processor Unavailable Interrupt */ |
383 | START_EXCEPTION(ap_unavailable); | 386 | START_EXCEPTION(ap_unavailable); |
384 | NORMAL_EXCEPTION_PROLOG(0xf20, PROLOG_ADDITION_NONE) | 387 | NORMAL_EXCEPTION_PROLOG(0xf20, PROLOG_ADDITION_NONE) |
385 | EXCEPTION_COMMON(0xf20, PACA_EXGEN, INTS_KEEP) | 388 | EXCEPTION_COMMON(0xf20, PACA_EXGEN, INTS_KEEP) |
@@ -454,6 +457,70 @@ interrupt_end_book3e: | |||
454 | kernel_dbg_exc: | 457 | kernel_dbg_exc: |
455 | b . /* NYI */ | 458 | b . /* NYI */ |
456 | 459 | ||
460 | /* Debug exception as a debug interrupt*/ | ||
461 | START_EXCEPTION(debug_debug); | ||
462 | DBG_EXCEPTION_PROLOG(0xd00, PROLOG_ADDITION_2REGS) | ||
463 | |||
464 | /* | ||
465 | * If there is a single step or branch-taken exception in an | ||
466 | * exception entry sequence, it was probably meant to apply to | ||
467 | * the code where the exception occurred (since exception entry | ||
468 | * doesn't turn off DE automatically). We simulate the effect | ||
469 | * of turning off DE on entry to an exception handler by turning | ||
470 | * off DE in the DSRR1 value and clearing the debug status. | ||
471 | */ | ||
472 | |||
473 | mfspr r14,SPRN_DBSR /* check single-step/branch taken */ | ||
474 | andis. r15,r14,DBSR_IC@h | ||
475 | beq+ 1f | ||
476 | |||
477 | LOAD_REG_IMMEDIATE(r14,interrupt_base_book3e) | ||
478 | LOAD_REG_IMMEDIATE(r15,interrupt_end_book3e) | ||
479 | cmpld cr0,r10,r14 | ||
480 | cmpld cr1,r10,r15 | ||
481 | blt+ cr0,1f | ||
482 | bge+ cr1,1f | ||
483 | |||
484 | /* here it looks like we got an inappropriate debug exception. */ | ||
485 | lis r14,DBSR_IC@h /* clear the IC event */ | ||
486 | rlwinm r11,r11,0,~MSR_DE /* clear DE in the DSRR1 value */ | ||
487 | mtspr SPRN_DBSR,r14 | ||
488 | mtspr SPRN_DSRR1,r11 | ||
489 | lwz r10,PACA_EXDBG+EX_CR(r13) /* restore registers */ | ||
490 | ld r1,PACA_EXDBG+EX_R1(r13) | ||
491 | ld r14,PACA_EXDBG+EX_R14(r13) | ||
492 | ld r15,PACA_EXDBG+EX_R15(r13) | ||
493 | mtcr r10 | ||
494 | ld r10,PACA_EXDBG+EX_R10(r13) /* restore registers */ | ||
495 | ld r11,PACA_EXDBG+EX_R11(r13) | ||
496 | mfspr r13,SPRN_SPRG_DBG_SCRATCH | ||
497 | rfdi | ||
498 | |||
499 | /* Normal debug exception */ | ||
500 | /* XXX We only handle coming from userspace for now since we can't | ||
501 | * quite save properly an interrupted kernel state yet | ||
502 | */ | ||
503 | 1: andi. r14,r11,MSR_PR; /* check for userspace again */ | ||
504 | beq kernel_dbg_exc; /* if from kernel mode */ | ||
505 | |||
506 | /* Now we mash up things to make it look like we are coming on a | ||
507 | * normal exception | ||
508 | */ | ||
509 | mfspr r15,SPRN_SPRG_DBG_SCRATCH | ||
510 | mtspr SPRN_SPRG_GEN_SCRATCH,r15 | ||
511 | mfspr r14,SPRN_DBSR | ||
512 | EXCEPTION_COMMON(0xd00, PACA_EXDBG, INTS_DISABLE_ALL) | ||
513 | std r14,_DSISR(r1) | ||
514 | addi r3,r1,STACK_FRAME_OVERHEAD | ||
515 | mr r4,r14 | ||
516 | ld r14,PACA_EXDBG+EX_R14(r13) | ||
517 | ld r15,PACA_EXDBG+EX_R15(r13) | ||
518 | bl .save_nvgprs | ||
519 | bl .DebugException | ||
520 | b .ret_from_except | ||
521 | |||
522 | MASKABLE_EXCEPTION(0x260, perfmon, .performance_monitor_exception, ACK_NONE) | ||
523 | |||
457 | /* Doorbell interrupt */ | 524 | /* Doorbell interrupt */ |
458 | MASKABLE_EXCEPTION(0x2070, doorbell, .doorbell_exception, ACK_NONE) | 525 | MASKABLE_EXCEPTION(0x2070, doorbell, .doorbell_exception, ACK_NONE) |
459 | 526 | ||
@@ -468,6 +535,11 @@ kernel_dbg_exc: | |||
468 | // b ret_from_crit_except | 535 | // b ret_from_crit_except |
469 | b . | 536 | b . |
470 | 537 | ||
538 | MASKABLE_EXCEPTION(0x2c0, guest_doorbell, .unknown_exception, ACK_NONE) | ||
539 | MASKABLE_EXCEPTION(0x2e0, guest_doorbell_crit, .unknown_exception, ACK_NONE) | ||
540 | MASKABLE_EXCEPTION(0x310, hypercall, .unknown_exception, ACK_NONE) | ||
541 | MASKABLE_EXCEPTION(0x320, ehpriv, .unknown_exception, ACK_NONE) | ||
542 | |||
471 | 543 | ||
472 | /* | 544 | /* |
473 | * An interrupt came in while soft-disabled; clear EE in SRR1, | 545 | * An interrupt came in while soft-disabled; clear EE in SRR1, |
@@ -587,7 +659,12 @@ fast_exception_return: | |||
587 | BAD_STACK_TRAMPOLINE(0x000) | 659 | BAD_STACK_TRAMPOLINE(0x000) |
588 | BAD_STACK_TRAMPOLINE(0x100) | 660 | BAD_STACK_TRAMPOLINE(0x100) |
589 | BAD_STACK_TRAMPOLINE(0x200) | 661 | BAD_STACK_TRAMPOLINE(0x200) |
662 | BAD_STACK_TRAMPOLINE(0x260) | ||
663 | BAD_STACK_TRAMPOLINE(0x2c0) | ||
664 | BAD_STACK_TRAMPOLINE(0x2e0) | ||
590 | BAD_STACK_TRAMPOLINE(0x300) | 665 | BAD_STACK_TRAMPOLINE(0x300) |
666 | BAD_STACK_TRAMPOLINE(0x310) | ||
667 | BAD_STACK_TRAMPOLINE(0x320) | ||
591 | BAD_STACK_TRAMPOLINE(0x400) | 668 | BAD_STACK_TRAMPOLINE(0x400) |
592 | BAD_STACK_TRAMPOLINE(0x500) | 669 | BAD_STACK_TRAMPOLINE(0x500) |
593 | BAD_STACK_TRAMPOLINE(0x600) | 670 | BAD_STACK_TRAMPOLINE(0x600) |
@@ -864,8 +941,23 @@ have_hes: | |||
864 | * that will have to be made dependent on whether we are running under | 941 | * that will have to be made dependent on whether we are running under |
865 | * a hypervisor I suppose. | 942 | * a hypervisor I suppose. |
866 | */ | 943 | */ |
867 | ori r3,r3,MAS0_HES | MAS0_WQ_ALLWAYS | 944 | |
868 | mtspr SPRN_MAS0,r3 | 945 | /* BEWARE, MAGIC |
946 | * This code is called as an ordinary function on the boot CPU. But to | ||
947 | * avoid duplication, this code is also used in SCOM bringup of | ||
948 | * secondary CPUs. We read the code between the initial_tlb_code_start | ||
949 | * and initial_tlb_code_end labels one instruction at a time and RAM it | ||
950 | * into the new core via SCOM. That doesn't process branches, so there | ||
951 | * must be none between those two labels. It also means if this code | ||
952 | * ever takes any parameters, the SCOM code must also be updated to | ||
953 | * provide them. | ||
954 | */ | ||
955 | .globl a2_tlbinit_code_start | ||
956 | a2_tlbinit_code_start: | ||
957 | |||
958 | ori r11,r3,MAS0_WQ_ALLWAYS | ||
959 | oris r11,r11,MAS0_ESEL(3)@h /* Use way 3: workaround A2 erratum 376 */ | ||
960 | mtspr SPRN_MAS0,r11 | ||
869 | lis r3,(MAS1_VALID | MAS1_IPROT)@h | 961 | lis r3,(MAS1_VALID | MAS1_IPROT)@h |
870 | ori r3,r3,BOOK3E_PAGESZ_1GB << MAS1_TSIZE_SHIFT | 962 | ori r3,r3,BOOK3E_PAGESZ_1GB << MAS1_TSIZE_SHIFT |
871 | mtspr SPRN_MAS1,r3 | 963 | mtspr SPRN_MAS1,r3 |
@@ -879,18 +971,86 @@ have_hes: | |||
879 | /* Write the TLB entry */ | 971 | /* Write the TLB entry */ |
880 | tlbwe | 972 | tlbwe |
881 | 973 | ||
974 | .globl a2_tlbinit_after_linear_map | ||
975 | a2_tlbinit_after_linear_map: | ||
976 | |||
882 | /* Now we branch the new virtual address mapped by this entry */ | 977 | /* Now we branch the new virtual address mapped by this entry */ |
883 | LOAD_REG_IMMEDIATE(r3,1f) | 978 | LOAD_REG_IMMEDIATE(r3,1f) |
884 | mtctr r3 | 979 | mtctr r3 |
885 | bctr | 980 | bctr |
886 | 981 | ||
887 | 1: /* We are now running at PAGE_OFFSET, clean the TLB of everything | 982 | 1: /* We are now running at PAGE_OFFSET, clean the TLB of everything |
888 | * else (XXX we should scan for bolted crap from the firmware too) | 983 | * else (including IPROTed things left by firmware) |
984 | * r4 = TLBnCFG | ||
985 | * r3 = current address (more or less) | ||
889 | */ | 986 | */ |
987 | |||
988 | li r5,0 | ||
989 | mtspr SPRN_MAS6,r5 | ||
990 | tlbsx 0,r3 | ||
991 | |||
992 | rlwinm r9,r4,0,TLBnCFG_N_ENTRY | ||
993 | rlwinm r10,r4,8,0xff | ||
994 | addi r10,r10,-1 /* Get inner loop mask */ | ||
995 | |||
996 | li r3,1 | ||
997 | |||
998 | mfspr r5,SPRN_MAS1 | ||
999 | rlwinm r5,r5,0,(~(MAS1_VALID|MAS1_IPROT)) | ||
1000 | |||
1001 | mfspr r6,SPRN_MAS2 | ||
1002 | rldicr r6,r6,0,51 /* Extract EPN */ | ||
1003 | |||
1004 | mfspr r7,SPRN_MAS0 | ||
1005 | rlwinm r7,r7,0,0xffff0fff /* Clear HES and WQ */ | ||
1006 | |||
1007 | rlwinm r8,r7,16,0xfff /* Extract ESEL */ | ||
1008 | |||
1009 | 2: add r4,r3,r8 | ||
1010 | and r4,r4,r10 | ||
1011 | |||
1012 | rlwimi r7,r4,16,MAS0_ESEL_MASK | ||
1013 | |||
1014 | mtspr SPRN_MAS0,r7 | ||
1015 | mtspr SPRN_MAS1,r5 | ||
1016 | mtspr SPRN_MAS2,r6 | ||
1017 | tlbwe | ||
1018 | |||
1019 | addi r3,r3,1 | ||
1020 | and. r4,r3,r10 | ||
1021 | |||
1022 | bne 3f | ||
1023 | addis r6,r6,(1<<30)@h | ||
1024 | 3: | ||
1025 | cmpw r3,r9 | ||
1026 | blt 2b | ||
1027 | |||
1028 | .globl a2_tlbinit_after_iprot_flush | ||
1029 | a2_tlbinit_after_iprot_flush: | ||
1030 | |||
1031 | #ifdef CONFIG_PPC_EARLY_DEBUG_WSP | ||
1032 | /* Now establish early debug mappings if applicable */ | ||
1033 | /* Restore the MAS0 we used for linear mapping load */ | ||
1034 | mtspr SPRN_MAS0,r11 | ||
1035 | |||
1036 | lis r3,(MAS1_VALID | MAS1_IPROT)@h | ||
1037 | ori r3,r3,(BOOK3E_PAGESZ_4K << MAS1_TSIZE_SHIFT) | ||
1038 | mtspr SPRN_MAS1,r3 | ||
1039 | LOAD_REG_IMMEDIATE(r3, WSP_UART_VIRT | MAS2_I | MAS2_G) | ||
1040 | mtspr SPRN_MAS2,r3 | ||
1041 | LOAD_REG_IMMEDIATE(r3, WSP_UART_PHYS | MAS3_SR | MAS3_SW) | ||
1042 | mtspr SPRN_MAS7_MAS3,r3 | ||
1043 | /* re-use the MAS8 value from the linear mapping */ | ||
1044 | tlbwe | ||
1045 | #endif /* CONFIG_PPC_EARLY_DEBUG_WSP */ | ||
1046 | |||
890 | PPC_TLBILX(0,0,0) | 1047 | PPC_TLBILX(0,0,0) |
891 | sync | 1048 | sync |
892 | isync | 1049 | isync |
893 | 1050 | ||
1051 | .globl a2_tlbinit_code_end | ||
1052 | a2_tlbinit_code_end: | ||
1053 | |||
894 | /* We translate LR and return */ | 1054 | /* We translate LR and return */ |
895 | mflr r3 | 1055 | mflr r3 |
896 | tovirt(r3,r3) | 1056 | tovirt(r3,r3) |
@@ -1040,3 +1200,33 @@ _GLOBAL(__setup_base_ivors) | |||
1040 | sync | 1200 | sync |
1041 | 1201 | ||
1042 | blr | 1202 | blr |
1203 | |||
1204 | _GLOBAL(setup_perfmon_ivor) | ||
1205 | SET_IVOR(35, 0x260) /* Performance Monitor */ | ||
1206 | blr | ||
1207 | |||
1208 | _GLOBAL(setup_doorbell_ivors) | ||
1209 | SET_IVOR(36, 0x280) /* Processor Doorbell */ | ||
1210 | SET_IVOR(37, 0x2a0) /* Processor Doorbell Crit */ | ||
1211 | |||
1212 | /* Check MMUCFG[LPIDSIZE] to determine if we have category E.HV */ | ||
1213 | mfspr r10,SPRN_MMUCFG | ||
1214 | rlwinm. r10,r10,0,MMUCFG_LPIDSIZE | ||
1215 | beqlr | ||
1216 | |||
1217 | SET_IVOR(38, 0x2c0) /* Guest Processor Doorbell */ | ||
1218 | SET_IVOR(39, 0x2e0) /* Guest Processor Doorbell Crit/MC */ | ||
1219 | blr | ||
1220 | |||
1221 | _GLOBAL(setup_ehv_ivors) | ||
1222 | /* | ||
1223 | * We may be running as a guest and lack E.HV even on a chip | ||
1224 | * that normally has it. | ||
1225 | */ | ||
1226 | mfspr r10,SPRN_MMUCFG | ||
1227 | rlwinm. r10,r10,0,MMUCFG_LPIDSIZE | ||
1228 | beqlr | ||
1229 | |||
1230 | SET_IVOR(40, 0x300) /* Embedded Hypervisor System Call */ | ||
1231 | SET_IVOR(41, 0x320) /* Embedded Hypervisor Privilege */ | ||
1232 | blr | ||