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.S | 6 | ||||
-rw-r--r-- | arch/arm/kernel/irq.c | 3 | ||||
-rw-r--r-- | arch/arm/kernel/process.c | 4 | ||||
-rw-r--r-- | arch/arm/kernel/ptrace.c | 21 | ||||
-rw-r--r-- | arch/arm/kernel/ptrace.h | 39 | ||||
-rw-r--r-- | arch/arm/kernel/signal.c | 22 | ||||
-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 | 24 | ||||
-rw-r--r-- | arch/arm/kernel/vmlinux.lds.S | 3 |
14 files changed, 242 insertions, 57 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) | |||
7 | # Object file lists. | 7 | # Object file lists. |
8 | 8 | ||
9 | obj-y := compat.o entry-armv.o entry-common.o irq.o \ | 9 | obj-y := compat.o entry-armv.o entry-common.o irq.o \ |
10 | process.o ptrace.o semaphore.o setup.o signal.o sys_arm.o \ | 10 | process.o ptrace.o semaphore.o setup.o signal.o \ |
11 | time.o traps.o | 11 | sys_arm.o stacktrace.o time.o traps.o |
12 | 12 | ||
13 | obj-$(CONFIG_ISA_DMA_API) += dma.o | 13 | obj-$(CONFIG_ISA_DMA_API) += dma.o |
14 | obj-$(CONFIG_ARCH_ACORN) += ecard.o | 14 | 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 @@ | |||
40 | #include <linux/device.h> | 40 | #include <linux/device.h> |
41 | #include <linux/init.h> | 41 | #include <linux/init.h> |
42 | #include <linux/mutex.h> | 42 | #include <linux/mutex.h> |
43 | #include <linux/kthread.h> | ||
43 | 44 | ||
44 | #include <asm/dma.h> | 45 | #include <asm/dma.h> |
45 | #include <asm/ecard.h> | 46 | #include <asm/ecard.h> |
@@ -50,6 +51,8 @@ | |||
50 | #include <asm/mach/irq.h> | 51 | #include <asm/mach/irq.h> |
51 | #include <asm/tlbflush.h> | 52 | #include <asm/tlbflush.h> |
52 | 53 | ||
54 | #include "ecard.h" | ||
55 | |||
53 | #ifndef CONFIG_ARCH_RPC | 56 | #ifndef CONFIG_ARCH_RPC |
54 | #define HAVE_EXPMASK | 57 | #define HAVE_EXPMASK |
55 | #endif | 58 | #endif |
@@ -123,7 +126,7 @@ static void ecard_task_reset(struct ecard_request *req) | |||
123 | 126 | ||
124 | res = ec->slot_no == 8 | 127 | res = ec->slot_no == 8 |
125 | ? &ec->resource[ECARD_RES_MEMC] | 128 | ? &ec->resource[ECARD_RES_MEMC] |
126 | : ec->type == ECARD_EASI | 129 | : ec->easi |
127 | ? &ec->resource[ECARD_RES_EASI] | 130 | ? &ec->resource[ECARD_RES_EASI] |
128 | : &ec->resource[ECARD_RES_IOCSYNC]; | 131 | : &ec->resource[ECARD_RES_IOCSYNC]; |
129 | 132 | ||
@@ -178,7 +181,7 @@ static void ecard_task_readbytes(struct ecard_request *req) | |||
178 | index += 1; | 181 | index += 1; |
179 | } | 182 | } |
180 | } else { | 183 | } else { |
181 | unsigned long base = (ec->type == ECARD_EASI | 184 | unsigned long base = (ec->easi |
182 | ? &ec->resource[ECARD_RES_EASI] | 185 | ? &ec->resource[ECARD_RES_EASI] |
183 | : &ec->resource[ECARD_RES_IOCSYNC])->start; | 186 | : &ec->resource[ECARD_RES_IOCSYNC])->start; |
184 | void __iomem *pbase = (void __iomem *)base; | 187 | void __iomem *pbase = (void __iomem *)base; |
@@ -263,8 +266,6 @@ static int ecard_init_mm(void) | |||
263 | static int | 266 | static int |
264 | ecard_task(void * unused) | 267 | ecard_task(void * unused) |
265 | { | 268 | { |
266 | daemonize("kecardd"); | ||
267 | |||
268 | /* | 269 | /* |
269 | * Allocate a mm. We're not a lazy-TLB kernel task since we need | 270 | * Allocate a mm. We're not a lazy-TLB kernel task since we need |
270 | * to set page table entries where the user space would be. Note | 271 | * 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) | |||
727 | char *start = buffer; | 728 | char *start = buffer; |
728 | 729 | ||
729 | buffer += sprintf(buffer, " %d: %s ", ec->slot_no, | 730 | buffer += sprintf(buffer, " %d: %s ", ec->slot_no, |
730 | ec->type == ECARD_EASI ? "EASI" : " "); | 731 | ec->easi ? "EASI" : " "); |
731 | 732 | ||
732 | if (ec->cid.id == 0) { | 733 | if (ec->cid.id == 0) { |
733 | struct in_chunk_dir incd; | 734 | struct in_chunk_dir incd; |
@@ -814,7 +815,7 @@ static struct expansion_card *__init ecard_alloc_card(int type, int slot) | |||
814 | } | 815 | } |
815 | 816 | ||
816 | ec->slot_no = slot; | 817 | ec->slot_no = slot; |
817 | ec->type = type; | 818 | ec->easi = type == ECARD_EASI; |
818 | ec->irq = NO_IRQ; | 819 | ec->irq = NO_IRQ; |
819 | ec->fiq = NO_IRQ; | 820 | ec->fiq = NO_IRQ; |
820 | ec->dma = NO_DMA; | 821 | ec->dma = NO_DMA; |
@@ -825,6 +826,7 @@ static struct expansion_card *__init ecard_alloc_card(int type, int slot) | |||
825 | ec->dev.bus = &ecard_bus_type; | 826 | ec->dev.bus = &ecard_bus_type; |
826 | ec->dev.dma_mask = &ec->dma_mask; | 827 | ec->dev.dma_mask = &ec->dma_mask; |
827 | ec->dma_mask = (u64)0xffffffff; | 828 | ec->dma_mask = (u64)0xffffffff; |
829 | ec->dev.coherent_dma_mask = ec->dma_mask; | ||
828 | 830 | ||
829 | if (slot < 4) { | 831 | if (slot < 4) { |
830 | ec_set_resource(ec, ECARD_RES_MEMC, | 832 | ec_set_resource(ec, ECARD_RES_MEMC, |
@@ -907,7 +909,7 @@ static ssize_t ecard_show_device(struct device *dev, struct device_attribute *at | |||
907 | static ssize_t ecard_show_type(struct device *dev, struct device_attribute *attr, char *buf) | 909 | static ssize_t ecard_show_type(struct device *dev, struct device_attribute *attr, char *buf) |
908 | { | 910 | { |
909 | struct expansion_card *ec = ECARD_DEV(dev); | 911 | struct expansion_card *ec = ECARD_DEV(dev); |
910 | return sprintf(buf, "%s\n", ec->type == ECARD_EASI ? "EASI" : "IOC"); | 912 | return sprintf(buf, "%s\n", ec->easi ? "EASI" : "IOC"); |
911 | } | 913 | } |
912 | 914 | ||
913 | static struct device_attribute ecard_dev_attrs[] = { | 915 | static struct device_attribute ecard_dev_attrs[] = { |
@@ -1058,13 +1060,14 @@ ecard_probe(int slot, card_type_t type) | |||
1058 | */ | 1060 | */ |
1059 | static int __init ecard_init(void) | 1061 | static int __init ecard_init(void) |
1060 | { | 1062 | { |
1061 | int slot, irqhw, ret; | 1063 | struct task_struct *task; |
1062 | 1064 | int slot, irqhw; | |
1063 | ret = kernel_thread(ecard_task, NULL, CLONE_KERNEL); | 1065 | |
1064 | if (ret < 0) { | 1066 | task = kthread_run(ecard_task, NULL, "kecardd"); |
1065 | printk(KERN_ERR "Ecard: unable to create kernel thread: %d\n", | 1067 | if (IS_ERR(task)) { |
1066 | ret); | 1068 | printk(KERN_ERR "Ecard: unable to create kernel thread: %ld\n", |
1067 | return ret; | 1069 | PTR_ERR(task)); |
1070 | return PTR_ERR(task); | ||
1068 | } | 1071 | } |
1069 | 1072 | ||
1070 | printk("Probing expansion cards\n"); | 1073 | 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 @@ | |||
1 | /* | ||
2 | * ecard.h | ||
3 | * | ||
4 | * Copyright 2007 Russell King | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | */ | ||
10 | |||
11 | /* Definitions internal to ecard.c - for it's use only!! | ||
12 | * | ||
13 | * External expansion card header as read from the card | ||
14 | */ | ||
15 | struct ex_ecid { | ||
16 | unsigned char r_irq:1; | ||
17 | unsigned char r_zero:1; | ||
18 | unsigned char r_fiq:1; | ||
19 | unsigned char r_id:4; | ||
20 | unsigned char r_a:1; | ||
21 | |||
22 | unsigned char r_cd:1; | ||
23 | unsigned char r_is:1; | ||
24 | unsigned char r_w:2; | ||
25 | unsigned char r_r1:4; | ||
26 | |||
27 | unsigned char r_r2:8; | ||
28 | |||
29 | unsigned char r_prod[2]; | ||
30 | |||
31 | unsigned char r_manu[2]; | ||
32 | |||
33 | unsigned char r_country; | ||
34 | |||
35 | unsigned char r_fiqmask; | ||
36 | unsigned char r_fiqoff[3]; | ||
37 | |||
38 | unsigned char r_irqmask; | ||
39 | unsigned char r_irqoff[3]; | ||
40 | }; | ||
41 | |||
42 | /* | ||
43 | * Chunk directory entry as read from the card | ||
44 | */ | ||
45 | struct ex_chunk_dir { | ||
46 | unsigned char r_id; | ||
47 | unsigned char r_len[3]; | ||
48 | unsigned long r_start; | ||
49 | union { | ||
50 | char string[256]; | ||
51 | char data[1]; | ||
52 | } d; | ||
53 | #define c_id(x) ((x)->r_id) | ||
54 | #define c_len(x) ((x)->r_len[0]|((x)->r_len[1]<<8)|((x)->r_len[2]<<16)) | ||
55 | #define c_start(x) ((x)->r_start) | ||
56 | }; | ||
diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S index 66db0a9bf0bc..1d35edacc011 100644 --- a/arch/arm/kernel/head.S +++ b/arch/arm/kernel/head.S | |||
@@ -257,7 +257,9 @@ __create_page_tables: | |||
257 | * Map some ram to cover our .data and .bss areas. | 257 | * Map some ram to cover our .data and .bss areas. |
258 | */ | 258 | */ |
259 | orr r3, r7, #(KERNEL_RAM_PADDR & 0xff000000) | 259 | orr r3, r7, #(KERNEL_RAM_PADDR & 0xff000000) |
260 | .if (KERNEL_RAM_PADDR & 0x00f00000) | ||
260 | orr r3, r3, #(KERNEL_RAM_PADDR & 0x00f00000) | 261 | orr r3, r3, #(KERNEL_RAM_PADDR & 0x00f00000) |
262 | .endif | ||
261 | add r0, r4, #(KERNEL_RAM_VADDR & 0xff000000) >> 18 | 263 | add r0, r4, #(KERNEL_RAM_VADDR & 0xff000000) >> 18 |
262 | str r3, [r0, #(KERNEL_RAM_VADDR & 0x00f00000) >> 18]! | 264 | str r3, [r0, #(KERNEL_RAM_VADDR & 0x00f00000) >> 18]! |
263 | ldr r6, =(_end - 1) | 265 | ldr r6, =(_end - 1) |
@@ -274,7 +276,9 @@ __create_page_tables: | |||
274 | */ | 276 | */ |
275 | add r0, r4, #PAGE_OFFSET >> 18 | 277 | add r0, r4, #PAGE_OFFSET >> 18 |
276 | orr r6, r7, #(PHYS_OFFSET & 0xff000000) | 278 | orr r6, r7, #(PHYS_OFFSET & 0xff000000) |
277 | orr r6, r6, #(PHYS_OFFSET & 0x00e00000) | 279 | .if (PHYS_OFFSET & 0x00f00000) |
280 | orr r6, r6, #(PHYS_OFFSET & 0x00f00000) | ||
281 | .endif | ||
278 | str r6, [r0] | 282 | str r6, [r0] |
279 | 283 | ||
280 | #ifdef CONFIG_DEBUG_LL | 284 | #ifdef CONFIG_DEBUG_LL |
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 @@ | |||
27 | #include <linux/ioport.h> | 27 | #include <linux/ioport.h> |
28 | #include <linux/interrupt.h> | 28 | #include <linux/interrupt.h> |
29 | #include <linux/irq.h> | 29 | #include <linux/irq.h> |
30 | #include <linux/ptrace.h> | ||
31 | #include <linux/slab.h> | 30 | #include <linux/slab.h> |
32 | #include <linux/random.h> | 31 | #include <linux/random.h> |
33 | #include <linux/smp.h> | 32 | #include <linux/smp.h> |
@@ -109,7 +108,7 @@ static struct irq_desc bad_irq_desc = { | |||
109 | * come via this function. Instead, they should provide their | 108 | * come via this function. Instead, they should provide their |
110 | * own 'handler' | 109 | * own 'handler' |
111 | */ | 110 | */ |
112 | asmlinkage void asm_do_IRQ(unsigned int irq, struct pt_regs *regs) | 111 | asmlinkage void __exception asm_do_IRQ(unsigned int irq, struct pt_regs *regs) |
113 | { | 112 | { |
114 | struct pt_regs *old_regs = set_irq_regs(regs); | 113 | struct pt_regs *old_regs = set_irq_regs(regs); |
115 | struct irq_desc *desc = irq_desc + irq; | 114 | struct irq_desc *desc = irq_desc + irq; |
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 @@ | |||
16 | #include <linux/mm.h> | 16 | #include <linux/mm.h> |
17 | #include <linux/stddef.h> | 17 | #include <linux/stddef.h> |
18 | #include <linux/unistd.h> | 18 | #include <linux/unistd.h> |
19 | #include <linux/ptrace.h> | ||
20 | #include <linux/slab.h> | 19 | #include <linux/slab.h> |
21 | #include <linux/user.h> | 20 | #include <linux/user.h> |
22 | #include <linux/a.out.h> | 21 | #include <linux/a.out.h> |
@@ -28,6 +27,7 @@ | |||
28 | #include <linux/cpu.h> | 27 | #include <linux/cpu.h> |
29 | #include <linux/elfcore.h> | 28 | #include <linux/elfcore.h> |
30 | #include <linux/pm.h> | 29 | #include <linux/pm.h> |
30 | #include <linux/tick.h> | ||
31 | 31 | ||
32 | #include <asm/leds.h> | 32 | #include <asm/leds.h> |
33 | #include <asm/processor.h> | 33 | #include <asm/processor.h> |
@@ -160,9 +160,11 @@ void cpu_idle(void) | |||
160 | if (!idle) | 160 | if (!idle) |
161 | idle = default_idle; | 161 | idle = default_idle; |
162 | leds_event(led_idle_start); | 162 | leds_event(led_idle_start); |
163 | tick_nohz_stop_sched_tick(); | ||
163 | while (!need_resched()) | 164 | while (!need_resched()) |
164 | idle(); | 165 | idle(); |
165 | leds_event(led_idle_end); | 166 | leds_event(led_idle_end); |
167 | tick_nohz_restart_sched_tick(); | ||
166 | preempt_enable_no_resched(); | 168 | preempt_enable_no_resched(); |
167 | schedule(); | 169 | schedule(); |
168 | preempt_disable(); | 170 | preempt_disable(); |
diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c index 9254ba2f46fc..13af4006a40f 100644 --- a/arch/arm/kernel/ptrace.c +++ b/arch/arm/kernel/ptrace.c | |||
@@ -457,13 +457,10 @@ void ptrace_cancel_bpt(struct task_struct *child) | |||
457 | 457 | ||
458 | /* | 458 | /* |
459 | * Called by kernel/ptrace.c when detaching.. | 459 | * Called by kernel/ptrace.c when detaching.. |
460 | * | ||
461 | * Make sure the single step bit is not set. | ||
462 | */ | 460 | */ |
463 | void ptrace_disable(struct task_struct *child) | 461 | void ptrace_disable(struct task_struct *child) |
464 | { | 462 | { |
465 | child->ptrace &= ~PT_SINGLESTEP; | 463 | single_step_disable(child); |
466 | ptrace_cancel_bpt(child); | ||
467 | } | 464 | } |
468 | 465 | ||
469 | /* | 466 | /* |
@@ -712,9 +709,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) | |||
712 | else | 709 | else |
713 | clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); | 710 | clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); |
714 | child->exit_code = data; | 711 | child->exit_code = data; |
715 | /* make sure single-step breakpoint is gone. */ | 712 | single_step_disable(child); |
716 | child->ptrace &= ~PT_SINGLESTEP; | ||
717 | ptrace_cancel_bpt(child); | ||
718 | wake_up_process(child); | 713 | wake_up_process(child); |
719 | ret = 0; | 714 | ret = 0; |
720 | break; | 715 | break; |
@@ -725,9 +720,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) | |||
725 | * exit. | 720 | * exit. |
726 | */ | 721 | */ |
727 | case PTRACE_KILL: | 722 | case PTRACE_KILL: |
728 | /* make sure single-step breakpoint is gone. */ | 723 | single_step_disable(child); |
729 | child->ptrace &= ~PT_SINGLESTEP; | ||
730 | ptrace_cancel_bpt(child); | ||
731 | if (child->exit_state != EXIT_ZOMBIE) { | 724 | if (child->exit_state != EXIT_ZOMBIE) { |
732 | child->exit_code = SIGKILL; | 725 | child->exit_code = SIGKILL; |
733 | wake_up_process(child); | 726 | wake_up_process(child); |
@@ -742,7 +735,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) | |||
742 | ret = -EIO; | 735 | ret = -EIO; |
743 | if (!valid_signal(data)) | 736 | if (!valid_signal(data)) |
744 | break; | 737 | break; |
745 | child->ptrace |= PT_SINGLESTEP; | 738 | single_step_enable(child); |
746 | clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); | 739 | clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); |
747 | child->exit_code = data; | 740 | child->exit_code = data; |
748 | /* give it a chance to run. */ | 741 | /* give it a chance to run. */ |
@@ -786,8 +779,8 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) | |||
786 | break; | 779 | break; |
787 | 780 | ||
788 | case PTRACE_SET_SYSCALL: | 781 | case PTRACE_SET_SYSCALL: |
782 | task_thread_info(child)->syscall = data; | ||
789 | ret = 0; | 783 | ret = 0; |
790 | child->ptrace_message = data; | ||
791 | break; | 784 | break; |
792 | 785 | ||
793 | #ifdef CONFIG_CRUNCH | 786 | #ifdef CONFIG_CRUNCH |
@@ -824,7 +817,7 @@ asmlinkage int syscall_trace(int why, struct pt_regs *regs, int scno) | |||
824 | ip = regs->ARM_ip; | 817 | ip = regs->ARM_ip; |
825 | regs->ARM_ip = why; | 818 | regs->ARM_ip = why; |
826 | 819 | ||
827 | current->ptrace_message = scno; | 820 | current_thread_info()->syscall = scno; |
828 | 821 | ||
829 | /* the 0x80 provides a way for the tracing parent to distinguish | 822 | /* the 0x80 provides a way for the tracing parent to distinguish |
830 | between a syscall stop and SIGTRAP delivery */ | 823 | between a syscall stop and SIGTRAP delivery */ |
@@ -841,5 +834,5 @@ asmlinkage int syscall_trace(int why, struct pt_regs *regs, int scno) | |||
841 | } | 834 | } |
842 | regs->ARM_ip = ip; | 835 | regs->ARM_ip = ip; |
843 | 836 | ||
844 | return current->ptrace_message; | 837 | return current_thread_info()->syscall; |
845 | } | 838 | } |
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 @@ | |||
7 | * it under the terms of the GNU General Public License version 2 as | 7 | * it under the terms of the GNU General Public License version 2 as |
8 | * published by the Free Software Foundation. | 8 | * published by the Free Software Foundation. |
9 | */ | 9 | */ |
10 | #include <linux/ptrace.h> | ||
11 | |||
10 | extern void ptrace_cancel_bpt(struct task_struct *); | 12 | extern void ptrace_cancel_bpt(struct task_struct *); |
11 | extern void ptrace_set_bpt(struct task_struct *); | 13 | extern void ptrace_set_bpt(struct task_struct *); |
12 | extern void ptrace_break(struct task_struct *, struct pt_regs *); | 14 | extern void ptrace_break(struct task_struct *, struct pt_regs *); |
15 | |||
16 | /* | ||
17 | * make sure single-step breakpoint is gone. | ||
18 | */ | ||
19 | static inline void single_step_disable(struct task_struct *task) | ||
20 | { | ||
21 | task->ptrace &= ~PT_SINGLESTEP; | ||
22 | ptrace_cancel_bpt(task); | ||
23 | } | ||
24 | |||
25 | static inline void single_step_enable(struct task_struct *task) | ||
26 | { | ||
27 | task->ptrace |= PT_SINGLESTEP; | ||
28 | } | ||
29 | |||
30 | /* | ||
31 | * Send SIGTRAP if we're single-stepping | ||
32 | */ | ||
33 | static inline void single_step_trap(struct task_struct *task) | ||
34 | { | ||
35 | if (task->ptrace & PT_SINGLESTEP) { | ||
36 | ptrace_cancel_bpt(task); | ||
37 | send_sig(SIGTRAP, task, 1); | ||
38 | } | ||
39 | } | ||
40 | |||
41 | static inline void single_step_clear(struct task_struct *task) | ||
42 | { | ||
43 | if (task->ptrace & PT_SINGLESTEP) | ||
44 | ptrace_cancel_bpt(task); | ||
45 | } | ||
46 | |||
47 | static inline void single_step_set(struct task_struct *task) | ||
48 | { | ||
49 | if (task->ptrace & PT_SINGLESTEP) | ||
50 | ptrace_set_bpt(task); | ||
51 | } | ||
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 @@ | |||
9 | */ | 9 | */ |
10 | #include <linux/errno.h> | 10 | #include <linux/errno.h> |
11 | #include <linux/signal.h> | 11 | #include <linux/signal.h> |
12 | #include <linux/ptrace.h> | ||
13 | #include <linux/personality.h> | 12 | #include <linux/personality.h> |
14 | #include <linux/freezer.h> | 13 | #include <linux/freezer.h> |
15 | 14 | ||
@@ -285,11 +284,7 @@ asmlinkage int sys_sigreturn(struct pt_regs *regs) | |||
285 | if (restore_sigframe(regs, frame)) | 284 | if (restore_sigframe(regs, frame)) |
286 | goto badframe; | 285 | goto badframe; |
287 | 286 | ||
288 | /* Send SIGTRAP if we're single-stepping */ | 287 | single_step_trap(current); |
289 | if (current->ptrace & PT_SINGLESTEP) { | ||
290 | ptrace_cancel_bpt(current); | ||
291 | send_sig(SIGTRAP, current, 1); | ||
292 | } | ||
293 | 288 | ||
294 | return regs->ARM_r0; | 289 | return regs->ARM_r0; |
295 | 290 | ||
@@ -324,11 +319,7 @@ asmlinkage int sys_rt_sigreturn(struct pt_regs *regs) | |||
324 | if (do_sigaltstack(&frame->sig.uc.uc_stack, NULL, regs->ARM_sp) == -EFAULT) | 319 | if (do_sigaltstack(&frame->sig.uc.uc_stack, NULL, regs->ARM_sp) == -EFAULT) |
325 | goto badframe; | 320 | goto badframe; |
326 | 321 | ||
327 | /* Send SIGTRAP if we're single-stepping */ | 322 | single_step_trap(current); |
328 | if (current->ptrace & PT_SINGLESTEP) { | ||
329 | ptrace_cancel_bpt(current); | ||
330 | send_sig(SIGTRAP, current, 1); | ||
331 | } | ||
332 | 323 | ||
333 | return regs->ARM_r0; | 324 | return regs->ARM_r0; |
334 | 325 | ||
@@ -644,14 +635,12 @@ static int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall) | |||
644 | if (try_to_freeze()) | 635 | if (try_to_freeze()) |
645 | goto no_signal; | 636 | goto no_signal; |
646 | 637 | ||
647 | if (current->ptrace & PT_SINGLESTEP) | 638 | single_step_clear(current); |
648 | ptrace_cancel_bpt(current); | ||
649 | 639 | ||
650 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); | 640 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); |
651 | if (signr > 0) { | 641 | if (signr > 0) { |
652 | handle_signal(signr, &ka, &info, oldset, regs, syscall); | 642 | handle_signal(signr, &ka, &info, oldset, regs, syscall); |
653 | if (current->ptrace & PT_SINGLESTEP) | 643 | single_step_set(current); |
654 | ptrace_set_bpt(current); | ||
655 | return 1; | 644 | return 1; |
656 | } | 645 | } |
657 | 646 | ||
@@ -705,8 +694,7 @@ static int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall) | |||
705 | restart_syscall(regs); | 694 | restart_syscall(regs); |
706 | } | 695 | } |
707 | } | 696 | } |
708 | if (current->ptrace & PT_SINGLESTEP) | 697 | single_step_set(current); |
709 | ptrace_set_bpt(current); | ||
710 | return 0; | 698 | return 0; |
711 | } | 699 | } |
712 | 700 | ||
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 @@ | |||
1 | #include <linux/sched.h> | ||
2 | #include <linux/stacktrace.h> | ||
3 | |||
4 | #include "stacktrace.h" | ||
5 | |||
6 | int walk_stackframe(unsigned long fp, unsigned long low, unsigned long high, | ||
7 | int (*fn)(struct stackframe *, void *), void *data) | ||
8 | { | ||
9 | struct stackframe *frame; | ||
10 | |||
11 | do { | ||
12 | /* | ||
13 | * Check current frame pointer is within bounds | ||
14 | */ | ||
15 | if ((fp - 12) < low || fp + 4 >= high) | ||
16 | break; | ||
17 | |||
18 | frame = (struct stackframe *)(fp - 12); | ||
19 | |||
20 | if (fn(frame, data)) | ||
21 | break; | ||
22 | |||
23 | /* | ||
24 | * Update the low bound - the next frame must always | ||
25 | * be at a higher address than the current frame. | ||
26 | */ | ||
27 | low = fp + 4; | ||
28 | fp = frame->fp; | ||
29 | } while (fp); | ||
30 | |||
31 | return 0; | ||
32 | } | ||
33 | |||
34 | #ifdef CONFIG_STACKTRACE | ||
35 | struct stack_trace_data { | ||
36 | struct stack_trace *trace; | ||
37 | unsigned int skip; | ||
38 | }; | ||
39 | |||
40 | static int save_trace(struct stackframe *frame, void *d) | ||
41 | { | ||
42 | struct stack_trace_data *data = d; | ||
43 | struct stack_trace *trace = data->trace; | ||
44 | |||
45 | if (data->skip) { | ||
46 | data->skip--; | ||
47 | return 0; | ||
48 | } | ||
49 | |||
50 | trace->entries[trace->nr_entries++] = frame->lr; | ||
51 | |||
52 | return trace->nr_entries >= trace->max_entries; | ||
53 | } | ||
54 | |||
55 | void save_stack_trace(struct stack_trace *trace, struct task_struct *task) | ||
56 | { | ||
57 | struct stack_trace_data data; | ||
58 | unsigned long fp, base; | ||
59 | |||
60 | data.trace = trace; | ||
61 | data.skip = trace->skip; | ||
62 | |||
63 | if (task) { | ||
64 | base = (unsigned long)task_stack_page(task); | ||
65 | fp = 0; /* FIXME */ | ||
66 | } else { | ||
67 | base = (unsigned long)task_stack_page(current); | ||
68 | asm("mov %0, fp" : "=r" (fp)); | ||
69 | } | ||
70 | |||
71 | walk_stackframe(fp, base, base + THREAD_SIZE, save_trace, &data); | ||
72 | } | ||
73 | #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 @@ | |||
1 | struct stackframe { | ||
2 | unsigned long fp; | ||
3 | unsigned long sp; | ||
4 | unsigned long lr; | ||
5 | unsigned long pc; | ||
6 | }; | ||
7 | |||
8 | int walk_stackframe(unsigned long fp, unsigned long low, unsigned long high, | ||
9 | 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) | |||
327 | } | 327 | } |
328 | EXPORT_SYMBOL(restore_time_delta); | 328 | EXPORT_SYMBOL(restore_time_delta); |
329 | 329 | ||
330 | #ifndef CONFIG_GENERIC_CLOCKEVENTS | ||
330 | /* | 331 | /* |
331 | * Kernel system timer support. | 332 | * Kernel system timer support. |
332 | */ | 333 | */ |
@@ -340,8 +341,9 @@ void timer_tick(void) | |||
340 | update_process_times(user_mode(get_irq_regs())); | 341 | update_process_times(user_mode(get_irq_regs())); |
341 | #endif | 342 | #endif |
342 | } | 343 | } |
344 | #endif | ||
343 | 345 | ||
344 | #ifdef CONFIG_PM | 346 | #if defined(CONFIG_PM) && !defined(CONFIG_GENERIC_CLOCKEVENTS) |
345 | static int timer_suspend(struct sys_device *dev, pm_message_t state) | 347 | static int timer_suspend(struct sys_device *dev, pm_message_t state) |
346 | { | 348 | { |
347 | struct sys_timer *timer = container_of(dev, struct sys_timer, dev); | 349 | 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..f05e66b0f868 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c | |||
@@ -16,7 +16,6 @@ | |||
16 | #include <linux/signal.h> | 16 | #include <linux/signal.h> |
17 | #include <linux/spinlock.h> | 17 | #include <linux/spinlock.h> |
18 | #include <linux/personality.h> | 18 | #include <linux/personality.h> |
19 | #include <linux/ptrace.h> | ||
20 | #include <linux/kallsyms.h> | 19 | #include <linux/kallsyms.h> |
21 | #include <linux/delay.h> | 20 | #include <linux/delay.h> |
22 | #include <linux/init.h> | 21 | #include <linux/init.h> |
@@ -45,7 +44,18 @@ static int __init user_debug_setup(char *str) | |||
45 | __setup("user_debug=", user_debug_setup); | 44 | __setup("user_debug=", user_debug_setup); |
46 | #endif | 45 | #endif |
47 | 46 | ||
48 | void dump_backtrace_entry(unsigned long where, unsigned long from) | 47 | static void dump_mem(const char *str, unsigned long bottom, unsigned long top); |
48 | |||
49 | static inline int in_exception_text(unsigned long ptr) | ||
50 | { | ||
51 | extern char __exception_text_start[]; | ||
52 | extern char __exception_text_end[]; | ||
53 | |||
54 | return ptr >= (unsigned long)&__exception_text_start && | ||
55 | ptr < (unsigned long)&__exception_text_end; | ||
56 | } | ||
57 | |||
58 | void dump_backtrace_entry(unsigned long where, unsigned long from, unsigned long frame) | ||
49 | { | 59 | { |
50 | #ifdef CONFIG_KALLSYMS | 60 | #ifdef CONFIG_KALLSYMS |
51 | printk("[<%08lx>] ", where); | 61 | printk("[<%08lx>] ", where); |
@@ -55,6 +65,9 @@ void dump_backtrace_entry(unsigned long where, unsigned long from) | |||
55 | #else | 65 | #else |
56 | printk("Function entered at [<%08lx>] from [<%08lx>]\n", where, from); | 66 | printk("Function entered at [<%08lx>] from [<%08lx>]\n", where, from); |
57 | #endif | 67 | #endif |
68 | |||
69 | if (in_exception_text(where)) | ||
70 | dump_mem("Exception stack", frame + 4, frame + 4 + sizeof(struct pt_regs)); | ||
58 | } | 71 | } |
59 | 72 | ||
60 | /* | 73 | /* |
@@ -266,13 +279,14 @@ void unregister_undef_hook(struct undef_hook *hook) | |||
266 | spin_unlock_irqrestore(&undef_lock, flags); | 279 | spin_unlock_irqrestore(&undef_lock, flags); |
267 | } | 280 | } |
268 | 281 | ||
269 | asmlinkage void do_undefinstr(struct pt_regs *regs) | 282 | asmlinkage void __exception do_undefinstr(struct pt_regs *regs) |
270 | { | 283 | { |
271 | unsigned int correction = thumb_mode(regs) ? 2 : 4; | 284 | unsigned int correction = thumb_mode(regs) ? 2 : 4; |
272 | unsigned int instr; | 285 | unsigned int instr; |
273 | struct undef_hook *hook; | 286 | struct undef_hook *hook; |
274 | siginfo_t info; | 287 | siginfo_t info; |
275 | void __user *pc; | 288 | void __user *pc; |
289 | unsigned long flags; | ||
276 | 290 | ||
277 | /* | 291 | /* |
278 | * According to the ARM ARM, PC is 2 or 4 bytes ahead, | 292 | * According to the ARM ARM, PC is 2 or 4 bytes ahead, |
@@ -291,7 +305,7 @@ asmlinkage void do_undefinstr(struct pt_regs *regs) | |||
291 | get_user(instr, (u32 __user *)pc); | 305 | get_user(instr, (u32 __user *)pc); |
292 | } | 306 | } |
293 | 307 | ||
294 | spin_lock_irq(&undef_lock); | 308 | spin_lock_irqsave(&undef_lock, flags); |
295 | list_for_each_entry(hook, &undef_hook, node) { | 309 | list_for_each_entry(hook, &undef_hook, node) { |
296 | if ((instr & hook->instr_mask) == hook->instr_val && | 310 | if ((instr & hook->instr_mask) == hook->instr_val && |
297 | (regs->ARM_cpsr & hook->cpsr_mask) == hook->cpsr_val) { | 311 | (regs->ARM_cpsr & hook->cpsr_mask) == hook->cpsr_val) { |
@@ -301,7 +315,7 @@ asmlinkage void do_undefinstr(struct pt_regs *regs) | |||
301 | } | 315 | } |
302 | } | 316 | } |
303 | } | 317 | } |
304 | spin_unlock_irq(&undef_lock); | 318 | spin_unlock_irqrestore(&undef_lock, flags); |
305 | 319 | ||
306 | #ifdef CONFIG_DEBUG_USER | 320 | #ifdef CONFIG_DEBUG_USER |
307 | if (user_debug & UDBG_UNDEFINED) { | 321 | if (user_debug & UDBG_UNDEFINED) { |
diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S index d1a6a597ed9a..6be67296f333 100644 --- a/arch/arm/kernel/vmlinux.lds.S +++ b/arch/arm/kernel/vmlinux.lds.S | |||
@@ -83,6 +83,9 @@ SECTIONS | |||
83 | 83 | ||
84 | .text : { /* Real text segment */ | 84 | .text : { /* Real text segment */ |
85 | _text = .; /* Text and read-only data */ | 85 | _text = .; /* Text and read-only data */ |
86 | __exception_text_start = .; | ||
87 | *(.exception.text) | ||
88 | __exception_text_end = .; | ||
86 | *(.text) | 89 | *(.text) |
87 | SCHED_TEXT | 90 | SCHED_TEXT |
88 | LOCK_TEXT | 91 | LOCK_TEXT |