diff options
Diffstat (limited to 'arch/avr32/kernel')
-rw-r--r-- | arch/avr32/kernel/entry-avr32b.S | 88 | ||||
-rw-r--r-- | arch/avr32/kernel/signal.c | 3 | ||||
-rw-r--r-- | arch/avr32/kernel/stacktrace.c | 1 | ||||
-rw-r--r-- | arch/avr32/kernel/time.c | 14 | ||||
-rw-r--r-- | arch/avr32/kernel/vmlinux.lds.S | 14 |
5 files changed, 64 insertions, 56 deletions
diff --git a/arch/avr32/kernel/entry-avr32b.S b/arch/avr32/kernel/entry-avr32b.S index 5f31702d6b1c..2b398cae110c 100644 --- a/arch/avr32/kernel/entry-avr32b.S +++ b/arch/avr32/kernel/entry-avr32b.S @@ -74,50 +74,41 @@ exception_vectors: .align 2 bral do_dtlb_modified - /* - * r0 : PGD/PT/PTE - * r1 : Offending address - * r2 : Scratch register - * r3 : Cause (5, 12 or 13) - */ #define tlbmiss_save pushm r0-r3 #define tlbmiss_restore popm r0-r3 - .section .tlbx.ex.text,"ax",@progbits + .org 0x50 .global itlb_miss itlb_miss: tlbmiss_save rjmp tlb_miss_common - .section .tlbr.ex.text,"ax",@progbits + .org 0x60 dtlb_miss_read: tlbmiss_save rjmp tlb_miss_common - .section .tlbw.ex.text,"ax",@progbits + .org 0x70 dtlb_miss_write: tlbmiss_save .global tlb_miss_common + .align 2 tlb_miss_common: mfsr r0, SYSREG_TLBEAR mfsr r1, SYSREG_PTBR - /* Is it the vmalloc space? */ - bld r0, 31 - brcs handle_vmalloc_miss - - /* First level lookup */ + /* + * First level lookup: The PGD contains virtual pointers to + * the second-level page tables, but they may be NULL if not + * present. + */ pgtbl_lookup: lsr r2, r0, PGDIR_SHIFT ld.w r3, r1[r2 << 2] bfextu r1, r0, PAGE_SHIFT, PGDIR_SHIFT - PAGE_SHIFT - bld r3, _PAGE_BIT_PRESENT - brcc page_table_not_present - - /* Translate to virtual address in P1. */ - andl r3, 0xf000 - sbr r3, 31 + cp.w r3, 0 + breq page_table_not_present /* Second level lookup */ ld.w r2, r3[r1 << 2] @@ -148,16 +139,55 @@ pgtbl_lookup: tlbmiss_restore rete -handle_vmalloc_miss: - /* Simply do the lookup in init's page table */ + /* The slow path of the TLB miss handler */ + .align 2 +page_table_not_present: + /* Do we need to synchronize with swapper_pg_dir? */ + bld r0, 31 + brcs sync_with_swapper_pg_dir + +page_not_present: + tlbmiss_restore + sub sp, 4 + stmts --sp, r0-lr + rcall save_full_context_ex + mfsr r12, SYSREG_ECR + mov r11, sp + rcall do_page_fault + rjmp ret_from_exception + + .align 2 +sync_with_swapper_pg_dir: + /* + * If swapper_pg_dir contains a non-NULL second-level page + * table pointer, copy it into the current PGD. If not, we + * must handle it as a full-blown page fault. + * + * Jumping back to pgtbl_lookup causes an unnecessary lookup, + * but it is guaranteed to be a cache hit, it won't happen + * very often, and we absolutely do not want to sacrifice any + * performance in the fast path in order to improve this. + */ mov r1, lo(swapper_pg_dir) orh r1, hi(swapper_pg_dir) + ld.w r3, r1[r2 << 2] + cp.w r3, 0 + breq page_not_present + mfsr r1, SYSREG_PTBR + st.w r1[r2 << 2], r3 rjmp pgtbl_lookup + /* + * We currently have two bytes left at this point until we + * crash into the system call handler... + * + * Don't worry, the assembler will let us know. + */ + /* --- System Call --- */ - .section .scall.text,"ax",@progbits + .org 0x100 system_call: #ifdef CONFIG_PREEMPT mask_interrupts @@ -266,18 +296,6 @@ syscall_exit_work: brcc syscall_exit_cont rjmp enter_monitor_mode - /* The slow path of the TLB miss handler */ -page_table_not_present: -page_not_present: - tlbmiss_restore - sub sp, 4 - stmts --sp, r0-lr - rcall save_full_context_ex - mfsr r12, SYSREG_ECR - mov r11, sp - rcall do_page_fault - rjmp ret_from_exception - /* This function expects to find offending PC in SYSREG_RAR_EX */ .type save_full_context_ex, @function .align 2 diff --git a/arch/avr32/kernel/signal.c b/arch/avr32/kernel/signal.c index 5616a00c10ba..c5b11f9067f1 100644 --- a/arch/avr32/kernel/signal.c +++ b/arch/avr32/kernel/signal.c @@ -93,6 +93,9 @@ asmlinkage int sys_rt_sigreturn(struct pt_regs *regs) if (restore_sigcontext(regs, &frame->uc.uc_mcontext)) goto badframe; + if (do_sigaltstack(&frame->uc.uc_stack, NULL, regs->sp) == -EFAULT) + goto badframe; + pr_debug("Context restored: pc = %08lx, lr = %08lx, sp = %08lx\n", regs->pc, regs->lr, regs->sp); diff --git a/arch/avr32/kernel/stacktrace.c b/arch/avr32/kernel/stacktrace.c index 9a68190bbffd..f4bdb448049c 100644 --- a/arch/avr32/kernel/stacktrace.c +++ b/arch/avr32/kernel/stacktrace.c @@ -51,3 +51,4 @@ void save_stack_trace(struct stack_trace *trace) fp = frame->fp; } } +EXPORT_SYMBOL_GPL(save_stack_trace); diff --git a/arch/avr32/kernel/time.c b/arch/avr32/kernel/time.c index 00a9862380ff..abd954fb7ba0 100644 --- a/arch/avr32/kernel/time.c +++ b/arch/avr32/kernel/time.c @@ -7,21 +7,13 @@ */ #include <linux/clk.h> #include <linux/clockchips.h> -#include <linux/time.h> -#include <linux/module.h> +#include <linux/init.h> #include <linux/interrupt.h> #include <linux/irq.h> -#include <linux/kernel_stat.h> -#include <linux/errno.h> -#include <linux/init.h> -#include <linux/profile.h> -#include <linux/sysdev.h> -#include <linux/err.h> +#include <linux/kernel.h> +#include <linux/time.h> -#include <asm/div64.h> #include <asm/sysreg.h> -#include <asm/io.h> -#include <asm/sections.h> #include <asm/arch/pm.h> diff --git a/arch/avr32/kernel/vmlinux.lds.S b/arch/avr32/kernel/vmlinux.lds.S index 481cfd40c053..7910d41eb886 100644 --- a/arch/avr32/kernel/vmlinux.lds.S +++ b/arch/avr32/kernel/vmlinux.lds.S @@ -68,14 +68,6 @@ SECTIONS _evba = .; _text = .; *(.ex.text) - . = 0x50; - *(.tlbx.ex.text) - . = 0x60; - *(.tlbr.ex.text) - . = 0x70; - *(.tlbw.ex.text) - . = 0x100; - *(.scall.text) *(.irq.text) KPROBES_TEXT TEXT_TEXT @@ -93,8 +85,6 @@ SECTIONS __stop___ex_table = .; } - BUG_TABLE - RODATA . = ALIGN(THREAD_SIZE); @@ -107,6 +97,10 @@ SECTIONS */ *(.data.init_task) + /* Then, the page-aligned data */ + . = ALIGN(PAGE_SIZE); + *(.data.page_aligned) + /* Then, the cacheline aligned data */ . = ALIGN(L1_CACHE_BYTES); *(.data.cacheline_aligned) |