diff options
Diffstat (limited to 'arch/arm/kernel')
-rw-r--r-- | arch/arm/kernel/Makefile | 4 | ||||
-rw-r--r-- | arch/arm/kernel/ecard.c | 31 | ||||
-rw-r--r-- | arch/arm/kernel/ecard.h | 56 | ||||
-rw-r--r-- | arch/arm/kernel/head-nommu.S | 2 | ||||
-rw-r--r-- | arch/arm/kernel/head.S | 8 | ||||
-rw-r--r-- | arch/arm/kernel/init_task.c | 2 | ||||
-rw-r--r-- | arch/arm/kernel/irq.c | 3 | ||||
-rw-r--r-- | arch/arm/kernel/module.c | 4 | ||||
-rw-r--r-- | arch/arm/kernel/process.c | 4 | ||||
-rw-r--r-- | arch/arm/kernel/ptrace.c | 22 | ||||
-rw-r--r-- | arch/arm/kernel/ptrace.h | 39 | ||||
-rw-r--r-- | arch/arm/kernel/signal.c | 22 | ||||
-rw-r--r-- | arch/arm/kernel/smp.c | 4 | ||||
-rw-r--r-- | arch/arm/kernel/stacktrace.c | 73 | ||||
-rw-r--r-- | arch/arm/kernel/stacktrace.h | 9 | ||||
-rw-r--r-- | arch/arm/kernel/time.c | 4 | ||||
-rw-r--r-- | arch/arm/kernel/traps.c | 38 | ||||
-rw-r--r-- | arch/arm/kernel/vmlinux.lds.S | 17 |
18 files changed, 265 insertions, 77 deletions
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile index bb28087bf818..593b56509f4f 100644 --- a/arch/arm/kernel/Makefile +++ b/arch/arm/kernel/Makefile @@ -7,8 +7,8 @@ AFLAGS_head.o := -DTEXT_OFFSET=$(TEXT_OFFSET) # Object file lists. obj-y := compat.o entry-armv.o entry-common.o irq.o \ - process.o ptrace.o semaphore.o setup.o signal.o sys_arm.o \ - time.o traps.o + process.o ptrace.o semaphore.o setup.o signal.o \ + sys_arm.o stacktrace.o time.o traps.o obj-$(CONFIG_ISA_DMA_API) += dma.o obj-$(CONFIG_ARCH_ACORN) += ecard.o diff --git a/arch/arm/kernel/ecard.c b/arch/arm/kernel/ecard.c index f1c0fb974177..bdbd7da99286 100644 --- a/arch/arm/kernel/ecard.c +++ b/arch/arm/kernel/ecard.c @@ -40,6 +40,7 @@ #include <linux/device.h> #include <linux/init.h> #include <linux/mutex.h> +#include <linux/kthread.h> #include <asm/dma.h> #include <asm/ecard.h> @@ -50,6 +51,8 @@ #include <asm/mach/irq.h> #include <asm/tlbflush.h> +#include "ecard.h" + #ifndef CONFIG_ARCH_RPC #define HAVE_EXPMASK #endif @@ -123,7 +126,7 @@ static void ecard_task_reset(struct ecard_request *req) res = ec->slot_no == 8 ? &ec->resource[ECARD_RES_MEMC] - : ec->type == ECARD_EASI + : ec->easi ? &ec->resource[ECARD_RES_EASI] : &ec->resource[ECARD_RES_IOCSYNC]; @@ -178,7 +181,7 @@ static void ecard_task_readbytes(struct ecard_request *req) index += 1; } } else { - unsigned long base = (ec->type == ECARD_EASI + unsigned long base = (ec->easi ? &ec->resource[ECARD_RES_EASI] : &ec->resource[ECARD_RES_IOCSYNC])->start; void __iomem *pbase = (void __iomem *)base; @@ -263,8 +266,6 @@ static int ecard_init_mm(void) static int ecard_task(void * unused) { - daemonize("kecardd"); - /* * Allocate a mm. We're not a lazy-TLB kernel task since we need * to set page table entries where the user space would be. Note @@ -727,7 +728,7 @@ static int ecard_prints(char *buffer, ecard_t *ec) char *start = buffer; buffer += sprintf(buffer, " %d: %s ", ec->slot_no, - ec->type == ECARD_EASI ? "EASI" : " "); + ec->easi ? "EASI" : " "); if (ec->cid.id == 0) { struct in_chunk_dir incd; @@ -814,7 +815,7 @@ static struct expansion_card *__init ecard_alloc_card(int type, int slot) } ec->slot_no = slot; - ec->type = type; + ec->easi = type == ECARD_EASI; ec->irq = NO_IRQ; ec->fiq = NO_IRQ; ec->dma = NO_DMA; @@ -825,6 +826,7 @@ static struct expansion_card *__init ecard_alloc_card(int type, int slot) ec->dev.bus = &ecard_bus_type; ec->dev.dma_mask = &ec->dma_mask; ec->dma_mask = (u64)0xffffffff; + ec->dev.coherent_dma_mask = ec->dma_mask; if (slot < 4) { ec_set_resource(ec, ECARD_RES_MEMC, @@ -907,7 +909,7 @@ static ssize_t ecard_show_device(struct device *dev, struct device_attribute *at static ssize_t ecard_show_type(struct device *dev, struct device_attribute *attr, char *buf) { struct expansion_card *ec = ECARD_DEV(dev); - return sprintf(buf, "%s\n", ec->type == ECARD_EASI ? "EASI" : "IOC"); + return sprintf(buf, "%s\n", ec->easi ? "EASI" : "IOC"); } static struct device_attribute ecard_dev_attrs[] = { @@ -1058,13 +1060,14 @@ ecard_probe(int slot, card_type_t type) */ static int __init ecard_init(void) { - int slot, irqhw, ret; - - ret = kernel_thread(ecard_task, NULL, CLONE_KERNEL); - if (ret < 0) { - printk(KERN_ERR "Ecard: unable to create kernel thread: %d\n", - ret); - return ret; + struct task_struct *task; + int slot, irqhw; + + task = kthread_run(ecard_task, NULL, "kecardd"); + if (IS_ERR(task)) { + printk(KERN_ERR "Ecard: unable to create kernel thread: %ld\n", + PTR_ERR(task)); + return PTR_ERR(task); } printk("Probing expansion cards\n"); diff --git a/arch/arm/kernel/ecard.h b/arch/arm/kernel/ecard.h new file mode 100644 index 000000000000..d7c2dacf935d --- /dev/null +++ b/arch/arm/kernel/ecard.h @@ -0,0 +1,56 @@ +/* + * ecard.h + * + * Copyright 2007 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/* Definitions internal to ecard.c - for it's use only!! + * + * External expansion card header as read from the card + */ +struct ex_ecid { + unsigned char r_irq:1; + unsigned char r_zero:1; + unsigned char r_fiq:1; + unsigned char r_id:4; + unsigned char r_a:1; + + unsigned char r_cd:1; + unsigned char r_is:1; + unsigned char r_w:2; + unsigned char r_r1:4; + + unsigned char r_r2:8; + + unsigned char r_prod[2]; + + unsigned char r_manu[2]; + + unsigned char r_country; + + unsigned char r_fiqmask; + unsigned char r_fiqoff[3]; + + unsigned char r_irqmask; + unsigned char r_irqoff[3]; +}; + +/* + * Chunk directory entry as read from the card + */ +struct ex_chunk_dir { + unsigned char r_id; + unsigned char r_len[3]; + unsigned long r_start; + union { + char string[256]; + char data[1]; + } d; +#define c_id(x) ((x)->r_id) +#define c_len(x) ((x)->r_len[0]|((x)->r_len[1]<<8)|((x)->r_len[2]<<16)) +#define c_start(x) ((x)->r_start) +}; diff --git a/arch/arm/kernel/head-nommu.S b/arch/arm/kernel/head-nommu.S index 0119c0d5f978..5d78ffb8a9a7 100644 --- a/arch/arm/kernel/head-nommu.S +++ b/arch/arm/kernel/head-nommu.S @@ -33,7 +33,7 @@ * numbers for r1. * */ - __INIT + .section ".text.head", "ax" .type stext, %function ENTRY(stext) msr cpsr_c, #PSR_F_BIT | PSR_I_BIT | SVC_MODE @ ensure svc mode diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S index 66db0a9bf0bc..41f98b4ba2ee 100644 --- a/arch/arm/kernel/head.S +++ b/arch/arm/kernel/head.S @@ -73,7 +73,7 @@ * crap here - that's what the boot loader (or in extreme, well justified * circumstances, zImage) is for. */ - __INIT + .section ".text.head", "ax" .type stext, %function ENTRY(stext) msr cpsr_c, #PSR_F_BIT | PSR_I_BIT | SVC_MODE @ ensure svc mode @@ -257,7 +257,9 @@ __create_page_tables: * Map some ram to cover our .data and .bss areas. */ orr r3, r7, #(KERNEL_RAM_PADDR & 0xff000000) + .if (KERNEL_RAM_PADDR & 0x00f00000) orr r3, r3, #(KERNEL_RAM_PADDR & 0x00f00000) + .endif add r0, r4, #(KERNEL_RAM_VADDR & 0xff000000) >> 18 str r3, [r0, #(KERNEL_RAM_VADDR & 0x00f00000) >> 18]! ldr r6, =(_end - 1) @@ -274,7 +276,9 @@ __create_page_tables: */ add r0, r4, #PAGE_OFFSET >> 18 orr r6, r7, #(PHYS_OFFSET & 0xff000000) - orr r6, r6, #(PHYS_OFFSET & 0x00e00000) + .if (PHYS_OFFSET & 0x00f00000) + orr r6, r6, #(PHYS_OFFSET & 0x00f00000) + .endif str r6, [r0] #ifdef CONFIG_DEBUG_LL diff --git a/arch/arm/kernel/init_task.c b/arch/arm/kernel/init_task.c index a00cca0000bd..bd4ef53bc6b9 100644 --- a/arch/arm/kernel/init_task.c +++ b/arch/arm/kernel/init_task.c @@ -31,7 +31,7 @@ EXPORT_SYMBOL(init_mm); * The things we do for performance.. */ union thread_union init_thread_union - __attribute__((__section__(".init.task"))) = + __attribute__((__section__(".data.init_task"))) = { INIT_THREAD_INFO(init_task) }; /* diff --git a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c index e101846ab7dd..11dcd52e51be 100644 --- a/arch/arm/kernel/irq.c +++ b/arch/arm/kernel/irq.c @@ -27,7 +27,6 @@ #include <linux/ioport.h> #include <linux/interrupt.h> #include <linux/irq.h> -#include <linux/ptrace.h> #include <linux/slab.h> #include <linux/random.h> #include <linux/smp.h> @@ -109,7 +108,7 @@ static struct irq_desc bad_irq_desc = { * come via this function. Instead, they should provide their * own 'handler' */ -asmlinkage void asm_do_IRQ(unsigned int irq, struct pt_regs *regs) +asmlinkage void __exception asm_do_IRQ(unsigned int irq, struct pt_regs *regs) { struct pt_regs *old_regs = set_irq_regs(regs); struct irq_desc *desc = irq_desc + irq; diff --git a/arch/arm/kernel/module.c b/arch/arm/kernel/module.c index 1b061583408e..79b7e5cf5416 100644 --- a/arch/arm/kernel/module.c +++ b/arch/arm/kernel/module.c @@ -116,8 +116,8 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex, offset += sym->st_value - loc; if (offset & 3 || - offset <= (s32)0xfc000000 || - offset >= (s32)0x04000000) { + offset <= (s32)0xfe000000 || + offset >= (s32)0x02000000) { printk(KERN_ERR "%s: relocation out of range, section " "%d reloc %d sym '%s'\n", module->name, diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c index 782af3cb213f..5d6e6523598b 100644 --- a/arch/arm/kernel/process.c +++ b/arch/arm/kernel/process.c @@ -16,7 +16,6 @@ #include <linux/mm.h> #include <linux/stddef.h> #include <linux/unistd.h> -#include <linux/ptrace.h> #include <linux/slab.h> #include <linux/user.h> #include <linux/a.out.h> @@ -28,6 +27,7 @@ #include <linux/cpu.h> #include <linux/elfcore.h> #include <linux/pm.h> +#include <linux/tick.h> #include <asm/leds.h> #include <asm/processor.h> @@ -160,9 +160,11 @@ void cpu_idle(void) if (!idle) idle = default_idle; leds_event(led_idle_start); + tick_nohz_stop_sched_tick(); while (!need_resched()) idle(); leds_event(led_idle_end); + tick_nohz_restart_sched_tick(); preempt_enable_no_resched(); schedule(); preempt_disable(); diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c index 9254ba2f46fc..6f2f46c2e406 100644 --- a/arch/arm/kernel/ptrace.c +++ b/arch/arm/kernel/ptrace.c @@ -13,7 +13,6 @@ #include <linux/sched.h> #include <linux/mm.h> #include <linux/smp.h> -#include <linux/smp_lock.h> #include <linux/ptrace.h> #include <linux/user.h> #include <linux/security.h> @@ -457,13 +456,10 @@ void ptrace_cancel_bpt(struct task_struct *child) /* * Called by kernel/ptrace.c when detaching.. - * - * Make sure the single step bit is not set. */ void ptrace_disable(struct task_struct *child) { - child->ptrace &= ~PT_SINGLESTEP; - ptrace_cancel_bpt(child); + single_step_disable(child); } /* @@ -712,9 +708,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) else clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); child->exit_code = data; - /* make sure single-step breakpoint is gone. */ - child->ptrace &= ~PT_SINGLESTEP; - ptrace_cancel_bpt(child); + single_step_disable(child); wake_up_process(child); ret = 0; break; @@ -725,9 +719,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) * exit. */ case PTRACE_KILL: - /* make sure single-step breakpoint is gone. */ - child->ptrace &= ~PT_SINGLESTEP; - ptrace_cancel_bpt(child); + single_step_disable(child); if (child->exit_state != EXIT_ZOMBIE) { child->exit_code = SIGKILL; wake_up_process(child); @@ -742,7 +734,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) ret = -EIO; if (!valid_signal(data)) break; - child->ptrace |= PT_SINGLESTEP; + single_step_enable(child); clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); child->exit_code = data; /* give it a chance to run. */ @@ -786,8 +778,8 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) break; case PTRACE_SET_SYSCALL: + task_thread_info(child)->syscall = data; ret = 0; - child->ptrace_message = data; break; #ifdef CONFIG_CRUNCH @@ -824,7 +816,7 @@ asmlinkage int syscall_trace(int why, struct pt_regs *regs, int scno) ip = regs->ARM_ip; regs->ARM_ip = why; - current->ptrace_message = scno; + current_thread_info()->syscall = scno; /* the 0x80 provides a way for the tracing parent to distinguish between a syscall stop and SIGTRAP delivery */ @@ -841,5 +833,5 @@ asmlinkage int syscall_trace(int why, struct pt_regs *regs, int scno) } regs->ARM_ip = ip; - return current->ptrace_message; + return current_thread_info()->syscall; } diff --git a/arch/arm/kernel/ptrace.h b/arch/arm/kernel/ptrace.h index f7cad13a22e9..def3b6184a79 100644 --- a/arch/arm/kernel/ptrace.h +++ b/arch/arm/kernel/ptrace.h @@ -7,6 +7,45 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ +#include <linux/ptrace.h> + extern void ptrace_cancel_bpt(struct task_struct *); extern void ptrace_set_bpt(struct task_struct *); extern void ptrace_break(struct task_struct *, struct pt_regs *); + +/* + * make sure single-step breakpoint is gone. + */ +static inline void single_step_disable(struct task_struct *task) +{ + task->ptrace &= ~PT_SINGLESTEP; + ptrace_cancel_bpt(task); +} + +static inline void single_step_enable(struct task_struct *task) +{ + task->ptrace |= PT_SINGLESTEP; +} + +/* + * Send SIGTRAP if we're single-stepping + */ +static inline void single_step_trap(struct task_struct *task) +{ + if (task->ptrace & PT_SINGLESTEP) { + ptrace_cancel_bpt(task); + send_sig(SIGTRAP, task, 1); + } +} + +static inline void single_step_clear(struct task_struct *task) +{ + if (task->ptrace & PT_SINGLESTEP) + ptrace_cancel_bpt(task); +} + +static inline void single_step_set(struct task_struct *task) +{ + if (task->ptrace & PT_SINGLESTEP) + ptrace_set_bpt(task); +} diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c index 3843d3bab2dd..54cdf1aeefc3 100644 --- a/arch/arm/kernel/signal.c +++ b/arch/arm/kernel/signal.c @@ -9,7 +9,6 @@ */ #include <linux/errno.h> #include <linux/signal.h> -#include <linux/ptrace.h> #include <linux/personality.h> #include <linux/freezer.h> @@ -285,11 +284,7 @@ asmlinkage int sys_sigreturn(struct pt_regs *regs) if (restore_sigframe(regs, frame)) goto badframe; - /* Send SIGTRAP if we're single-stepping */ - if (current->ptrace & PT_SINGLESTEP) { - ptrace_cancel_bpt(current); - send_sig(SIGTRAP, current, 1); - } + single_step_trap(current); return regs->ARM_r0; @@ -324,11 +319,7 @@ asmlinkage int sys_rt_sigreturn(struct pt_regs *regs) if (do_sigaltstack(&frame->sig.uc.uc_stack, NULL, regs->ARM_sp) == -EFAULT) goto badframe; - /* Send SIGTRAP if we're single-stepping */ - if (current->ptrace & PT_SINGLESTEP) { - ptrace_cancel_bpt(current); - send_sig(SIGTRAP, current, 1); - } + single_step_trap(current); return regs->ARM_r0; @@ -644,14 +635,12 @@ static int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall) if (try_to_freeze()) goto no_signal; - if (current->ptrace & PT_SINGLESTEP) - ptrace_cancel_bpt(current); + single_step_clear(current); signr = get_signal_to_deliver(&info, &ka, regs, NULL); if (signr > 0) { handle_signal(signr, &ka, &info, oldset, regs, syscall); - if (current->ptrace & PT_SINGLESTEP) - ptrace_set_bpt(current); + single_step_set(current); return 1; } @@ -705,8 +694,7 @@ static int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall) restart_syscall(regs); } } - if (current->ptrace & PT_SINGLESTEP) - ptrace_set_bpt(current); + single_step_set(current); return 0; } diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index 070bcb7a6306..1b76d87fa335 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -486,7 +486,7 @@ static void ipi_timer(void) } #ifdef CONFIG_LOCAL_TIMERS -asmlinkage void do_local_timer(struct pt_regs *regs) +asmlinkage void __exception do_local_timer(struct pt_regs *regs) { struct pt_regs *old_regs = set_irq_regs(regs); int cpu = smp_processor_id(); @@ -551,7 +551,7 @@ static void ipi_cpu_stop(unsigned int cpu) * * Bit 0 - Inter-processor function call */ -asmlinkage void do_IPI(struct pt_regs *regs) +asmlinkage void __exception do_IPI(struct pt_regs *regs) { unsigned int cpu = smp_processor_id(); struct ipi_data *ipi = &per_cpu(ipi_data, cpu); diff --git a/arch/arm/kernel/stacktrace.c b/arch/arm/kernel/stacktrace.c new file mode 100644 index 000000000000..77ef35efaa8d --- /dev/null +++ b/arch/arm/kernel/stacktrace.c @@ -0,0 +1,73 @@ +#include <linux/sched.h> +#include <linux/stacktrace.h> + +#include "stacktrace.h" + +int walk_stackframe(unsigned long fp, unsigned long low, unsigned long high, + int (*fn)(struct stackframe *, void *), void *data) +{ + struct stackframe *frame; + + do { + /* + * Check current frame pointer is within bounds + */ + if ((fp - 12) < low || fp + 4 >= high) + break; + + frame = (struct stackframe *)(fp - 12); + + if (fn(frame, data)) + break; + + /* + * Update the low bound - the next frame must always + * be at a higher address than the current frame. + */ + low = fp + 4; + fp = frame->fp; + } while (fp); + + return 0; +} + +#ifdef CONFIG_STACKTRACE +struct stack_trace_data { + struct stack_trace *trace; + unsigned int skip; +}; + +static int save_trace(struct stackframe *frame, void *d) +{ + struct stack_trace_data *data = d; + struct stack_trace *trace = data->trace; + + if (data->skip) { + data->skip--; + return 0; + } + + trace->entries[trace->nr_entries++] = frame->lr; + + return trace->nr_entries >= trace->max_entries; +} + +void save_stack_trace(struct stack_trace *trace, struct task_struct *task) +{ + struct stack_trace_data data; + unsigned long fp, base; + + data.trace = trace; + data.skip = trace->skip; + + if (task) { + base = (unsigned long)task_stack_page(task); + fp = 0; /* FIXME */ + } else { + base = (unsigned long)task_stack_page(current); + asm("mov %0, fp" : "=r" (fp)); + } + + walk_stackframe(fp, base, base + THREAD_SIZE, save_trace, &data); +} +#endif diff --git a/arch/arm/kernel/stacktrace.h b/arch/arm/kernel/stacktrace.h new file mode 100644 index 000000000000..e9fd20cb5662 --- /dev/null +++ b/arch/arm/kernel/stacktrace.h @@ -0,0 +1,9 @@ +struct stackframe { + unsigned long fp; + unsigned long sp; + unsigned long lr; + unsigned long pc; +}; + +int walk_stackframe(unsigned long fp, unsigned long low, unsigned long high, + int (*fn)(struct stackframe *, void *), void *data); diff --git a/arch/arm/kernel/time.c b/arch/arm/kernel/time.c index f61decb89ba2..d0540e4eaf5b 100644 --- a/arch/arm/kernel/time.c +++ b/arch/arm/kernel/time.c @@ -327,6 +327,7 @@ void restore_time_delta(struct timespec *delta, struct timespec *rtc) } EXPORT_SYMBOL(restore_time_delta); +#ifndef CONFIG_GENERIC_CLOCKEVENTS /* * Kernel system timer support. */ @@ -340,8 +341,9 @@ void timer_tick(void) update_process_times(user_mode(get_irq_regs())); #endif } +#endif -#ifdef CONFIG_PM +#if defined(CONFIG_PM) && !defined(CONFIG_GENERIC_CLOCKEVENTS) static int timer_suspend(struct sys_device *dev, pm_message_t state) { struct sys_timer *timer = container_of(dev, struct sys_timer, dev); diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index 24095601359b..10ff36e4e414 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c @@ -16,7 +16,6 @@ #include <linux/signal.h> #include <linux/spinlock.h> #include <linux/personality.h> -#include <linux/ptrace.h> #include <linux/kallsyms.h> #include <linux/delay.h> #include <linux/init.h> @@ -45,7 +44,18 @@ static int __init user_debug_setup(char *str) __setup("user_debug=", user_debug_setup); #endif -void dump_backtrace_entry(unsigned long where, unsigned long from) +static void dump_mem(const char *str, unsigned long bottom, unsigned long top); + +static inline int in_exception_text(unsigned long ptr) +{ + extern char __exception_text_start[]; + extern char __exception_text_end[]; + + return ptr >= (unsigned long)&__exception_text_start && + ptr < (unsigned long)&__exception_text_end; +} + +void dump_backtrace_entry(unsigned long where, unsigned long from, unsigned long frame) { #ifdef CONFIG_KALLSYMS printk("[<%08lx>] ", where); @@ -55,6 +65,9 @@ void dump_backtrace_entry(unsigned long where, unsigned long from) #else printk("Function entered at [<%08lx>] from [<%08lx>]\n", where, from); #endif + + if (in_exception_text(where)) + dump_mem("Exception stack", frame + 4, frame + 4 + sizeof(struct pt_regs)); } /* @@ -232,8 +245,8 @@ NORET_TYPE void die(const char *str, struct pt_regs *regs, int err) do_exit(SIGSEGV); } -void notify_die(const char *str, struct pt_regs *regs, struct siginfo *info, - unsigned long err, unsigned long trap) +void arm_notify_die(const char *str, struct pt_regs *regs, + struct siginfo *info, unsigned long err, unsigned long trap) { if (user_mode(regs)) { current->thread.error_code = err; @@ -266,13 +279,14 @@ void unregister_undef_hook(struct undef_hook *hook) spin_unlock_irqrestore(&undef_lock, flags); } -asmlinkage void do_undefinstr(struct pt_regs *regs) +asmlinkage void __exception do_undefinstr(struct pt_regs *regs) { unsigned int correction = thumb_mode(regs) ? 2 : 4; unsigned int instr; struct undef_hook *hook; siginfo_t info; void __user *pc; + unsigned long flags; /* * According to the ARM ARM, PC is 2 or 4 bytes ahead, @@ -291,7 +305,7 @@ asmlinkage void do_undefinstr(struct pt_regs *regs) get_user(instr, (u32 __user *)pc); } - spin_lock_irq(&undef_lock); + spin_lock_irqsave(&undef_lock, flags); list_for_each_entry(hook, &undef_hook, node) { if ((instr & hook->instr_mask) == hook->instr_val && (regs->ARM_cpsr & hook->cpsr_mask) == hook->cpsr_val) { @@ -301,7 +315,7 @@ asmlinkage void do_undefinstr(struct pt_regs *regs) } } } - spin_unlock_irq(&undef_lock); + spin_unlock_irqrestore(&undef_lock, flags); #ifdef CONFIG_DEBUG_USER if (user_debug & UDBG_UNDEFINED) { @@ -316,7 +330,7 @@ asmlinkage void do_undefinstr(struct pt_regs *regs) info.si_code = ILL_ILLOPC; info.si_addr = pc; - notify_die("Oops - undefined instruction", regs, &info, 0, 6); + arm_notify_die("Oops - undefined instruction", regs, &info, 0, 6); } asmlinkage void do_unexp_fiq (struct pt_regs *regs) @@ -370,7 +384,7 @@ static int bad_syscall(int n, struct pt_regs *regs) info.si_addr = (void __user *)instruction_pointer(regs) - (thumb_mode(regs) ? 2 : 4); - notify_die("Oops - bad syscall", regs, &info, n, 0); + arm_notify_die("Oops - bad syscall", regs, &info, n, 0); return regs->ARM_r0; } @@ -414,7 +428,7 @@ asmlinkage int arm_syscall(int no, struct pt_regs *regs) info.si_code = SEGV_MAPERR; info.si_addr = NULL; - notify_die("branch through zero", regs, &info, 0, 0); + arm_notify_die("branch through zero", regs, &info, 0, 0); return 0; case NR(breakpoint): /* SWI BREAK_POINT */ @@ -550,7 +564,7 @@ asmlinkage int arm_syscall(int no, struct pt_regs *regs) info.si_addr = (void __user *)instruction_pointer(regs) - (thumb_mode(regs) ? 2 : 4); - notify_die("Oops - bad syscall(2)", regs, &info, no, 0); + arm_notify_die("Oops - bad syscall(2)", regs, &info, no, 0); return 0; } @@ -624,7 +638,7 @@ baddataabort(int code, unsigned long instr, struct pt_regs *regs) info.si_code = ILL_ILLOPC; info.si_addr = (void __user *)addr; - notify_die("unknown data abort code", regs, &info, instr, 0); + arm_notify_die("unknown data abort code", regs, &info, instr, 0); } void __attribute__((noreturn)) __bug(const char *file, int line) diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S index ddbdad48f5b2..e4156e7868ce 100644 --- a/arch/arm/kernel/vmlinux.lds.S +++ b/arch/arm/kernel/vmlinux.lds.S @@ -23,11 +23,15 @@ SECTIONS #else . = PAGE_OFFSET + TEXT_OFFSET; #endif - .init : { /* Init code and data */ + .text.head : { _stext = .; - _sinittext = .; + _sinittext = .; + *(.text.head) + } + + .init : { /* Init code and data */ *(.init.text) - _einittext = .; + _einittext = .; __proc_info_begin = .; *(.proc.info.init) __proc_info_end = .; @@ -59,7 +63,7 @@ SECTIONS usr/built-in.o(.init.ramfs) __initramfs_end = .; #endif - . = ALIGN(64); + . = ALIGN(4096); __per_cpu_start = .; *(.data.percpu) __per_cpu_end = .; @@ -83,6 +87,9 @@ SECTIONS .text : { /* Real text segment */ _text = .; /* Text and read-only data */ + __exception_text_start = .; + *(.exception.text) + __exception_text_end = .; *(.text) SCHED_TEXT LOCK_TEXT @@ -116,7 +123,7 @@ SECTIONS * first, the init task union, aligned * to an 8192 byte boundary. */ - *(.init.task) + *(.data.init_task) #ifdef CONFIG_XIP_KERNEL . = ALIGN(4096); |