aboutsummaryrefslogtreecommitdiffstats
path: root/arch/microblaze
diff options
context:
space:
mode:
authorMichal Simek <monstr@monstr.eu>2009-07-21 06:48:01 -0400
committerMichal Simek <monstr@monstr.eu>2009-07-27 03:03:15 -0400
commit3863dbceac7e69642b95f43de1c12c6236fdbe5b (patch)
treed6e9a0d01784ca1c9e321971a3571fe2bf8b17dc /arch/microblaze
parent94ad8eb854cbc1cf875a318f9b97314ddc6b1560 (diff)
microblaze: Support unaligned address for put/get_user macros
This patch add support for cases where load/store instruction in put/get_user macro gets unaligned pointer to data and this address is not valid. I prevent all cases which can failed. I had to disable first stage of unaligned handler which is used only for noMMU kernel and the whole work is done when interrupt is enabled. You have enable HW support for detect unaligned access in Microblaze. This patch fixed three LTP tests: getpeername01, getsockname01, socketpair01 Signed-off-by: Michal Simek <monstr@monstr.eu>
Diffstat (limited to 'arch/microblaze')
-rw-r--r--arch/microblaze/kernel/hw_exception_handler.S109
-rw-r--r--arch/microblaze/mm/fault.c2
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 */
960ex_lw_vm: 912ex_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 */ 914load1: 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; 918load2: lbui r5, r4, 1;
967 sbi r5, r6, 1; 919 sbi r5, r6, 1;
968 lbui r5, r4, 2; 920load3: lbui r5, r4, 2;
969 sbi r5, r6, 2; 921 sbi r5, r6, 2;
970 lbui r5, r4, 3; 922load4: 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; 932load5: 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 */
983ex_lw_tail_vm: 935ex_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; 951store1: sbi r3, r4, 0;
1000 lbui r3, r5, 1; 952 lbui r3, r5, 1;
1001 sbi r3, r4, 1; 953store2: sbi r3, r4, 1;
1002 lbui r3, r5, 2; 954 lbui r3, r5, 2;
1003 sbi r3, r4, 2; 955store3: 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 */ 958store4: sbi r3, r4, 3; /* Delay slot */
1007ex_shw_vm: 959ex_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; 962store5: 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 */ 965store6: sbi r3, r4, 1; /* Delay slot */
1014ex_sw_end_vm: /* Exception handling of store word, ends. */ 966ex_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 */
972ex_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 */
72static void bad_page_fault(struct pt_regs *regs, unsigned long address, int sig) 72void 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 */