diff options
Diffstat (limited to 'arch/arm/kernel')
-rw-r--r-- | arch/arm/kernel/armksyms.c | 4 | ||||
-rw-r--r-- | arch/arm/kernel/arthur.c | 2 | ||||
-rw-r--r-- | arch/arm/kernel/bios32.c | 1 | ||||
-rw-r--r-- | arch/arm/kernel/dma-footbridge.c | 1 | ||||
-rw-r--r-- | arch/arm/kernel/dma-rpc.c | 1 | ||||
-rw-r--r-- | arch/arm/kernel/dma.c | 2 | ||||
-rw-r--r-- | arch/arm/kernel/ecard.c | 10 | ||||
-rw-r--r-- | arch/arm/kernel/hw-footbridge.c | 145 | ||||
-rw-r--r-- | arch/arm/kernel/hw-sa1100.c | 2 | ||||
-rw-r--r-- | arch/arm/kernel/irq.c | 2 | ||||
-rw-r--r-- | arch/arm/kernel/isa.c | 1 | ||||
-rw-r--r-- | arch/arm/kernel/leds-footbridge.c | 2 | ||||
-rw-r--r-- | arch/arm/kernel/leds-sa1100.c | 2 | ||||
-rw-r--r-- | arch/arm/kernel/process.c | 10 | ||||
-rw-r--r-- | arch/arm/kernel/ptrace.c | 571 | ||||
-rw-r--r-- | arch/arm/kernel/ptrace.h | 16 | ||||
-rw-r--r-- | arch/arm/kernel/semaphore.c | 1 | ||||
-rw-r--r-- | arch/arm/kernel/setup.c | 1 | ||||
-rw-r--r-- | arch/arm/kernel/signal.c | 23 | ||||
-rw-r--r-- | arch/arm/kernel/time.c | 1 | ||||
-rw-r--r-- | arch/arm/kernel/traps.c | 126 |
21 files changed, 482 insertions, 442 deletions
diff --git a/arch/arm/kernel/armksyms.c b/arch/arm/kernel/armksyms.c index ffd0f1b5e..5ac0743be 100644 --- a/arch/arm/kernel/armksyms.c +++ b/arch/arm/kernel/armksyms.c @@ -31,6 +31,8 @@ extern void outswb(unsigned int port, const void *to, int len); extern unsigned int local_bh_count[NR_CPUS]; extern unsigned int local_irq_count[NR_CPUS]; +extern void __bad_xchg(volatile void *ptr, int size); + /* * syscalls */ @@ -90,7 +92,6 @@ EXPORT_SYMBOL(kd_mksound); EXPORT_SYMBOL(dump_thread); EXPORT_SYMBOL(dump_fpu); EXPORT_SYMBOL(udelay); -EXPORT_SYMBOL(xchg_str); EXPORT_SYMBOL(local_bh_count); EXPORT_SYMBOL(local_irq_count); #ifdef CONFIG_CPU_32 @@ -103,6 +104,7 @@ EXPORT_SYMBOL(system_serial_low); EXPORT_SYMBOL(system_serial_high); EXPORT_SYMBOL(mem_fclk_21285); EXPORT_SYMBOL(__bug); +EXPORT_SYMBOL(__bad_xchg); EXPORT_SYMBOL(__readwrite_bug); EXPORT_SYMBOL(enable_irq); EXPORT_SYMBOL(disable_irq); diff --git a/arch/arm/kernel/arthur.c b/arch/arm/kernel/arthur.c index 8a8a5510d..0547302f8 100644 --- a/arch/arm/kernel/arthur.c +++ b/arch/arm/kernel/arthur.c @@ -3,8 +3,8 @@ * Copyright (C) 1998-1999 Philip Blundell */ -#include <linux/personality.h> #include <linux/module.h> +#include <linux/personality.h> #include <linux/stddef.h> #include <linux/signal.h> #include <linux/sched.h> diff --git a/arch/arm/kernel/bios32.c b/arch/arm/kernel/bios32.c index 2fbda24be..a077f13b9 100644 --- a/arch/arm/kernel/bios32.c +++ b/arch/arm/kernel/bios32.c @@ -8,7 +8,6 @@ #include <linux/config.h> #include <linux/kernel.h> #include <linux/pci.h> -#include <linux/errno.h> #include <linux/init.h> #include <asm/irq.h> diff --git a/arch/arm/kernel/dma-footbridge.c b/arch/arm/kernel/dma-footbridge.c index 65875831c..1d2ef26c4 100644 --- a/arch/arm/kernel/dma-footbridge.c +++ b/arch/arm/kernel/dma-footbridge.c @@ -13,7 +13,6 @@ #include <linux/config.h> #include <linux/sched.h> -#include <linux/errno.h> #include <linux/init.h> #include <asm/dma.h> diff --git a/arch/arm/kernel/dma-rpc.c b/arch/arm/kernel/dma-rpc.c index e1b54233b..f4bc97f1d 100644 --- a/arch/arm/kernel/dma-rpc.c +++ b/arch/arm/kernel/dma-rpc.c @@ -15,6 +15,7 @@ #include <asm/fiq.h> #include <asm/io.h> #include <asm/iomd.h> +#include <asm/irq.h> #include <asm/hardware.h> #include <asm/uaccess.h> diff --git a/arch/arm/kernel/dma.c b/arch/arm/kernel/dma.c index 7d1a11cd5..ff8322d34 100644 --- a/arch/arm/kernel/dma.c +++ b/arch/arm/kernel/dma.c @@ -14,9 +14,9 @@ * * Moved DMA resource allocation here... */ +#include <linux/malloc.h> #include <linux/sched.h> #include <linux/module.h> -#include <linux/malloc.h> #include <linux/mman.h> #include <linux/init.h> #include <linux/spinlock.h> diff --git a/arch/arm/kernel/ecard.c b/arch/arm/kernel/ecard.c index 61eb422b2..b4d38e00f 100644 --- a/arch/arm/kernel/ecard.c +++ b/arch/arm/kernel/ecard.c @@ -33,9 +33,7 @@ #include <linux/interrupt.h> #include <linux/mm.h> #include <linux/malloc.h> -#include <linux/errno.h> #include <linux/proc_fs.h> -#include <linux/unistd.h> #include <linux/init.h> #include <asm/dma.h> @@ -913,7 +911,6 @@ ecard_probe(int slot, card_type_t type) ecard_t **ecp; ecard_t *ec; struct ex_ecid cid; - char buffer[200]; int i, rc = -ENOMEM; ec = kmalloc(sizeof(ecard_t), GFP_KERNEL); @@ -994,12 +991,9 @@ ecard_probe(int slot, card_type_t type) nodev: if (rc && ec) kfree(ec); - else { + else slot_to_expcard[slot] = ec; - ecard_prints(buffer, ec); - printk("%s", buffer); - } return rc; } @@ -1075,7 +1069,7 @@ void __init ecard_init(void) init_waitqueue_head(&ecard_done); #endif - printk("Probing expansion cards: (does not imply support)\n"); + printk("Probing expansion cards\n"); for (slot = 0; slot < 8; slot ++) { if (ecard_probe(slot, ECARD_EASI) == -ENODEV) diff --git a/arch/arm/kernel/hw-footbridge.c b/arch/arm/kernel/hw-footbridge.c index 08aac078e..b56b944e7 100644 --- a/arch/arm/kernel/hw-footbridge.c +++ b/arch/arm/kernel/hw-footbridge.c @@ -8,19 +8,12 @@ #include <linux/config.h> #include <linux/module.h> #include <linux/sched.h> +#include <linux/ioport.h> #include <linux/kernel.h> #include <linux/delay.h> -#include <linux/pci.h> -#include <linux/ptrace.h> -#include <linux/interrupt.h> -#include <linux/ioport.h> -#include <linux/smp.h> -#include <linux/mm.h> #include <linux/init.h> -#include <asm/dec21285.h> #include <asm/io.h> -#include <asm/irq.h> #include <asm/leds.h> #include <asm/system.h> @@ -28,6 +21,13 @@ #define GP1_IO_BASE 0x338 #define GP2_IO_BASE 0x33a + +#ifdef CONFIG_LEDS +#define DEFAULT_LEDS 0 +#else +#define DEFAULT_LEDS GPIO_GREEN_LED +#endif + /* * Netwinder stuff */ @@ -396,9 +396,9 @@ static unsigned char rwa_unlock[] __initdata = 0x3a, 0x9d, 0xce, 0xe7, 0x73, 0x39 }; #ifndef DEBUG -#define dprintk if (0) printk +#define dprintk(x...) #else -#define dprintk printk +#define dprintk(x...) printk(x) #endif #define WRITE_RWA(r,v) do { outb((r), 0x279); udelay(10); outb((v), 0xa79); } while (0) @@ -602,74 +602,13 @@ EXPORT_SYMBOL(gpio_modify_op); EXPORT_SYMBOL(gpio_modify_io); EXPORT_SYMBOL(cpld_modify); -#endif - -#ifdef CONFIG_LEDS -#define DEFAULT_LEDS 0 -#else -#define DEFAULT_LEDS GPIO_GREEN_LED -#endif - -/* - * CATS stuff - */ -#ifdef CONFIG_ARCH_CATS - -#define CONFIG_PORT 0x370 -#define INDEX_PORT (CONFIG_PORT) -#define DATA_PORT (CONFIG_PORT + 1) - -static void __init cats_hw_init(void) -{ - /* Set Aladdin to CONFIGURE mode */ - outb(0x51, CONFIG_PORT); - outb(0x23, CONFIG_PORT); - - /* Select logical device 3 */ - outb(0x07, INDEX_PORT); - outb(0x03, DATA_PORT); - - /* Set parallel port to DMA channel 3, ECP+EPP1.9, - enable EPP timeout */ - outb(0x74, INDEX_PORT); - outb(0x03, DATA_PORT); - - outb(0xf0, INDEX_PORT); - outb(0x0f, DATA_PORT); - - outb(0xf1, INDEX_PORT); - outb(0x07, DATA_PORT); - - /* Select logical device 4 */ - outb(0x07, INDEX_PORT); - outb(0x04, DATA_PORT); - - /* UART1 high speed mode */ - outb(0xf0, INDEX_PORT); - outb(0x02, DATA_PORT); - - /* Select logical device 5 */ - outb(0x07, INDEX_PORT); - outb(0x05, DATA_PORT); - - /* UART2 high speed mode */ - outb(0xf0, INDEX_PORT); - outb(0x02, DATA_PORT); - - /* Set Aladdin to RUN mode */ - outb(0xbb, CONFIG_PORT); -} - -#endif - /* * Initialise any other hardware after we've got the PCI bus * initialised. We may need the PCI bus to talk to this other * hardware. */ -static int __init hw_init(void) +static int __init nw_hw_init(void) { -#ifdef CONFIG_ARCH_NETWINDER /* * this ought to have a better home... * Since this calls the above routines, which are @@ -688,12 +627,66 @@ static int __init hw_init(void) gpio_modify_op(GPIO_RED_LED|GPIO_GREEN_LED, DEFAULT_LEDS); spin_unlock_irqrestore(&gpio_lock, flags); } + return 0; +} + +__initcall(nw_hw_init); #endif + +/* + * CATS stuff + */ #ifdef CONFIG_ARCH_CATS - if (machine_is_cats()) - cats_hw_init(); -#endif + +#define CONFIG_PORT 0x370 +#define INDEX_PORT (CONFIG_PORT) +#define DATA_PORT (CONFIG_PORT + 1) + +static int __init cats_hw_init(void) +{ + if (machine_is_cats()) { + /* Set Aladdin to CONFIGURE mode */ + outb(0x51, CONFIG_PORT); + outb(0x23, CONFIG_PORT); + + /* Select logical device 3 */ + outb(0x07, INDEX_PORT); + outb(0x03, DATA_PORT); + + /* Set parallel port to DMA channel 3, ECP+EPP1.9, + enable EPP timeout */ + outb(0x74, INDEX_PORT); + outb(0x03, DATA_PORT); + + outb(0xf0, INDEX_PORT); + outb(0x0f, DATA_PORT); + + outb(0xf1, INDEX_PORT); + outb(0x07, DATA_PORT); + + /* Select logical device 4 */ + outb(0x07, INDEX_PORT); + outb(0x04, DATA_PORT); + + /* UART1 high speed mode */ + outb(0xf0, INDEX_PORT); + outb(0x02, DATA_PORT); + + /* Select logical device 5 */ + outb(0x07, INDEX_PORT); + outb(0x05, DATA_PORT); + + /* UART2 high speed mode */ + outb(0xf0, INDEX_PORT); + outb(0x02, DATA_PORT); + + /* Set Aladdin to RUN mode */ + outb(0xbb, CONFIG_PORT); + } + return 0; } -__initcall(hw_init); +__initcall(cats_hw_init); +#endif + diff --git a/arch/arm/kernel/hw-sa1100.c b/arch/arm/kernel/hw-sa1100.c index 539bb721b..862c3a2c4 100644 --- a/arch/arm/kernel/hw-sa1100.c +++ b/arch/arm/kernel/hw-sa1100.c @@ -10,9 +10,9 @@ * */ #include <linux/config.h> +#include <linux/module.h> #include <linux/init.h> #include <linux/kernel.h> -#include <linux/module.h> #include <linux/sched.h> #include <asm/delay.h> diff --git a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c index 7a761b7c6..40a47c45f 100644 --- a/arch/arm/kernel/irq.c +++ b/arch/arm/kernel/irq.c @@ -17,7 +17,6 @@ */ #include <linux/config.h> #include <linux/ptrace.h> -#include <linux/errno.h> #include <linux/kernel_stat.h> #include <linux/signal.h> #include <linux/sched.h> @@ -26,7 +25,6 @@ #include <linux/malloc.h> #include <linux/random.h> #include <linux/smp.h> -#include <linux/smp_lock.h> #include <linux/init.h> #include <asm/hardware.h> diff --git a/arch/arm/kernel/isa.c b/arch/arm/kernel/isa.c index a5424f8b6..17696acb0 100644 --- a/arch/arm/kernel/isa.c +++ b/arch/arm/kernel/isa.c @@ -13,7 +13,6 @@ #include <linux/stddef.h> #include <linux/types.h> -#include <linux/linkage.h> #include <linux/fs.h> #include <linux/sysctl.h> #include <linux/init.h> diff --git a/arch/arm/kernel/leds-footbridge.c b/arch/arm/kernel/leds-footbridge.c index 4fa2237eb..b309c2ea3 100644 --- a/arch/arm/kernel/leds-footbridge.c +++ b/arch/arm/kernel/leds-footbridge.c @@ -18,8 +18,8 @@ * 02-05-1999 RMK Various cleanups */ #include <linux/config.h> -#include <linux/kernel.h> #include <linux/module.h> +#include <linux/kernel.h> #include <linux/init.h> #include <linux/spinlock.h> diff --git a/arch/arm/kernel/leds-sa1100.c b/arch/arm/kernel/leds-sa1100.c index ef6918d7c..f2f0325c3 100644 --- a/arch/arm/kernel/leds-sa1100.c +++ b/arch/arm/kernel/leds-sa1100.c @@ -29,8 +29,8 @@ * */ #include <linux/config.h> -#include <linux/kernel.h> #include <linux/module.h> +#include <linux/kernel.h> #include <linux/init.h> #include <linux/spinlock.h> diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c index 40b3b9e72..cab969c5c 100644 --- a/arch/arm/kernel/process.c +++ b/arch/arm/kernel/process.c @@ -7,28 +7,22 @@ #include <stdarg.h> -#include <linux/errno.h> +#include <linux/config.h> #include <linux/sched.h> #include <linux/kernel.h> #include <linux/mm.h> -#include <linux/smp.h> -#include <linux/smp_lock.h> #include <linux/stddef.h> #include <linux/unistd.h> #include <linux/ptrace.h> #include <linux/malloc.h> -#include <linux/vmalloc.h> #include <linux/user.h> -#include <linux/a.out.h> -#include <linux/interrupt.h> -#include <linux/config.h> #include <linux/delay.h> #include <linux/reboot.h> #include <linux/init.h> -#include <asm/uaccess.h> #include <asm/system.h> #include <asm/io.h> +#include <asm/uaccess.h> /* * Values for cpu_do_idle() diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c index 1684c5f5f..e45e03fcb 100644 --- a/arch/arm/kernel/ptrace.c +++ b/arch/arm/kernel/ptrace.c @@ -8,7 +8,6 @@ #include <linux/mm.h> #include <linux/smp.h> #include <linux/smp_lock.h> -#include <linux/errno.h> #include <linux/ptrace.h> #include <linux/user.h> @@ -16,6 +15,10 @@ #include <asm/pgtable.h> #include <asm/system.h> +#include "ptrace.h" + +#define REG_PC 15 +#define REG_PSR 16 /* * does not yet catch signals sent when the child dies. * in exit.c or in signal.c. @@ -27,6 +30,18 @@ #define BREAKINST 0xef9f0001 /* + * Get the address of the live pt_regs for the specified task. + * These are saved onto the top kernel stack when the process + * is not running. + */ +static inline struct pt_regs * +get_user_regs(struct task_struct *task) +{ + return (struct pt_regs *) + ((unsigned long)task + 8192 - sizeof(struct pt_regs)); +} + +/* * this routine will get a word off of the processes privileged stack. * the offset is how far from the base addr as stored in the THREAD. * this routine assumes that all the privileged stacks are in our @@ -34,11 +49,7 @@ */ static inline long get_stack_long(struct task_struct *task, int offset) { - struct pt_regs *regs; - - regs = (struct pt_regs *)((unsigned long)task + 8192 - sizeof(struct pt_regs)); - - return regs->uregs[offset]; + return get_user_regs(task)->uregs[offset]; } /* @@ -47,20 +58,16 @@ static inline long get_stack_long(struct task_struct *task, int offset) * this routine assumes that all the privileged stacks are in our * data space. */ -static inline long put_stack_long(struct task_struct *task, int offset, - unsigned long data) +static inline int +put_stack_long(struct task_struct *task, int offset, long data) { - struct pt_regs *regs; - - regs = (struct pt_regs *)((unsigned long)task + 8192 - sizeof(struct pt_regs)); - - regs->uregs[offset] = data; + get_user_regs(task)->uregs[offset] = data; return 0; } -static int -read_long(struct task_struct *child, unsigned long addr, unsigned long *res) +static inline int +read_tsk_long(struct task_struct *child, unsigned long addr, unsigned long *res) { int copied; @@ -69,8 +76,8 @@ read_long(struct task_struct *child, unsigned long addr, unsigned long *res) return copied != sizeof(*res) ? -EIO : 0; } -static int -write_long(struct task_struct *child, unsigned long addr, unsigned long val) +static inline int +write_tsk_long(struct task_struct *child, unsigned long addr, unsigned long val) { int copied; @@ -82,35 +89,33 @@ write_long(struct task_struct *child, unsigned long addr, unsigned long val) /* * Get value of register `rn' (in the instruction) */ -static unsigned long ptrace_getrn (struct task_struct *child, unsigned long insn) +static unsigned long +ptrace_getrn(struct task_struct *child, unsigned long insn) { unsigned int reg = (insn >> 16) & 15; unsigned long val; + val = get_stack_long(child, reg); if (reg == 15) - val = pc_pointer (get_stack_long (child, reg)); - else - val = get_stack_long (child, reg); + val = pc_pointer(val); -printk ("r%02d=%08lX ", reg, val); return val; } /* * Get value of operand 2 (in an ALU instruction) */ -static unsigned long ptrace_getaluop2 (struct task_struct *child, unsigned long insn) +static unsigned long +ptrace_getaluop2(struct task_struct *child, unsigned long insn) { unsigned long val; int shift; int type; -printk ("op2="); if (insn & 1 << 25) { val = insn & 255; shift = (insn >> 8) & 15; type = 3; -printk ("(imm)"); } else { val = get_stack_long (child, insn & 15); @@ -120,9 +125,8 @@ printk ("(imm)"); shift = (insn >> 7) & 31; type = (insn >> 5) & 3; -printk ("(r%02ld)", insn & 15); } -printk ("sh%dx%d", type, shift); + switch (type) { case 0: val <<= shift; break; case 1: val >>= shift; break; @@ -133,24 +137,23 @@ printk ("sh%dx%d", type, shift); val = (val >> shift) | (val << (32 - shift)); break; } -printk ("=%08lX ", val); return val; } /* * Get value of operand 2 (in a LDR instruction) */ -static unsigned long ptrace_getldrop2 (struct task_struct *child, unsigned long insn) +static unsigned long +ptrace_getldrop2(struct task_struct *child, unsigned long insn) { unsigned long val; int shift; int type; - val = get_stack_long (child, insn & 15); + val = get_stack_long(child, insn & 15); shift = (insn >> 7) & 31; type = (insn >> 5) & 3; -printk ("op2=r%02ldsh%dx%d", insn & 15, shift, type); switch (type) { case 0: val <<= shift; break; case 1: val >>= shift; break; @@ -161,7 +164,6 @@ printk ("op2=r%02ldsh%dx%d", insn & 15, shift, type); val = (val >> shift) | (val << (32 - shift)); break; } -printk ("=%08lX ", val); return val; } @@ -170,95 +172,72 @@ get_branch_address(struct task_struct *child, unsigned long pc, unsigned long in { unsigned long alt = 0; -printk(KERN_DEBUG "ptrace_set_bpt: insn=%08lX pc=%08lX ", insn, pc); - switch (insn & 0x0e100000) { + switch (insn & 0x0e000000) { case 0x00000000: - case 0x00100000: - case 0x02000000: - case 0x02100000: /* data processing */ - printk ("data "); - switch (insn & 0x01e0f000) { - case 0x0000f000: - alt = ptrace_getrn(child, insn) & ptrace_getaluop2(child, insn); - break; - case 0x0020f000: - alt = ptrace_getrn(child, insn) ^ ptrace_getaluop2(child, insn); - break; - case 0x0040f000: - alt = ptrace_getrn(child, insn) - ptrace_getaluop2(child, insn); - break; - case 0x0060f000: - alt = ptrace_getaluop2(child, insn) - ptrace_getrn(child, insn); - break; - case 0x0080f000: - alt = ptrace_getrn(child, insn) + ptrace_getaluop2(child, insn); - break; - case 0x00a0f000: - alt = ptrace_getrn(child, insn) + ptrace_getaluop2(child, insn) + - (get_stack_long (child, 16/*REG_PSR*/) & CC_C_BIT ? 1 : 0); - break; - case 0x00c0f000: - alt = ptrace_getrn(child, insn) - ptrace_getaluop2(child, insn) + - (get_stack_long (child, 16/*REG_PSR*/) & CC_C_BIT ? 1 : 0); - break; - case 0x00e0f000: - alt = ptrace_getaluop2(child, insn) - ptrace_getrn(child, insn) + - (get_stack_long (child, 16/*REG_PSR*/) & CC_C_BIT ? 1 : 0); - break; - case 0x0180f000: - alt = ptrace_getrn(child, insn) | ptrace_getaluop2(child, insn); - break; - case 0x01a0f000: - alt = ptrace_getaluop2(child, insn); - break; - case 0x01c0f000: - alt = ptrace_getrn(child, insn) & ~ptrace_getaluop2(child, insn); - break; - case 0x01e0f000: - alt = ~ptrace_getaluop2(child, insn); + case 0x02000000: { + /* + * data processing + */ + long aluop1, aluop2, ccbit; + + if ((insn & 0xf000) != 0xf000) break; + + aluop1 = ptrace_getrn(child, insn); + aluop2 = ptrace_getaluop2(child, insn); + ccbit = get_stack_long(child, REG_PSR) & CC_C_BIT ? 1 : 0; + + switch (insn & 0x01e00000) { + case 0x00000000: alt = aluop1 & aluop2; break; + case 0x00200000: alt = aluop1 ^ aluop2; break; + case 0x00400000: alt = aluop1 - aluop2; break; + case 0x00600000: alt = aluop2 - aluop1; break; + case 0x00800000: alt = aluop1 + aluop2; break; + case 0x00a00000: alt = aluop1 + aluop2 + ccbit; break; + case 0x00c00000: alt = aluop1 - aluop2 + ccbit; break; + case 0x00e00000: alt = aluop2 - aluop1 + ccbit; break; + case 0x01800000: alt = aluop1 | aluop2; break; + case 0x01a00000: alt = aluop2; break; + case 0x01c00000: alt = aluop1 & ~aluop2; break; + case 0x01e00000: alt = ~aluop2; break; } break; + } + + case 0x04000000: + case 0x06000000: + /* + * ldr + */ + if ((insn & 0x0010f000) == 0x0010f000) { + unsigned long base; - case 0x04100000: /* ldr */ - if ((insn & 0xf000) == 0xf000) { -printk ("ldr "); - alt = ptrace_getrn(child, insn); + base = ptrace_getrn(child, insn); if (insn & 1 << 24) { - if (insn & 1 << 23) - alt += ptrace_getldrop2 (child, insn); + long aluop2; + + if (insn & 0x02000000) + aluop2 = ptrace_getldrop2(child, insn); else - alt -= ptrace_getldrop2 (child, insn); - } - if (read_long (child, alt, &alt) < 0) - alt = 0; /* not valid */ - else - alt = pc_pointer (alt); - } - break; + aluop2 = insn & 0xfff; - case 0x06100000: /* ldr imm */ - if ((insn & 0xf000) == 0xf000) { -printk ("ldrimm "); - alt = ptrace_getrn(child, insn); - if (insn & 1 << 24) { if (insn & 1 << 23) - alt += insn & 0xfff; + base += aluop2; else - alt -= insn & 0xfff; + base -= aluop2; } - if (read_long (child, alt, &alt) < 0) - alt = 0; /* not valid */ - else - alt = pc_pointer (alt); + if (read_tsk_long(child, base, &alt) == 0) + alt = pc_pointer(alt); } break; - case 0x08100000: /* ldm */ - if (insn & (1 << 15)) { + case 0x08000000: + /* + * ldm + */ + if ((insn & 0x00108000) == 0x00108000) { unsigned long base; - int nr_regs; -printk ("ldm "); + unsigned int nr_regs; if (insn & (1 << 23)) { nr_regs = insn & 65535; @@ -278,23 +257,22 @@ printk ("ldm "); nr_regs = 0; } - base = ptrace_getrn (child, insn); + base = ptrace_getrn(child, insn); - if (read_long (child, base + nr_regs, &alt) < 0) - alt = 0; /* not valid */ - else + if (read_tsk_long(child, base + nr_regs, &alt) == 0) alt = pc_pointer (alt); break; } break; - case 0x0a000000: - case 0x0a100000: { /* bl or b */ + case 0x0a000000: { + /* + * bl or b + */ signed long displ; -printk ("b/bl "); /* It's a branch/branch link: instead of trying to * figure out whether the branch will be taken or not, - * we'll put a breakpoint at either location. This is + * we'll put a breakpoint at both locations. This is * simpler, more reliable, and probably not a whole lot * slower than the alternative approach of emulating the * branch. @@ -306,7 +284,6 @@ printk ("b/bl "); } break; } -printk ("=%08lX\n", alt); return alt; } @@ -318,9 +295,9 @@ add_breakpoint(struct task_struct *child, struct debug_info *dbg, unsigned long int res = -EINVAL; if (nr < 2) { - res = read_long(child, addr, &dbg->bp[nr].insn); + res = read_tsk_long(child, addr, &dbg->bp[nr].insn); if (res == 0) - res = write_long(child, addr, BREAKINST); + res = write_tsk_long(child, addr, BREAKINST); if (res == 0) { dbg->bp[nr].address = addr; @@ -332,257 +309,309 @@ add_breakpoint(struct task_struct *child, struct debug_info *dbg, unsigned long return res; } -int ptrace_set_bpt (struct task_struct *child) +int ptrace_set_bpt(struct task_struct *child) { - struct debug_info *dbg = &child->thread.debug; - unsigned long insn, pc, alt; + unsigned long insn, pc; int res; - pc = pc_pointer (get_stack_long (child, 15/*REG_PC*/)); + pc = pc_pointer(get_stack_long(child, REG_PC)); - res = read_long(child, pc, &insn); - if (res >= 0) { - res = 0; + res = read_tsk_long(child, pc, &insn); + if (!res) { + struct debug_info *dbg = &child->thread.debug; + unsigned long alt; dbg->nsaved = 0; - res = add_breakpoint(child, dbg, pc + 4); + alt = get_branch_address(child, pc, insn); + if (alt) + res = add_breakpoint(child, dbg, alt); - if (res == 0) { - alt = get_branch_address(child, pc, insn); - if (alt) - res = add_breakpoint(child, dbg, alt); - } + if (!res && (!alt || predicate(insn) != PREDICATE_ALWAYS)) + res = add_breakpoint(child, dbg, pc + 4); } return res; } -/* Ensure no single-step breakpoint is pending. Returns non-zero +/* + * Ensure no single-step breakpoint is pending. Returns non-zero * value if child was being single-stepped. */ -int ptrace_cancel_bpt (struct task_struct *child) +void __ptrace_cancel_bpt(struct task_struct *child) { struct debug_info *dbg = &child->thread.debug; - unsigned long tmp; int i, nsaved = dbg->nsaved; dbg->nsaved = 0; if (nsaved > 2) { - printk ("ptrace_cancel_bpt: bogus nsaved: %d!\n", nsaved); + printk("ptrace_cancel_bpt: bogus nsaved: %d!\n", nsaved); nsaved = 2; } for (i = 0; i < nsaved; i++) { - read_long(child, dbg->bp[i].address, &tmp); + unsigned long tmp; + + read_tsk_long(child, dbg->bp[i].address, &tmp); if (tmp != BREAKINST) printk(KERN_ERR "ptrace_cancel_bpt: weirdness\n"); - write_long(child, dbg->bp[i].address, dbg->bp[i].insn); + write_tsk_long(child, dbg->bp[i].address, dbg->bp[i].insn); } - - return nsaved != 0; } -asmlinkage int sys_ptrace(long request, long pid, long addr, long data) +static int do_ptrace(int request, struct task_struct *child, long addr, long data) { - struct task_struct *child; + unsigned long tmp; int ret; - lock_kernel(); - ret = -EPERM; - if (request == PTRACE_TRACEME) { - /* are we already being traced? */ - if (current->ptrace & PT_PTRACED) - goto out; - /* set the ptrace bit in the process flags. */ - current->ptrace |= PT_PTRACED; - ret = 0; - goto out; - } - if (pid == 1) /* you may not mess with init */ - goto out; - ret = -ESRCH; - if (!(child = find_task_by_pid(pid))) - goto out; - ret = -EPERM; - if (request == PTRACE_ATTACH) { - if (child == current) - goto out; - if ((!child->dumpable || - (current->uid != child->euid) || - (current->uid != child->suid) || - (current->uid != child->uid) || - (current->gid != child->egid) || - (current->gid != child->sgid) || - (!cap_issubset(child->cap_permitted, current->cap_permitted)) || - (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE)) - goto out; - /* the same process cannot be attached many times */ - if (child->ptrace & PT_PTRACED) - goto out; - child->ptrace |= PT_PTRACED; - if (child->p_pptr != current) { - REMOVE_LINKS(child); - child->p_pptr = current; - SET_LINKS(child); - } - send_sig(SIGSTOP, child, 1); - ret = 0; - goto out; - } - ret = -ESRCH; - if (!(child->ptrace & PT_PTRACED)) - goto out; - if (child->state != TASK_STOPPED) { - if (request != PTRACE_KILL) - goto out; - } - if (child->p_pptr != current) - goto out; - switch (request) { - case PTRACE_PEEKTEXT: /* read word at location addr. */ - case PTRACE_PEEKDATA: { - unsigned long tmp; - - ret = read_long(child, addr, &tmp); + /* + * read word at location "addr" in the child process. + */ + case PTRACE_PEEKTEXT: + case PTRACE_PEEKDATA: + ret = read_tsk_long(child, addr, &tmp); if (!ret) ret = put_user(tmp, (unsigned long *) data); - goto out; - } - - case PTRACE_PEEKUSR: { /* read the word at location addr in the USER area. */ - unsigned long tmp; + break; + /* + * read the word at location "addr" in the user registers. + */ + case PTRACE_PEEKUSR: ret = -EIO; if ((addr & 3) || addr < 0 || addr >= sizeof(struct user)) - goto out; + break; tmp = 0; /* Default return condition */ - if (addr < sizeof (struct pt_regs)) + if (addr < sizeof(struct pt_regs)) tmp = get_stack_long(child, (int)addr >> 2); ret = put_user(tmp, (unsigned long *)data); - goto out; - } + break; - case PTRACE_POKETEXT: /* write the word at location addr. */ + /* + * write the word at location addr. + */ + case PTRACE_POKETEXT: case PTRACE_POKEDATA: - ret = write_long(child, addr, data); - goto out; + ret = write_tsk_long(child, addr, data); + break; - case PTRACE_POKEUSR: /* write the word at location addr in the USER area */ + /* + * write the word at location addr in the user registers. + */ + case PTRACE_POKEUSR: ret = -EIO; if ((addr & 3) || addr < 0 || addr >= sizeof(struct user)) - goto out; + break; if (addr < sizeof (struct pt_regs)) ret = put_stack_long(child, (int)addr >> 2, data); - goto out; + break; - case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ - case PTRACE_CONT: /* restart after signal. */ + /* + * continue/restart and stop at next (return from) syscall + */ + case PTRACE_SYSCALL: + case PTRACE_CONT: ret = -EIO; if ((unsigned long) data > _NSIG) - goto out; + break; if (request == PTRACE_SYSCALL) child->ptrace |= PT_TRACESYS; else child->ptrace &= ~PT_TRACESYS; child->exit_code = data; - wake_up_process (child); /* make sure single-step breakpoint is gone. */ - ptrace_cancel_bpt (child); + __ptrace_cancel_bpt(child); + wake_up_process(child); ret = 0; - goto out; + break; - /* make the child exit. Best I can do is send it a sigkill. + /* + * make the child exit. Best I can do is send it a sigkill. * perhaps it should be put in the status that it wants to * exit. */ case PTRACE_KILL: - if (child->state == TASK_ZOMBIE) /* already dead */ - return 0; - wake_up_process (child); + /* already dead */ + ret = 0; + if (child->state == TASK_ZOMBIE) + break; child->exit_code = SIGKILL; /* make sure single-step breakpoint is gone. */ - ptrace_cancel_bpt (child); + __ptrace_cancel_bpt(child); + wake_up_process(child); ret = 0; - goto out; + break; - case PTRACE_SINGLESTEP: /* execute single instruction. */ + /* + * execute single instruction. + */ + case PTRACE_SINGLESTEP: ret = -EIO; if ((unsigned long) data > _NSIG) - goto out; + break; child->thread.debug.nsaved = -1; child->ptrace &= ~PT_TRACESYS; - wake_up_process(child); child->exit_code = data; /* give it a chance to run. */ + wake_up_process(child); ret = 0; - goto out; - - case PTRACE_GETREGS: - { /* Get all gp regs from the child. */ - unsigned char *stack; + break; + + /* + * detach a process that was attached. + */ + case PTRACE_DETACH: + ret = -EIO; + if ((unsigned long) data > _NSIG) + break; + child->ptrace &= ~(PT_PTRACED|PT_TRACESYS); + child->exit_code = data; + write_lock_irq(&tasklist_lock); + REMOVE_LINKS(child); + child->p_pptr = child->p_opptr; + SET_LINKS(child); + write_unlock_irq(&tasklist_lock); + /* make sure single-step breakpoint is gone. */ + __ptrace_cancel_bpt(child); + wake_up_process (child); + ret = 0; + break; + + /* + * Get all gp regs from the child. + */ + case PTRACE_GETREGS: { + struct pt_regs *regs = get_user_regs(child); ret = 0; - stack = (unsigned char *)((unsigned long)child + 8192 - sizeof(struct pt_regs)); - if (copy_to_user((void *)data, stack, + if (copy_to_user((void *)data, regs, sizeof(struct pt_regs))) ret = -EFAULT; - goto out; - }; + break; + } - case PTRACE_SETREGS: - { - /* Set all gp regs in the child. */ - unsigned char *stack; + /* + * Set all gp regs in the child. + */ + case PTRACE_SETREGS: { + struct pt_regs *regs = get_user_regs(child); ret = 0; - stack = (unsigned char *)((unsigned long)child + 8192 - sizeof(struct pt_regs)); - if (copy_from_user(stack, (void *)data, + if (copy_from_user(regs, (void *)data, sizeof(struct pt_regs))) ret = -EFAULT; - goto out; - }; + break; + } - case PTRACE_GETFPREGS: - /* Get the child FPU state. */ - ret = 0; - if (copy_to_user((void *)data, &child->thread.fpstate, - sizeof(struct user_fp))) - ret = -EFAULT; - goto out; + /* + * Get the child FPU state. + */ + case PTRACE_GETFPREGS: + ret = -EIO; + if (!access_ok(VERIFY_WRITE, (void *)data, sizeof(struct user_fp))) + break; + + /* we should check child->used_math here */ + ret = __copy_to_user((void *)data, &child->thread.fpstate, + sizeof(struct user_fp)) ? -EFAULT : 0; + break; + /* + * Set the child FPU state. + */ case PTRACE_SETFPREGS: - /* Set the child FPU state. */ - ret = 0; - if (copy_from_user(&child->thread.fpstate, (void *)data, - sizeof(struct user_fp))) - ret = -EFAULT; - goto out; - - case PTRACE_DETACH: /* detach a process that was attached. */ ret = -EIO; - if ((unsigned long) data > _NSIG) - goto out; - child->ptrace &= ~(PT_PTRACED|PT_TRACESYS); - wake_up_process (child); - child->exit_code = data; - REMOVE_LINKS(child); - child->p_pptr = child->p_opptr; - SET_LINKS(child); - /* make sure single-step breakpoint is gone. */ - ptrace_cancel_bpt (child); - ret = 0; - goto out; + if (!access_ok(VERIFY_READ, (void *)data, sizeof(struct user_fp))) + break; + + child->used_math = 1; + ret = __copy_from_user(&child->thread.fpstate, (void *)data, + sizeof(struct user_fp)) ? -EFAULT : 0; + break; default: ret = -EIO; + break; + } + + return ret; +} + +asmlinkage int sys_ptrace(long request, long pid, long addr, long data) +{ + struct task_struct *child; + int ret; + + lock_kernel(); + ret = -EPERM; + if (request == PTRACE_TRACEME) { + /* are we already being traced? */ + if (current->ptrace & PT_PTRACED) goto out; + /* set the ptrace bit in the process flags. */ + current->ptrace |= PT_PTRACED; + ret = 0; + goto out; } + ret = -ESRCH; + read_lock(&tasklist_lock); + child = find_task_by_pid(pid); + if (child) + get_task_struct(child); + read_unlock(&tasklist_lock); + if (!child) + goto out; + + ret = -EPERM; + if (pid == 1) /* you may not mess with init */ + goto out_tsk; + + if (request == PTRACE_ATTACH) { + if (child == current) + goto out_tsk; + if ((!child->dumpable || + (current->uid != child->euid) || + (current->uid != child->suid) || + (current->uid != child->uid) || + (current->gid != child->egid) || + (current->gid != child->sgid) || + (!cap_issubset(child->cap_permitted, current->cap_permitted)) || + (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE)) + goto out_tsk; + /* the same process cannot be attached many times */ + if (child->ptrace & PT_PTRACED) + goto out_tsk; + child->ptrace |= PT_PTRACED; + + write_lock_irq(&tasklist_lock); + if (child->p_pptr != current) { + REMOVE_LINKS(child); + child->p_pptr = current; + SET_LINKS(child); + } + write_unlock_irq(&tasklist_lock); + + send_sig(SIGSTOP, child, 1); + ret = 0; + goto out_tsk; + } + ret = -ESRCH; + if (!(child->ptrace & PT_PTRACED)) + goto out_tsk; + if (child->state != TASK_STOPPED && request != PTRACE_KILL) + goto out_tsk; + if (child->p_pptr != current) + goto out_tsk; + + ret = do_ptrace(request, child, addr, data); + +out_tsk: + free_task_struct(child); out: unlock_kernel(); return ret; diff --git a/arch/arm/kernel/ptrace.h b/arch/arm/kernel/ptrace.h new file mode 100644 index 000000000..feae0acd8 --- /dev/null +++ b/arch/arm/kernel/ptrace.h @@ -0,0 +1,16 @@ +extern void __ptrace_cancel_bpt(struct task_struct *); +extern int ptrace_set_bpt(struct task_struct *); + +/* + * Clear a breakpoint, if one exists. + */ +static inline int ptrace_cancel_bpt(struct task_struct *tsk) +{ + int nsaved = tsk->thread.debug.nsaved; + + if (nsaved) + __ptrace_cancel_bpt(tsk); + + return nsaved; +} + diff --git a/arch/arm/kernel/semaphore.c b/arch/arm/kernel/semaphore.c index 93a370f2d..8118b6a68 100644 --- a/arch/arm/kernel/semaphore.c +++ b/arch/arm/kernel/semaphore.c @@ -8,7 +8,6 @@ * Modified for ARM by Russell King */ #include <linux/sched.h> -#include <linux/errno.h> #include <asm/semaphore.h> diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c index 1f4295540..c6010476a 100644 --- a/arch/arm/kernel/setup.c +++ b/arch/arm/kernel/setup.c @@ -35,6 +35,7 @@ extern void paging_init(struct meminfo *); extern void bootmem_init(struct meminfo *); extern void reboot_setup(char *str); extern void disable_hlt(void); +extern unsigned long memparse(char *ptr, char **retptr); extern int root_mountflags; extern int _stext, _text, _etext, _edata, _end; diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c index 431dd96c1..3e6cf6cb4 100644 --- a/arch/arm/kernel/signal.c +++ b/arch/arm/kernel/signal.c @@ -10,18 +10,19 @@ #include <linux/smp.h> #include <linux/smp_lock.h> #include <linux/kernel.h> -#include <linux/signal.h> #include <linux/errno.h> +#include <linux/signal.h> #include <linux/wait.h> #include <linux/ptrace.h> -#include <linux/unistd.h> #include <linux/stddef.h> -#include <linux/binfmts.h> +#include <linux/unistd.h> #include <linux/tty.h> +#include <asm/pgalloc.h> #include <asm/ucontext.h> #include <asm/uaccess.h> -#include <asm/pgalloc.h> + +#include "ptrace.h" #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) @@ -31,8 +32,6 @@ asmlinkage int sys_wait4(pid_t pid, unsigned long * stat_addr, int options, unsigned long *ru); asmlinkage int do_signal(sigset_t *oldset, struct pt_regs * regs, int syscall); -extern int ptrace_cancel_bpt (struct task_struct *); -extern int ptrace_set_bpt (struct task_struct *); int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from) { @@ -234,7 +233,7 @@ asmlinkage int sys_sigreturn(struct pt_regs *regs) goto badframe; /* Send SIGTRAP if we're single-stepping */ - if (ptrace_cancel_bpt (current)) + if (ptrace_cancel_bpt(current)) send_sig(SIGTRAP, current, 1); return regs->ARM_r0; @@ -274,7 +273,7 @@ asmlinkage int sys_rt_sigreturn(struct pt_regs *regs) goto badframe; /* Send SIGTRAP if we're single-stepping */ - if (ptrace_cancel_bpt (current)) + if (ptrace_cancel_bpt(current)) send_sig(SIGTRAP, current, 1); return regs->ARM_r0; @@ -500,7 +499,7 @@ asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall) if (!oldset) oldset = ¤t->blocked; - single_stepping = ptrace_cancel_bpt (current); + single_stepping = ptrace_cancel_bpt(current); for (;;) { unsigned long signr; @@ -518,7 +517,7 @@ asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall) current->state = TASK_STOPPED; notify_parent(current, SIGCHLD); schedule(); - single_stepping |= ptrace_cancel_bpt (current); + single_stepping |= ptrace_cancel_bpt(current); /* We're back. Did the debugger cancel the sig? */ if (!(signr = current->exit_code)) @@ -617,7 +616,7 @@ asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall) /* Whee! Actually deliver the signal. */ handle_signal(signr, ka, &info, oldset, regs); if (single_stepping) - ptrace_set_bpt (current); + ptrace_set_bpt(current); return 1; } @@ -629,6 +628,6 @@ asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall) regs->ARM_pc -= 4; } if (single_stepping) - ptrace_set_bpt (current); + ptrace_set_bpt(current); return 0; } diff --git a/arch/arm/kernel/time.c b/arch/arm/kernel/time.c index bdb725551..d7f6640eb 100644 --- a/arch/arm/kernel/time.c +++ b/arch/arm/kernel/time.c @@ -13,7 +13,6 @@ * "A Kernel Model for Precision Timekeeping" by Dave Mills */ #include <linux/config.h> -#include <linux/errno.h> #include <linux/sched.h> #include <linux/kernel.h> #include <linux/interrupt.h> diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index 1d692dd35..188f89722 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c @@ -17,16 +17,18 @@ #include <linux/sched.h> #include <linux/mm.h> #include <linux/spinlock.h> +#include <linux/ptrace.h> #include <linux/init.h> -#include <asm/system.h> -#include <asm/uaccess.h> -#include <asm/io.h> #include <asm/atomic.h> +#include <asm/io.h> #include <asm/pgtable.h> +#include <asm/system.h> +#include <asm/uaccess.h> + +#include "ptrace.h" extern void c_backtrace (unsigned long fp, int pmode); -extern int ptrace_cancel_bpt (struct task_struct *); char *processor_modes[]= { "USER_26", "FIQ_26" , "IRQ_26" , "SVC_26" , "UK4_26" , "UK5_26" , "UK6_26" , "UK7_26" , @@ -46,8 +48,6 @@ static inline void console_verbose(void) console_loglevel = 15; } -int kstack_depth_to_print = 200; - /* * Stack pointers should always be within the kernels view of * physical memory. If it is not there, then we can't dump @@ -199,37 +199,48 @@ void die_if_kernel(const char *str, struct pt_regs *regs, int err) die(str, regs, err); } -void bad_user_access_alignment(const void *ptr) -{ - printk(KERN_ERR "bad user access alignment: ptr = %p, pc = %p\n", ptr, - __builtin_return_address(0)); - current->thread.error_code = 0; - current->thread.trap_no = 11; - force_sig(SIGBUS, current); -/* die_if_kernel("Oops - bad user access alignment", regs, mode);*/ -} - asmlinkage void do_undefinstr(int address, struct pt_regs *regs, int mode) { + unsigned long addr = instruction_pointer(regs); + siginfo_t info; + #ifdef CONFIG_DEBUG_USER printk(KERN_INFO "%s (%d): undefined instruction: pc=%08lx\n", - current->comm, current->pid, instruction_pointer(regs)); + current->comm, current->pid, addr); #endif + current->thread.error_code = 0; current->thread.trap_no = 6; - force_sig(SIGILL, current); + + info.si_signo = SIGILL; + info.si_errno = 0; + info.si_code = ILL_ILLOPC; + info.si_addr = (void *)addr; + + force_sig_info(SIGILL, &info, current); + die_if_kernel("Oops - undefined instruction", regs, mode); } asmlinkage void do_excpt(int address, struct pt_regs *regs, int mode) { + siginfo_t info; + #ifdef CONFIG_DEBUG_USER printk(KERN_INFO "%s (%d): address exception: pc=%08lx\n", current->comm, current->pid, instruction_pointer(regs)); #endif + current->thread.error_code = 0; current->thread.trap_no = 11; - force_sig(SIGBUS, current); + + info.si_signo = SIGBUS; + info.si_errno = 0; + info.si_code = BUS_ADRERR; + info.si_addr = (void *)address; + + force_sig_info(SIGBUS, &info, current); + die_if_kernel("Oops - address exception", regs, mode); } @@ -269,32 +280,38 @@ asmlinkage void bad_mode(struct pt_regs *regs, int reason, int proc_mode) } /* - * 'math_state_restore()' saves the current math information in the - * old math state array, and gets the new ones from the current task. - * - * We no longer save/restore the math state on every context switch - * any more. We only do this now if it actually gets used. - */ -asmlinkage void math_state_restore (void) -{ - current->used_math = 1; -} - -/* * Handle some more esoteric system calls */ -asmlinkage int arm_syscall (int no, struct pt_regs *regs) +asmlinkage int arm_syscall(int no, struct pt_regs *regs) { + siginfo_t info; + switch (no) { case 0: /* branch through 0 */ - force_sig(SIGSEGV, current); + info.si_signo = SIGSEGV; + info.si_errno = 0; + info.si_code = SEGV_MAPERR; + info.si_addr = NULL; + + force_sig_info(SIGSEGV, &info, current); + die_if_kernel("branch through zero", regs, 0); break; - case 1: /* SWI_BREAK_POINT */ - regs->ARM_pc -= 4; /* Decrement PC by one instruction */ - ptrace_cancel_bpt(current); - force_sig(SIGTRAP, current); + case 1: /* SWI BREAK_POINT */ + /* + * The PC is always left pointing at the next + * instruction. Fix this. + */ + regs->ARM_pc -= 4; + __ptrace_cancel_bpt(current); + + info.si_signo = SIGTRAP; + info.si_errno = 0; + info.si_code = TRAP_BRKPT; + info.si_addr = (void *)instruction_pointer(regs); + + force_sig_info(SIGTRAP, &info, current); return regs->ARM_r0; case 2: /* sys_cacheflush */ @@ -350,29 +367,24 @@ asmlinkage void deferred(int n, struct pt_regs *regs) die_if_kernel("Oops", regs, n); } -asmlinkage void arm_malalignedptr(const char *str, void *pc, volatile void *ptr) -{ - printk("Mal-aligned pointer in %s: %p (PC=%p)\n", str, ptr, pc); -} - -asmlinkage void arm_invalidptr(const char *function, int size) +void __bad_xchg(volatile void *ptr, int size) { - printk("Invalid pointer size in %s (pc=%p) size %d\n", - function, __builtin_return_address(0), size); + printk("xchg: bad data size: pc 0x%p, ptr 0x%p, size %d\n", + __builtin_return_address(0), ptr, size); + BUG(); } /* - * A data abort trap was taken, but the instruction was not an instruction - * which should cause the trap to be taken. Try to abort it. Note that - * the while(1) is there because we cannot currently handle returning from - * this function. + * A data abort trap was taken, but we did not handle the instruction. + * Try to abort the user program, or panic if it was the kernel. */ asmlinkage void baddataabort(int code, unsigned long instr, struct pt_regs *regs) { unsigned long addr = instruction_pointer(regs); + siginfo_t info; -#ifdef CONFIG_DEBUG_ERRORS +#ifdef CONFIG_DEBUG_USER dump_instr(addr, 1); { pgd_t *pgd; @@ -389,16 +401,22 @@ baddataabort(int code, unsigned long instr, struct pt_regs *regs) printk ("\n"); } #endif - force_sig(SIGILL, current); + + info.si_signo = SIGILL; + info.si_errno = 0; + info.si_code = ILL_ILLOPC; + info.si_addr = (void *)addr; + + force_sig_info(SIGILL, &info, current); die_if_kernel("unknown data abort code", regs, instr); - while (1); } void __bug(const char *file, int line, void *data) { - printk(KERN_CRIT"kernel BUG at %s:%d!\n", file, line); + printk(KERN_CRIT"kernel BUG at %s:%d!", file, line); if (data) - printk(KERN_CRIT"extra data = %p\n", data); + printk(KERN_CRIT" - extra data = %p", data); + printk("\n"); BUG(); } |