diff options
| -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 */ |
