aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/kernel')
-rw-r--r--arch/arm/kernel/Makefile4
-rw-r--r--arch/arm/kernel/ecard.c31
-rw-r--r--arch/arm/kernel/ecard.h56
-rw-r--r--arch/arm/kernel/head.S6
-rw-r--r--arch/arm/kernel/irq.c3
-rw-r--r--arch/arm/kernel/process.c4
-rw-r--r--arch/arm/kernel/ptrace.c21
-rw-r--r--arch/arm/kernel/ptrace.h39
-rw-r--r--arch/arm/kernel/signal.c22
-rw-r--r--arch/arm/kernel/stacktrace.c73
-rw-r--r--arch/arm/kernel/stacktrace.h9
-rw-r--r--arch/arm/kernel/time.c4
-rw-r--r--arch/arm/kernel/traps.c24
-rw-r--r--arch/arm/kernel/vmlinux.lds.S3
14 files changed, 242 insertions, 57 deletions
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
index bb28087bf81..593b56509f4 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
9obj-y := compat.o entry-armv.o entry-common.o irq.o \ 9obj-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
13obj-$(CONFIG_ISA_DMA_API) += dma.o 13obj-$(CONFIG_ISA_DMA_API) += dma.o
14obj-$(CONFIG_ARCH_ACORN) += ecard.o 14obj-$(CONFIG_ARCH_ACORN) += ecard.o
diff --git a/arch/arm/kernel/ecard.c b/arch/arm/kernel/ecard.c
index f1c0fb97417..bdbd7da9928 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)
263static int 266static int
264ecard_task(void * unused) 267ecard_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
907static ssize_t ecard_show_type(struct device *dev, struct device_attribute *attr, char *buf) 909static 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
913static struct device_attribute ecard_dev_attrs[] = { 915static struct device_attribute ecard_dev_attrs[] = {
@@ -1058,13 +1060,14 @@ ecard_probe(int slot, card_type_t type)
1058 */ 1060 */
1059static int __init ecard_init(void) 1061static 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 00000000000..d7c2dacf935
--- /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 */
15struct 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 */
45struct 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 66db0a9bf0b..1d35edacc01 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 e101846ab7d..11dcd52e51b 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 */
112asmlinkage void asm_do_IRQ(unsigned int irq, struct pt_regs *regs) 111asmlinkage 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 782af3cb213..5d6e6523598 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 9254ba2f46f..13af4006a40 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 */
463void ptrace_disable(struct task_struct *child) 461void 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 f7cad13a22e..def3b6184a7 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
10extern void ptrace_cancel_bpt(struct task_struct *); 12extern void ptrace_cancel_bpt(struct task_struct *);
11extern void ptrace_set_bpt(struct task_struct *); 13extern void ptrace_set_bpt(struct task_struct *);
12extern void ptrace_break(struct task_struct *, struct pt_regs *); 14extern void ptrace_break(struct task_struct *, struct pt_regs *);
15
16/*
17 * make sure single-step breakpoint is gone.
18 */
19static inline void single_step_disable(struct task_struct *task)
20{
21 task->ptrace &= ~PT_SINGLESTEP;
22 ptrace_cancel_bpt(task);
23}
24
25static 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 */
33static 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
41static inline void single_step_clear(struct task_struct *task)
42{
43 if (task->ptrace & PT_SINGLESTEP)
44 ptrace_cancel_bpt(task);
45}
46
47static 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 3843d3bab2d..54cdf1aeefc 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 00000000000..77ef35efaa8
--- /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
6int 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
35struct stack_trace_data {
36 struct stack_trace *trace;
37 unsigned int skip;
38};
39
40static 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
55void 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 00000000000..e9fd20cb566
--- /dev/null
+++ b/arch/arm/kernel/stacktrace.h
@@ -0,0 +1,9 @@
1struct stackframe {
2 unsigned long fp;
3 unsigned long sp;
4 unsigned long lr;
5 unsigned long pc;
6};
7
8int 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 f61decb89ba..d0540e4eaf5 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}
328EXPORT_SYMBOL(restore_time_delta); 328EXPORT_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)
345static int timer_suspend(struct sys_device *dev, pm_message_t state) 347static 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 24095601359..f05e66b0f86 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
48void dump_backtrace_entry(unsigned long where, unsigned long from) 47static void dump_mem(const char *str, unsigned long bottom, unsigned long top);
48
49static 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
58void 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
269asmlinkage void do_undefinstr(struct pt_regs *regs) 282asmlinkage 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 d1a6a597ed9..6be67296f33 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