diff options
Diffstat (limited to 'arch')
-rw-r--r-- | arch/microblaze/kernel/hw_exception_handler.S | 109 | ||||
-rw-r--r-- | arch/microblaze/mm/fault.c | 2 |
2 files changed, 47 insertions, 64 deletions
diff --git a/arch/microblaze/kernel/hw_exception_handler.S b/arch/microblaze/kernel/hw_exception_handler.S index 9d591cd74fc2..3288c9737671 100644 --- a/arch/microblaze/kernel/hw_exception_handler.S +++ b/arch/microblaze/kernel/hw_exception_handler.S | |||
@@ -74,6 +74,7 @@ | |||
74 | 74 | ||
75 | #include <asm/mmu.h> | 75 | #include <asm/mmu.h> |
76 | #include <asm/pgtable.h> | 76 | #include <asm/pgtable.h> |
77 | #include <asm/signal.h> | ||
77 | #include <asm/asm-offsets.h> | 78 | #include <asm/asm-offsets.h> |
78 | 79 | ||
79 | /* Helpful Macros */ | 80 | /* Helpful Macros */ |
@@ -428,19 +429,9 @@ handle_unaligned_ex: | |||
428 | mfs r17, rbtr; /* ESR[DS] set - return address in BTR */ | 429 | mfs r17, rbtr; /* ESR[DS] set - return address in BTR */ |
429 | nop | 430 | nop |
430 | _no_delayslot: | 431 | _no_delayslot: |
431 | #endif | 432 | /* jump to high level unaligned handler */ |
432 | 433 | RESTORE_STATE; | |
433 | #ifdef CONFIG_MMU | 434 | bri unaligned_data_trap |
434 | /* Check if unaligned address is last on a 4k page */ | ||
435 | andi r5, r4, 0xffc | ||
436 | xori r5, r5, 0xffc | ||
437 | bnei r5, _unaligned_ex2 | ||
438 | _unaligned_ex1: | ||
439 | RESTORE_STATE; | ||
440 | /* Another page must be accessed or physical address not in page table */ | ||
441 | bri unaligned_data_trap | ||
442 | |||
443 | _unaligned_ex2: | ||
444 | #endif | 435 | #endif |
445 | andi r6, r3, 0x3E0; /* Mask and extract the register operand */ | 436 | andi r6, r3, 0x3E0; /* Mask and extract the register operand */ |
446 | srl r6, r6; /* r6 >> 5 */ | 437 | srl r6, r6; /* r6 >> 5 */ |
@@ -450,45 +441,6 @@ _no_delayslot: | |||
450 | srl r6, r6; | 441 | srl r6, r6; |
451 | /* Store the register operand in a temporary location */ | 442 | /* Store the register operand in a temporary location */ |
452 | sbi r6, r0, TOPHYS(ex_reg_op); | 443 | sbi r6, r0, TOPHYS(ex_reg_op); |
453 | #ifdef CONFIG_MMU | ||
454 | /* Get physical address */ | ||
455 | /* If we are faulting a kernel address, we have to use the | ||
456 | * kernel page tables. | ||
457 | */ | ||
458 | ori r5, r0, CONFIG_KERNEL_START | ||
459 | cmpu r5, r4, r5 | ||
460 | bgti r5, _unaligned_ex3 | ||
461 | ori r5, r0, swapper_pg_dir | ||
462 | bri _unaligned_ex4 | ||
463 | |||
464 | /* Get the PGD for the current thread. */ | ||
465 | _unaligned_ex3: /* user thread */ | ||
466 | addi r5 ,CURRENT_TASK, TOPHYS(0); /* get current task address */ | ||
467 | lwi r5, r5, TASK_THREAD + PGDIR | ||
468 | _unaligned_ex4: | ||
469 | tophys(r5,r5) | ||
470 | BSRLI(r6,r4,20) /* Create L1 (pgdir/pmd) address */ | ||
471 | andi r6, r6, 0xffc | ||
472 | /* Assume pgdir aligned on 4K boundary, no need for "andi r5,r5,0xfffff003" */ | ||
473 | or r5, r5, r6 | ||
474 | lwi r6, r5, 0 /* Get L1 entry */ | ||
475 | andi r5, r6, 0xfffff000 /* Extract L2 (pte) base address. */ | ||
476 | beqi r5, _unaligned_ex1 /* Bail if no table */ | ||
477 | |||
478 | tophys(r5,r5) | ||
479 | BSRLI(r6,r4,10) /* Compute PTE address */ | ||
480 | andi r6, r6, 0xffc | ||
481 | andi r5, r5, 0xfffff003 | ||
482 | or r5, r5, r6 | ||
483 | lwi r5, r5, 0 /* Get Linux PTE */ | ||
484 | |||
485 | andi r6, r5, _PAGE_PRESENT | ||
486 | beqi r6, _unaligned_ex1 /* Bail if no page */ | ||
487 | |||
488 | andi r5, r5, 0xfffff000 /* Extract RPN */ | ||
489 | andi r4, r4, 0x00000fff /* Extract offset */ | ||
490 | or r4, r4, r5 /* Create physical address */ | ||
491 | #endif /* CONFIG_MMU */ | ||
492 | 444 | ||
493 | andi r6, r3, 0x400; /* Extract ESR[S] */ | 445 | andi r6, r3, 0x400; /* Extract ESR[S] */ |
494 | bnei r6, ex_sw; | 446 | bnei r6, ex_sw; |
@@ -959,15 +911,15 @@ _unaligned_data_exception: | |||
959 | andi r6, r3, 0x800; /* Extract ESR[W] - delay slot */ | 911 | andi r6, r3, 0x800; /* Extract ESR[W] - delay slot */ |
960 | ex_lw_vm: | 912 | ex_lw_vm: |
961 | beqid r6, ex_lhw_vm; | 913 | beqid r6, ex_lhw_vm; |
962 | lbui r5, r4, 0; /* Exception address in r4 - delay slot */ | 914 | load1: lbui r5, r4, 0; /* Exception address in r4 - delay slot */ |
963 | /* Load a word, byte-by-byte from destination address and save it in tmp space*/ | 915 | /* Load a word, byte-by-byte from destination address and save it in tmp space*/ |
964 | la r6, r0, ex_tmp_data_loc_0; | 916 | la r6, r0, ex_tmp_data_loc_0; |
965 | sbi r5, r6, 0; | 917 | sbi r5, r6, 0; |
966 | lbui r5, r4, 1; | 918 | load2: lbui r5, r4, 1; |
967 | sbi r5, r6, 1; | 919 | sbi r5, r6, 1; |
968 | lbui r5, r4, 2; | 920 | load3: lbui r5, r4, 2; |
969 | sbi r5, r6, 2; | 921 | sbi r5, r6, 2; |
970 | lbui r5, r4, 3; | 922 | load4: lbui r5, r4, 3; |
971 | sbi r5, r6, 3; | 923 | sbi r5, r6, 3; |
972 | brid ex_lw_tail_vm; | 924 | brid ex_lw_tail_vm; |
973 | /* Get the destination register value into r3 - delay slot */ | 925 | /* Get the destination register value into r3 - delay slot */ |
@@ -977,7 +929,7 @@ ex_lhw_vm: | |||
977 | * save it in tmp space */ | 929 | * save it in tmp space */ |
978 | la r6, r0, ex_tmp_data_loc_0; | 930 | la r6, r0, ex_tmp_data_loc_0; |
979 | sbi r5, r6, 0; | 931 | sbi r5, r6, 0; |
980 | lbui r5, r4, 1; | 932 | load5: lbui r5, r4, 1; |
981 | sbi r5, r6, 1; | 933 | sbi r5, r6, 1; |
982 | lhui r3, r6, 0; /* Get the destination register value into r3 */ | 934 | lhui r3, r6, 0; /* Get the destination register value into r3 */ |
983 | ex_lw_tail_vm: | 935 | ex_lw_tail_vm: |
@@ -996,22 +948,53 @@ ex_sw_tail_vm: | |||
996 | swi r3, r5, 0; /* Get the word - delay slot */ | 948 | swi r3, r5, 0; /* Get the word - delay slot */ |
997 | /* Store the word, byte-by-byte into destination address */ | 949 | /* Store the word, byte-by-byte into destination address */ |
998 | lbui r3, r5, 0; | 950 | lbui r3, r5, 0; |
999 | sbi r3, r4, 0; | 951 | store1: sbi r3, r4, 0; |
1000 | lbui r3, r5, 1; | 952 | lbui r3, r5, 1; |
1001 | sbi r3, r4, 1; | 953 | store2: sbi r3, r4, 1; |
1002 | lbui r3, r5, 2; | 954 | lbui r3, r5, 2; |
1003 | sbi r3, r4, 2; | 955 | store3: sbi r3, r4, 2; |
1004 | lbui r3, r5, 3; | 956 | lbui r3, r5, 3; |
1005 | brid ret_from_exc; | 957 | brid ret_from_exc; |
1006 | sbi r3, r4, 3; /* Delay slot */ | 958 | store4: sbi r3, r4, 3; /* Delay slot */ |
1007 | ex_shw_vm: | 959 | ex_shw_vm: |
1008 | /* Store the lower half-word, byte-by-byte into destination address */ | 960 | /* Store the lower half-word, byte-by-byte into destination address */ |
1009 | lbui r3, r5, 2; | 961 | lbui r3, r5, 2; |
1010 | sbi r3, r4, 0; | 962 | store5: sbi r3, r4, 0; |
1011 | lbui r3, r5, 3; | 963 | lbui r3, r5, 3; |
1012 | brid ret_from_exc; | 964 | brid ret_from_exc; |
1013 | sbi r3, r4, 1; /* Delay slot */ | 965 | store6: sbi r3, r4, 1; /* Delay slot */ |
1014 | ex_sw_end_vm: /* Exception handling of store word, ends. */ | 966 | ex_sw_end_vm: /* Exception handling of store word, ends. */ |
967 | |||
968 | /* We have to prevent cases that get/put_user macros get unaligned pointer | ||
969 | * to bad page area. We have to find out which origin instruction caused it | ||
970 | * and called fixup for that origin instruction not instruction in unaligned | ||
971 | * handler */ | ||
972 | ex_unaligned_fixup: | ||
973 | ori r5, r7, 0 /* setup pointer to pt_regs */ | ||
974 | lwi r6, r7, PT_PC; /* faulting address is one instruction above */ | ||
975 | addik r6, r6, -4 /* for finding proper fixup */ | ||
976 | swi r6, r7, PT_PC; /* a save back it to PT_PC */ | ||
977 | addik r7, r0, SIGSEGV | ||
978 | /* call bad_page_fault for finding aligned fixup, fixup address is saved | ||
979 | * in PT_PC which is used as return address from exception */ | ||
980 | la r15, r0, ret_from_exc-8 /* setup return address */ | ||
981 | brid bad_page_fault | ||
982 | nop | ||
983 | |||
984 | /* We prevent all load/store because it could failed any attempt to access */ | ||
985 | .section __ex_table,"a"; | ||
986 | .word load1,ex_unaligned_fixup; | ||
987 | .word load2,ex_unaligned_fixup; | ||
988 | .word load3,ex_unaligned_fixup; | ||
989 | .word load4,ex_unaligned_fixup; | ||
990 | .word load5,ex_unaligned_fixup; | ||
991 | .word store1,ex_unaligned_fixup; | ||
992 | .word store2,ex_unaligned_fixup; | ||
993 | .word store3,ex_unaligned_fixup; | ||
994 | .word store4,ex_unaligned_fixup; | ||
995 | .word store5,ex_unaligned_fixup; | ||
996 | .word store6,ex_unaligned_fixup; | ||
997 | .previous; | ||
1015 | .end _unaligned_data_exception | 998 | .end _unaligned_data_exception |
1016 | #endif /* CONFIG_MMU */ | 999 | #endif /* CONFIG_MMU */ |
1017 | 1000 | ||
diff --git a/arch/microblaze/mm/fault.c b/arch/microblaze/mm/fault.c index 398c76117355..d9d249a66ff2 100644 --- a/arch/microblaze/mm/fault.c +++ b/arch/microblaze/mm/fault.c | |||
@@ -69,7 +69,7 @@ static int store_updates_sp(struct pt_regs *regs) | |||
69 | * It is called from do_page_fault above and from some of the procedures | 69 | * It is called from do_page_fault above and from some of the procedures |
70 | * in traps.c. | 70 | * in traps.c. |
71 | */ | 71 | */ |
72 | static void bad_page_fault(struct pt_regs *regs, unsigned long address, int sig) | 72 | void bad_page_fault(struct pt_regs *regs, unsigned long address, int sig) |
73 | { | 73 | { |
74 | const struct exception_table_entry *fixup; | 74 | const struct exception_table_entry *fixup; |
75 | /* MS: no context */ | 75 | /* MS: no context */ |