diff options
Diffstat (limited to 'arch/arm/kernel')
-rw-r--r-- | arch/arm/kernel/bios32.c | 5 | ||||
-rw-r--r-- | arch/arm/kernel/head-common.S | 90 | ||||
-rw-r--r-- | arch/arm/kernel/head-nommu.S | 3 | ||||
-rw-r--r-- | arch/arm/kernel/head.S | 9 | ||||
-rw-r--r-- | arch/arm/kernel/irq.c | 50 | ||||
-rw-r--r-- | arch/arm/kernel/module.c | 27 | ||||
-rw-r--r-- | arch/arm/kernel/ptrace.c | 383 | ||||
-rw-r--r-- | arch/arm/kernel/ptrace.h | 37 | ||||
-rw-r--r-- | arch/arm/kernel/return_address.c | 1 | ||||
-rw-r--r-- | arch/arm/kernel/setup.c | 39 | ||||
-rw-r--r-- | arch/arm/kernel/signal.c | 9 | ||||
-rw-r--r-- | arch/arm/kernel/traps.c | 4 |
12 files changed, 94 insertions, 563 deletions
diff --git a/arch/arm/kernel/bios32.c b/arch/arm/kernel/bios32.c index c6273a3bfc25..d86fcd44b220 100644 --- a/arch/arm/kernel/bios32.c +++ b/arch/arm/kernel/bios32.c | |||
@@ -583,6 +583,11 @@ void __init pci_common_init(struct hw_pci *hw) | |||
583 | * Assign resources. | 583 | * Assign resources. |
584 | */ | 584 | */ |
585 | pci_bus_assign_resources(bus); | 585 | pci_bus_assign_resources(bus); |
586 | |||
587 | /* | ||
588 | * Enable bridges | ||
589 | */ | ||
590 | pci_enable_bridges(bus); | ||
586 | } | 591 | } |
587 | 592 | ||
588 | /* | 593 | /* |
diff --git a/arch/arm/kernel/head-common.S b/arch/arm/kernel/head-common.S index 8f57515bbdb0..c84b57d27d07 100644 --- a/arch/arm/kernel/head-common.S +++ b/arch/arm/kernel/head-common.S | |||
@@ -25,83 +25,6 @@ | |||
25 | * machine ID for example). | 25 | * machine ID for example). |
26 | */ | 26 | */ |
27 | __HEAD | 27 | __HEAD |
28 | __error_a: | ||
29 | #ifdef CONFIG_DEBUG_LL | ||
30 | mov r4, r1 @ preserve machine ID | ||
31 | adr r0, str_a1 | ||
32 | bl printascii | ||
33 | mov r0, r4 | ||
34 | bl printhex8 | ||
35 | adr r0, str_a2 | ||
36 | bl printascii | ||
37 | adr r3, __lookup_machine_type_data | ||
38 | ldmia r3, {r4, r5, r6} @ get machine desc list | ||
39 | sub r4, r3, r4 @ get offset between virt&phys | ||
40 | add r5, r5, r4 @ convert virt addresses to | ||
41 | add r6, r6, r4 @ physical address space | ||
42 | 1: ldr r0, [r5, #MACHINFO_TYPE] @ get machine type | ||
43 | bl printhex8 | ||
44 | mov r0, #'\t' | ||
45 | bl printch | ||
46 | ldr r0, [r5, #MACHINFO_NAME] @ get machine name | ||
47 | add r0, r0, r4 | ||
48 | bl printascii | ||
49 | mov r0, #'\n' | ||
50 | bl printch | ||
51 | add r5, r5, #SIZEOF_MACHINE_DESC @ next machine_desc | ||
52 | cmp r5, r6 | ||
53 | blo 1b | ||
54 | adr r0, str_a3 | ||
55 | bl printascii | ||
56 | b __error | ||
57 | ENDPROC(__error_a) | ||
58 | |||
59 | str_a1: .asciz "\nError: unrecognized/unsupported machine ID (r1 = 0x" | ||
60 | str_a2: .asciz ").\n\nAvailable machine support:\n\nID (hex)\tNAME\n" | ||
61 | str_a3: .asciz "\nPlease check your kernel config and/or bootloader.\n" | ||
62 | .align | ||
63 | #else | ||
64 | b __error | ||
65 | #endif | ||
66 | |||
67 | /* | ||
68 | * Lookup machine architecture in the linker-build list of architectures. | ||
69 | * Note that we can't use the absolute addresses for the __arch_info | ||
70 | * lists since we aren't running with the MMU on (and therefore, we are | ||
71 | * not in the correct address space). We have to calculate the offset. | ||
72 | * | ||
73 | * r1 = machine architecture number | ||
74 | * Returns: | ||
75 | * r3, r4, r6 corrupted | ||
76 | * r5 = mach_info pointer in physical address space | ||
77 | */ | ||
78 | __lookup_machine_type: | ||
79 | adr r3, __lookup_machine_type_data | ||
80 | ldmia r3, {r4, r5, r6} | ||
81 | sub r3, r3, r4 @ get offset between virt&phys | ||
82 | add r5, r5, r3 @ convert virt addresses to | ||
83 | add r6, r6, r3 @ physical address space | ||
84 | 1: ldr r3, [r5, #MACHINFO_TYPE] @ get machine type | ||
85 | teq r3, r1 @ matches loader number? | ||
86 | beq 2f @ found | ||
87 | add r5, r5, #SIZEOF_MACHINE_DESC @ next machine_desc | ||
88 | cmp r5, r6 | ||
89 | blo 1b | ||
90 | mov r5, #0 @ unknown machine | ||
91 | 2: mov pc, lr | ||
92 | ENDPROC(__lookup_machine_type) | ||
93 | |||
94 | /* | ||
95 | * Look in arch/arm/kernel/arch.[ch] for information about the | ||
96 | * __arch_info structures. | ||
97 | */ | ||
98 | .align 2 | ||
99 | .type __lookup_machine_type_data, %object | ||
100 | __lookup_machine_type_data: | ||
101 | .long . | ||
102 | .long __arch_info_begin | ||
103 | .long __arch_info_end | ||
104 | .size __lookup_machine_type_data, . - __lookup_machine_type_data | ||
105 | 28 | ||
106 | /* Determine validity of the r2 atags pointer. The heuristic requires | 29 | /* Determine validity of the r2 atags pointer. The heuristic requires |
107 | * that the pointer be aligned, in the first 16k of physical RAM and | 30 | * that the pointer be aligned, in the first 16k of physical RAM and |
@@ -109,8 +32,6 @@ __lookup_machine_type_data: | |||
109 | * of this function may be more lenient with the physical address and | 32 | * of this function may be more lenient with the physical address and |
110 | * may also be able to move the ATAGS block if necessary. | 33 | * may also be able to move the ATAGS block if necessary. |
111 | * | 34 | * |
112 | * r8 = machinfo | ||
113 | * | ||
114 | * Returns: | 35 | * Returns: |
115 | * r2 either valid atags pointer, or zero | 36 | * r2 either valid atags pointer, or zero |
116 | * r5, r6 corrupted | 37 | * r5, r6 corrupted |
@@ -185,17 +106,6 @@ __mmap_switched_data: | |||
185 | .size __mmap_switched_data, . - __mmap_switched_data | 106 | .size __mmap_switched_data, . - __mmap_switched_data |
186 | 107 | ||
187 | /* | 108 | /* |
188 | * This provides a C-API version of __lookup_machine_type | ||
189 | */ | ||
190 | ENTRY(lookup_machine_type) | ||
191 | stmfd sp!, {r4 - r6, lr} | ||
192 | mov r1, r0 | ||
193 | bl __lookup_machine_type | ||
194 | mov r0, r5 | ||
195 | ldmfd sp!, {r4 - r6, pc} | ||
196 | ENDPROC(lookup_machine_type) | ||
197 | |||
198 | /* | ||
199 | * This provides a C-API version of __lookup_processor_type | 109 | * This provides a C-API version of __lookup_processor_type |
200 | */ | 110 | */ |
201 | ENTRY(lookup_processor_type) | 111 | ENTRY(lookup_processor_type) |
diff --git a/arch/arm/kernel/head-nommu.S b/arch/arm/kernel/head-nommu.S index 814ce1a73270..6b1e0ad9ec3b 100644 --- a/arch/arm/kernel/head-nommu.S +++ b/arch/arm/kernel/head-nommu.S | |||
@@ -44,9 +44,6 @@ ENTRY(stext) | |||
44 | bl __lookup_processor_type @ r5=procinfo r9=cpuid | 44 | bl __lookup_processor_type @ r5=procinfo r9=cpuid |
45 | movs r10, r5 @ invalid processor (r5=0)? | 45 | movs r10, r5 @ invalid processor (r5=0)? |
46 | beq __error_p @ yes, error 'p' | 46 | beq __error_p @ yes, error 'p' |
47 | bl __lookup_machine_type @ r5=machinfo | ||
48 | movs r8, r5 @ invalid machine (r5=0)? | ||
49 | beq __error_a @ yes, error 'a' | ||
50 | 47 | ||
51 | adr lr, BSYM(__after_proc_init) @ return (PIC) address | 48 | adr lr, BSYM(__after_proc_init) @ return (PIC) address |
52 | ARM( add pc, r10, #PROCINFO_INITFUNC ) | 49 | ARM( add pc, r10, #PROCINFO_INITFUNC ) |
diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S index f06ff9feb0db..60fe2795f4a3 100644 --- a/arch/arm/kernel/head.S +++ b/arch/arm/kernel/head.S | |||
@@ -87,14 +87,10 @@ ENTRY(stext) | |||
87 | movs r10, r5 @ invalid processor (r5=0)? | 87 | movs r10, r5 @ invalid processor (r5=0)? |
88 | THUMB( it eq ) @ force fixup-able long branch encoding | 88 | THUMB( it eq ) @ force fixup-able long branch encoding |
89 | beq __error_p @ yes, error 'p' | 89 | beq __error_p @ yes, error 'p' |
90 | bl __lookup_machine_type @ r5=machinfo | ||
91 | movs r8, r5 @ invalid machine (r5=0)? | ||
92 | THUMB( it eq ) @ force fixup-able long branch encoding | ||
93 | beq __error_a @ yes, error 'a' | ||
94 | 90 | ||
95 | /* | 91 | /* |
96 | * r1 = machine no, r2 = atags, | 92 | * r1 = machine no, r2 = atags, |
97 | * r8 = machinfo, r9 = cpuid, r10 = procinfo | 93 | * r9 = cpuid, r10 = procinfo |
98 | */ | 94 | */ |
99 | bl __vet_atags | 95 | bl __vet_atags |
100 | #ifdef CONFIG_SMP_ON_UP | 96 | #ifdef CONFIG_SMP_ON_UP |
@@ -105,7 +101,7 @@ ENTRY(stext) | |||
105 | /* | 101 | /* |
106 | * The following calls CPU specific code in a position independent | 102 | * The following calls CPU specific code in a position independent |
107 | * manner. See arch/arm/mm/proc-*.S for details. r10 = base of | 103 | * manner. See arch/arm/mm/proc-*.S for details. r10 = base of |
108 | * xxx_proc_info structure selected by __lookup_machine_type | 104 | * xxx_proc_info structure selected by __lookup_processor_type |
109 | * above. On return, the CPU will be ready for the MMU to be | 105 | * above. On return, the CPU will be ready for the MMU to be |
110 | * turned on, and r0 will hold the CPU control register value. | 106 | * turned on, and r0 will hold the CPU control register value. |
111 | */ | 107 | */ |
@@ -124,7 +120,6 @@ ENDPROC(stext) | |||
124 | * amount which are required to get the kernel running, which | 120 | * amount which are required to get the kernel running, which |
125 | * generally means mapping in the kernel code. | 121 | * generally means mapping in the kernel code. |
126 | * | 122 | * |
127 | * r8 = machinfo | ||
128 | * r9 = cpuid | 123 | * r9 = cpuid |
129 | * r10 = procinfo | 124 | * r10 = procinfo |
130 | * | 125 | * |
diff --git a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c index 28536e352deb..3535d3793e65 100644 --- a/arch/arm/kernel/irq.c +++ b/arch/arm/kernel/irq.c | |||
@@ -179,14 +179,21 @@ int __init arch_probe_nr_irqs(void) | |||
179 | 179 | ||
180 | #ifdef CONFIG_HOTPLUG_CPU | 180 | #ifdef CONFIG_HOTPLUG_CPU |
181 | 181 | ||
182 | static void route_irq(struct irq_desc *desc, unsigned int irq, unsigned int cpu) | 182 | static bool migrate_one_irq(struct irq_data *d) |
183 | { | 183 | { |
184 | pr_debug("IRQ%u: moving from cpu%u to cpu%u\n", irq, desc->irq_data.node, cpu); | 184 | unsigned int cpu = cpumask_any_and(d->affinity, cpu_online_mask); |
185 | bool ret = false; | ||
185 | 186 | ||
186 | raw_spin_lock_irq(&desc->lock); | 187 | if (cpu >= nr_cpu_ids) { |
187 | desc->irq_data.chip->irq_set_affinity(&desc->irq_data, | 188 | cpu = cpumask_any(cpu_online_mask); |
188 | cpumask_of(cpu), false); | 189 | ret = true; |
189 | raw_spin_unlock_irq(&desc->lock); | 190 | } |
191 | |||
192 | pr_debug("IRQ%u: moving from cpu%u to cpu%u\n", d->irq, d->node, cpu); | ||
193 | |||
194 | d->chip->irq_set_affinity(d, cpumask_of(cpu), true); | ||
195 | |||
196 | return ret; | ||
190 | } | 197 | } |
191 | 198 | ||
192 | /* | 199 | /* |
@@ -198,25 +205,30 @@ void migrate_irqs(void) | |||
198 | { | 205 | { |
199 | unsigned int i, cpu = smp_processor_id(); | 206 | unsigned int i, cpu = smp_processor_id(); |
200 | struct irq_desc *desc; | 207 | struct irq_desc *desc; |
208 | unsigned long flags; | ||
209 | |||
210 | local_irq_save(flags); | ||
201 | 211 | ||
202 | for_each_irq_desc(i, desc) { | 212 | for_each_irq_desc(i, desc) { |
203 | struct irq_data *d = &desc->irq_data; | 213 | struct irq_data *d = &desc->irq_data; |
214 | bool affinity_broken = false; | ||
204 | 215 | ||
205 | if (d->node == cpu) { | 216 | raw_spin_lock(&desc->lock); |
206 | unsigned int newcpu = cpumask_any_and(d->affinity, | 217 | do { |
207 | cpu_online_mask); | 218 | if (desc->action == NULL) |
208 | if (newcpu >= nr_cpu_ids) { | 219 | break; |
209 | if (printk_ratelimit()) | ||
210 | printk(KERN_INFO "IRQ%u no longer affine to CPU%u\n", | ||
211 | i, cpu); | ||
212 | 220 | ||
213 | cpumask_setall(d->affinity); | 221 | if (d->node != cpu) |
214 | newcpu = cpumask_any_and(d->affinity, | 222 | break; |
215 | cpu_online_mask); | ||
216 | } | ||
217 | 223 | ||
218 | route_irq(desc, i, newcpu); | 224 | affinity_broken = migrate_one_irq(d); |
219 | } | 225 | } while (0); |
226 | raw_spin_unlock(&desc->lock); | ||
227 | |||
228 | if (affinity_broken && printk_ratelimit()) | ||
229 | pr_warning("IRQ%u no longer affine to CPU%u\n", i, cpu); | ||
220 | } | 230 | } |
231 | |||
232 | local_irq_restore(flags); | ||
221 | } | 233 | } |
222 | #endif /* CONFIG_HOTPLUG_CPU */ | 234 | #endif /* CONFIG_HOTPLUG_CPU */ |
diff --git a/arch/arm/kernel/module.c b/arch/arm/kernel/module.c index 6d4105e6872f..6fcf22cf385c 100644 --- a/arch/arm/kernel/module.c +++ b/arch/arm/kernel/module.c | |||
@@ -76,6 +76,7 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex, | |||
76 | for (i = 0; i < relsec->sh_size / sizeof(Elf32_Rel); i++, rel++) { | 76 | for (i = 0; i < relsec->sh_size / sizeof(Elf32_Rel); i++, rel++) { |
77 | unsigned long loc; | 77 | unsigned long loc; |
78 | Elf32_Sym *sym; | 78 | Elf32_Sym *sym; |
79 | const char *symname; | ||
79 | s32 offset; | 80 | s32 offset; |
80 | #ifdef CONFIG_THUMB2_KERNEL | 81 | #ifdef CONFIG_THUMB2_KERNEL |
81 | u32 upper, lower, sign, j1, j2; | 82 | u32 upper, lower, sign, j1, j2; |
@@ -83,18 +84,18 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex, | |||
83 | 84 | ||
84 | offset = ELF32_R_SYM(rel->r_info); | 85 | offset = ELF32_R_SYM(rel->r_info); |
85 | if (offset < 0 || offset > (symsec->sh_size / sizeof(Elf32_Sym))) { | 86 | if (offset < 0 || offset > (symsec->sh_size / sizeof(Elf32_Sym))) { |
86 | printk(KERN_ERR "%s: bad relocation, section %d reloc %d\n", | 87 | pr_err("%s: section %u reloc %u: bad relocation sym offset\n", |
87 | module->name, relindex, i); | 88 | module->name, relindex, i); |
88 | return -ENOEXEC; | 89 | return -ENOEXEC; |
89 | } | 90 | } |
90 | 91 | ||
91 | sym = ((Elf32_Sym *)symsec->sh_addr) + offset; | 92 | sym = ((Elf32_Sym *)symsec->sh_addr) + offset; |
93 | symname = strtab + sym->st_name; | ||
92 | 94 | ||
93 | if (rel->r_offset < 0 || rel->r_offset > dstsec->sh_size - sizeof(u32)) { | 95 | if (rel->r_offset < 0 || rel->r_offset > dstsec->sh_size - sizeof(u32)) { |
94 | printk(KERN_ERR "%s: out of bounds relocation, " | 96 | pr_err("%s: section %u reloc %u sym '%s': out of bounds relocation, offset %d size %u\n", |
95 | "section %d reloc %d offset %d size %d\n", | 97 | module->name, relindex, i, symname, |
96 | module->name, relindex, i, rel->r_offset, | 98 | rel->r_offset, dstsec->sh_size); |
97 | dstsec->sh_size); | ||
98 | return -ENOEXEC; | 99 | return -ENOEXEC; |
99 | } | 100 | } |
100 | 101 | ||
@@ -120,10 +121,10 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex, | |||
120 | if (offset & 3 || | 121 | if (offset & 3 || |
121 | offset <= (s32)0xfe000000 || | 122 | offset <= (s32)0xfe000000 || |
122 | offset >= (s32)0x02000000) { | 123 | offset >= (s32)0x02000000) { |
123 | printk(KERN_ERR | 124 | pr_err("%s: section %u reloc %u sym '%s': relocation %u out of range (%#lx -> %#x)\n", |
124 | "%s: relocation out of range, section " | 125 | module->name, relindex, i, symname, |
125 | "%d reloc %d sym '%s'\n", module->name, | 126 | ELF32_R_TYPE(rel->r_info), loc, |
126 | relindex, i, strtab + sym->st_name); | 127 | sym->st_value); |
127 | return -ENOEXEC; | 128 | return -ENOEXEC; |
128 | } | 129 | } |
129 | 130 | ||
@@ -196,10 +197,10 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex, | |||
196 | if (!(offset & 1) || | 197 | if (!(offset & 1) || |
197 | offset <= (s32)0xff000000 || | 198 | offset <= (s32)0xff000000 || |
198 | offset >= (s32)0x01000000) { | 199 | offset >= (s32)0x01000000) { |
199 | printk(KERN_ERR | 200 | pr_err("%s: section %u reloc %u sym '%s': relocation %u out of range (%#lx -> %#x)\n", |
200 | "%s: relocation out of range, section " | 201 | module->name, relindex, i, symname, |
201 | "%d reloc %d sym '%s'\n", module->name, | 202 | ELF32_R_TYPE(rel->r_info), loc, |
202 | relindex, i, strtab + sym->st_name); | 203 | sym->st_value); |
203 | return -ENOEXEC; | 204 | return -ENOEXEC; |
204 | } | 205 | } |
205 | 206 | ||
diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c index b13e70f63d71..2bf27f364d09 100644 --- a/arch/arm/kernel/ptrace.c +++ b/arch/arm/kernel/ptrace.c | |||
@@ -26,8 +26,6 @@ | |||
26 | #include <asm/system.h> | 26 | #include <asm/system.h> |
27 | #include <asm/traps.h> | 27 | #include <asm/traps.h> |
28 | 28 | ||
29 | #include "ptrace.h" | ||
30 | |||
31 | #define REG_PC 15 | 29 | #define REG_PC 15 |
32 | #define REG_PSR 16 | 30 | #define REG_PSR 16 |
33 | /* | 31 | /* |
@@ -184,389 +182,12 @@ put_user_reg(struct task_struct *task, int offset, long data) | |||
184 | return ret; | 182 | return ret; |
185 | } | 183 | } |
186 | 184 | ||
187 | static inline int | ||
188 | read_u32(struct task_struct *task, unsigned long addr, u32 *res) | ||
189 | { | ||
190 | int ret; | ||
191 | |||
192 | ret = access_process_vm(task, addr, res, sizeof(*res), 0); | ||
193 | |||
194 | return ret == sizeof(*res) ? 0 : -EIO; | ||
195 | } | ||
196 | |||
197 | static inline int | ||
198 | read_instr(struct task_struct *task, unsigned long addr, u32 *res) | ||
199 | { | ||
200 | int ret; | ||
201 | |||
202 | if (addr & 1) { | ||
203 | u16 val; | ||
204 | ret = access_process_vm(task, addr & ~1, &val, sizeof(val), 0); | ||
205 | ret = ret == sizeof(val) ? 0 : -EIO; | ||
206 | *res = val; | ||
207 | } else { | ||
208 | u32 val; | ||
209 | ret = access_process_vm(task, addr & ~3, &val, sizeof(val), 0); | ||
210 | ret = ret == sizeof(val) ? 0 : -EIO; | ||
211 | *res = val; | ||
212 | } | ||
213 | return ret; | ||
214 | } | ||
215 | |||
216 | /* | ||
217 | * Get value of register `rn' (in the instruction) | ||
218 | */ | ||
219 | static unsigned long | ||
220 | ptrace_getrn(struct task_struct *child, unsigned long insn) | ||
221 | { | ||
222 | unsigned int reg = (insn >> 16) & 15; | ||
223 | unsigned long val; | ||
224 | |||
225 | val = get_user_reg(child, reg); | ||
226 | if (reg == 15) | ||
227 | val += 8; | ||
228 | |||
229 | return val; | ||
230 | } | ||
231 | |||
232 | /* | ||
233 | * Get value of operand 2 (in an ALU instruction) | ||
234 | */ | ||
235 | static unsigned long | ||
236 | ptrace_getaluop2(struct task_struct *child, unsigned long insn) | ||
237 | { | ||
238 | unsigned long val; | ||
239 | int shift; | ||
240 | int type; | ||
241 | |||
242 | if (insn & 1 << 25) { | ||
243 | val = insn & 255; | ||
244 | shift = (insn >> 8) & 15; | ||
245 | type = 3; | ||
246 | } else { | ||
247 | val = get_user_reg (child, insn & 15); | ||
248 | |||
249 | if (insn & (1 << 4)) | ||
250 | shift = (int)get_user_reg (child, (insn >> 8) & 15); | ||
251 | else | ||
252 | shift = (insn >> 7) & 31; | ||
253 | |||
254 | type = (insn >> 5) & 3; | ||
255 | } | ||
256 | |||
257 | switch (type) { | ||
258 | case 0: val <<= shift; break; | ||
259 | case 1: val >>= shift; break; | ||
260 | case 2: | ||
261 | val = (((signed long)val) >> shift); | ||
262 | break; | ||
263 | case 3: | ||
264 | val = (val >> shift) | (val << (32 - shift)); | ||
265 | break; | ||
266 | } | ||
267 | return val; | ||
268 | } | ||
269 | |||
270 | /* | ||
271 | * Get value of operand 2 (in a LDR instruction) | ||
272 | */ | ||
273 | static unsigned long | ||
274 | ptrace_getldrop2(struct task_struct *child, unsigned long insn) | ||
275 | { | ||
276 | unsigned long val; | ||
277 | int shift; | ||
278 | int type; | ||
279 | |||
280 | val = get_user_reg(child, insn & 15); | ||
281 | shift = (insn >> 7) & 31; | ||
282 | type = (insn >> 5) & 3; | ||
283 | |||
284 | switch (type) { | ||
285 | case 0: val <<= shift; break; | ||
286 | case 1: val >>= shift; break; | ||
287 | case 2: | ||
288 | val = (((signed long)val) >> shift); | ||
289 | break; | ||
290 | case 3: | ||
291 | val = (val >> shift) | (val << (32 - shift)); | ||
292 | break; | ||
293 | } | ||
294 | return val; | ||
295 | } | ||
296 | |||
297 | #define OP_MASK 0x01e00000 | ||
298 | #define OP_AND 0x00000000 | ||
299 | #define OP_EOR 0x00200000 | ||
300 | #define OP_SUB 0x00400000 | ||
301 | #define OP_RSB 0x00600000 | ||
302 | #define OP_ADD 0x00800000 | ||
303 | #define OP_ADC 0x00a00000 | ||
304 | #define OP_SBC 0x00c00000 | ||
305 | #define OP_RSC 0x00e00000 | ||
306 | #define OP_ORR 0x01800000 | ||
307 | #define OP_MOV 0x01a00000 | ||
308 | #define OP_BIC 0x01c00000 | ||
309 | #define OP_MVN 0x01e00000 | ||
310 | |||
311 | static unsigned long | ||
312 | get_branch_address(struct task_struct *child, unsigned long pc, unsigned long insn) | ||
313 | { | ||
314 | u32 alt = 0; | ||
315 | |||
316 | switch (insn & 0x0e000000) { | ||
317 | case 0x00000000: | ||
318 | case 0x02000000: { | ||
319 | /* | ||
320 | * data processing | ||
321 | */ | ||
322 | long aluop1, aluop2, ccbit; | ||
323 | |||
324 | if ((insn & 0x0fffffd0) == 0x012fff10) { | ||
325 | /* | ||
326 | * bx or blx | ||
327 | */ | ||
328 | alt = get_user_reg(child, insn & 15); | ||
329 | break; | ||
330 | } | ||
331 | |||
332 | |||
333 | if ((insn & 0xf000) != 0xf000) | ||
334 | break; | ||
335 | |||
336 | aluop1 = ptrace_getrn(child, insn); | ||
337 | aluop2 = ptrace_getaluop2(child, insn); | ||
338 | ccbit = get_user_reg(child, REG_PSR) & PSR_C_BIT ? 1 : 0; | ||
339 | |||
340 | switch (insn & OP_MASK) { | ||
341 | case OP_AND: alt = aluop1 & aluop2; break; | ||
342 | case OP_EOR: alt = aluop1 ^ aluop2; break; | ||
343 | case OP_SUB: alt = aluop1 - aluop2; break; | ||
344 | case OP_RSB: alt = aluop2 - aluop1; break; | ||
345 | case OP_ADD: alt = aluop1 + aluop2; break; | ||
346 | case OP_ADC: alt = aluop1 + aluop2 + ccbit; break; | ||
347 | case OP_SBC: alt = aluop1 - aluop2 + ccbit; break; | ||
348 | case OP_RSC: alt = aluop2 - aluop1 + ccbit; break; | ||
349 | case OP_ORR: alt = aluop1 | aluop2; break; | ||
350 | case OP_MOV: alt = aluop2; break; | ||
351 | case OP_BIC: alt = aluop1 & ~aluop2; break; | ||
352 | case OP_MVN: alt = ~aluop2; break; | ||
353 | } | ||
354 | break; | ||
355 | } | ||
356 | |||
357 | case 0x04000000: | ||
358 | case 0x06000000: | ||
359 | /* | ||
360 | * ldr | ||
361 | */ | ||
362 | if ((insn & 0x0010f000) == 0x0010f000) { | ||
363 | unsigned long base; | ||
364 | |||
365 | base = ptrace_getrn(child, insn); | ||
366 | if (insn & 1 << 24) { | ||
367 | long aluop2; | ||
368 | |||
369 | if (insn & 0x02000000) | ||
370 | aluop2 = ptrace_getldrop2(child, insn); | ||
371 | else | ||
372 | aluop2 = insn & 0xfff; | ||
373 | |||
374 | if (insn & 1 << 23) | ||
375 | base += aluop2; | ||
376 | else | ||
377 | base -= aluop2; | ||
378 | } | ||
379 | read_u32(child, base, &alt); | ||
380 | } | ||
381 | break; | ||
382 | |||
383 | case 0x08000000: | ||
384 | /* | ||
385 | * ldm | ||
386 | */ | ||
387 | if ((insn & 0x00108000) == 0x00108000) { | ||
388 | unsigned long base; | ||
389 | unsigned int nr_regs; | ||
390 | |||
391 | if (insn & (1 << 23)) { | ||
392 | nr_regs = hweight16(insn & 65535) << 2; | ||
393 | |||
394 | if (!(insn & (1 << 24))) | ||
395 | nr_regs -= 4; | ||
396 | } else { | ||
397 | if (insn & (1 << 24)) | ||
398 | nr_regs = -4; | ||
399 | else | ||
400 | nr_regs = 0; | ||
401 | } | ||
402 | |||
403 | base = ptrace_getrn(child, insn); | ||
404 | |||
405 | read_u32(child, base + nr_regs, &alt); | ||
406 | break; | ||
407 | } | ||
408 | break; | ||
409 | |||
410 | case 0x0a000000: { | ||
411 | /* | ||
412 | * bl or b | ||
413 | */ | ||
414 | signed long displ; | ||
415 | /* It's a branch/branch link: instead of trying to | ||
416 | * figure out whether the branch will be taken or not, | ||
417 | * we'll put a breakpoint at both locations. This is | ||
418 | * simpler, more reliable, and probably not a whole lot | ||
419 | * slower than the alternative approach of emulating the | ||
420 | * branch. | ||
421 | */ | ||
422 | displ = (insn & 0x00ffffff) << 8; | ||
423 | displ = (displ >> 6) + 8; | ||
424 | if (displ != 0 && displ != 4) | ||
425 | alt = pc + displ; | ||
426 | } | ||
427 | break; | ||
428 | } | ||
429 | |||
430 | return alt; | ||
431 | } | ||
432 | |||
433 | static int | ||
434 | swap_insn(struct task_struct *task, unsigned long addr, | ||
435 | void *old_insn, void *new_insn, int size) | ||
436 | { | ||
437 | int ret; | ||
438 | |||
439 | ret = access_process_vm(task, addr, old_insn, size, 0); | ||
440 | if (ret == size) | ||
441 | ret = access_process_vm(task, addr, new_insn, size, 1); | ||
442 | return ret; | ||
443 | } | ||
444 | |||
445 | static void | ||
446 | add_breakpoint(struct task_struct *task, struct debug_info *dbg, unsigned long addr) | ||
447 | { | ||
448 | int nr = dbg->nsaved; | ||
449 | |||
450 | if (nr < 2) { | ||
451 | u32 new_insn = BREAKINST_ARM; | ||
452 | int res; | ||
453 | |||
454 | res = swap_insn(task, addr, &dbg->bp[nr].insn, &new_insn, 4); | ||
455 | |||
456 | if (res == 4) { | ||
457 | dbg->bp[nr].address = addr; | ||
458 | dbg->nsaved += 1; | ||
459 | } | ||
460 | } else | ||
461 | printk(KERN_ERR "ptrace: too many breakpoints\n"); | ||
462 | } | ||
463 | |||
464 | /* | ||
465 | * Clear one breakpoint in the user program. We copy what the hardware | ||
466 | * does and use bit 0 of the address to indicate whether this is a Thumb | ||
467 | * breakpoint or an ARM breakpoint. | ||
468 | */ | ||
469 | static void clear_breakpoint(struct task_struct *task, struct debug_entry *bp) | ||
470 | { | ||
471 | unsigned long addr = bp->address; | ||
472 | union debug_insn old_insn; | ||
473 | int ret; | ||
474 | |||
475 | if (addr & 1) { | ||
476 | ret = swap_insn(task, addr & ~1, &old_insn.thumb, | ||
477 | &bp->insn.thumb, 2); | ||
478 | |||
479 | if (ret != 2 || old_insn.thumb != BREAKINST_THUMB) | ||
480 | printk(KERN_ERR "%s:%d: corrupted Thumb breakpoint at " | ||
481 | "0x%08lx (0x%04x)\n", task->comm, | ||
482 | task_pid_nr(task), addr, old_insn.thumb); | ||
483 | } else { | ||
484 | ret = swap_insn(task, addr & ~3, &old_insn.arm, | ||
485 | &bp->insn.arm, 4); | ||
486 | |||
487 | if (ret != 4 || old_insn.arm != BREAKINST_ARM) | ||
488 | printk(KERN_ERR "%s:%d: corrupted ARM breakpoint at " | ||
489 | "0x%08lx (0x%08x)\n", task->comm, | ||
490 | task_pid_nr(task), addr, old_insn.arm); | ||
491 | } | ||
492 | } | ||
493 | |||
494 | void ptrace_set_bpt(struct task_struct *child) | ||
495 | { | ||
496 | struct pt_regs *regs; | ||
497 | unsigned long pc; | ||
498 | u32 insn; | ||
499 | int res; | ||
500 | |||
501 | regs = task_pt_regs(child); | ||
502 | pc = instruction_pointer(regs); | ||
503 | |||
504 | if (thumb_mode(regs)) { | ||
505 | printk(KERN_WARNING "ptrace: can't handle thumb mode\n"); | ||
506 | return; | ||
507 | } | ||
508 | |||
509 | res = read_instr(child, pc, &insn); | ||
510 | if (!res) { | ||
511 | struct debug_info *dbg = &child->thread.debug; | ||
512 | unsigned long alt; | ||
513 | |||
514 | dbg->nsaved = 0; | ||
515 | |||
516 | alt = get_branch_address(child, pc, insn); | ||
517 | if (alt) | ||
518 | add_breakpoint(child, dbg, alt); | ||
519 | |||
520 | /* | ||
521 | * Note that we ignore the result of setting the above | ||
522 | * breakpoint since it may fail. When it does, this is | ||
523 | * not so much an error, but a forewarning that we may | ||
524 | * be receiving a prefetch abort shortly. | ||
525 | * | ||
526 | * If we don't set this breakpoint here, then we can | ||
527 | * lose control of the thread during single stepping. | ||
528 | */ | ||
529 | if (!alt || predicate(insn) != PREDICATE_ALWAYS) | ||
530 | add_breakpoint(child, dbg, pc + 4); | ||
531 | } | ||
532 | } | ||
533 | |||
534 | /* | ||
535 | * Ensure no single-step breakpoint is pending. Returns non-zero | ||
536 | * value if child was being single-stepped. | ||
537 | */ | ||
538 | void ptrace_cancel_bpt(struct task_struct *child) | ||
539 | { | ||
540 | int i, nsaved = child->thread.debug.nsaved; | ||
541 | |||
542 | child->thread.debug.nsaved = 0; | ||
543 | |||
544 | if (nsaved > 2) { | ||
545 | printk("ptrace_cancel_bpt: bogus nsaved: %d!\n", nsaved); | ||
546 | nsaved = 2; | ||
547 | } | ||
548 | |||
549 | for (i = 0; i < nsaved; i++) | ||
550 | clear_breakpoint(child, &child->thread.debug.bp[i]); | ||
551 | } | ||
552 | |||
553 | void user_disable_single_step(struct task_struct *task) | ||
554 | { | ||
555 | task->ptrace &= ~PT_SINGLESTEP; | ||
556 | ptrace_cancel_bpt(task); | ||
557 | } | ||
558 | |||
559 | void user_enable_single_step(struct task_struct *task) | ||
560 | { | ||
561 | task->ptrace |= PT_SINGLESTEP; | ||
562 | } | ||
563 | |||
564 | /* | 185 | /* |
565 | * Called by kernel/ptrace.c when detaching.. | 186 | * Called by kernel/ptrace.c when detaching.. |
566 | */ | 187 | */ |
567 | void ptrace_disable(struct task_struct *child) | 188 | void ptrace_disable(struct task_struct *child) |
568 | { | 189 | { |
569 | user_disable_single_step(child); | 190 | /* Nothing to do. */ |
570 | } | 191 | } |
571 | 192 | ||
572 | /* | 193 | /* |
@@ -576,8 +197,6 @@ void ptrace_break(struct task_struct *tsk, struct pt_regs *regs) | |||
576 | { | 197 | { |
577 | siginfo_t info; | 198 | siginfo_t info; |
578 | 199 | ||
579 | ptrace_cancel_bpt(tsk); | ||
580 | |||
581 | info.si_signo = SIGTRAP; | 200 | info.si_signo = SIGTRAP; |
582 | info.si_errno = 0; | 201 | info.si_errno = 0; |
583 | info.si_code = TRAP_BRKPT; | 202 | info.si_code = TRAP_BRKPT; |
diff --git a/arch/arm/kernel/ptrace.h b/arch/arm/kernel/ptrace.h deleted file mode 100644 index 3926605b82ea..000000000000 --- a/arch/arm/kernel/ptrace.h +++ /dev/null | |||
@@ -1,37 +0,0 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/kernel/ptrace.h | ||
3 | * | ||
4 | * Copyright (C) 2000-2003 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 | #include <linux/ptrace.h> | ||
11 | |||
12 | extern void ptrace_cancel_bpt(struct task_struct *); | ||
13 | extern void ptrace_set_bpt(struct task_struct *); | ||
14 | extern void ptrace_break(struct task_struct *, struct pt_regs *); | ||
15 | |||
16 | /* | ||
17 | * Send SIGTRAP if we're single-stepping | ||
18 | */ | ||
19 | static inline void single_step_trap(struct task_struct *task) | ||
20 | { | ||
21 | if (task->ptrace & PT_SINGLESTEP) { | ||
22 | ptrace_cancel_bpt(task); | ||
23 | send_sig(SIGTRAP, task, 1); | ||
24 | } | ||
25 | } | ||
26 | |||
27 | static inline void single_step_clear(struct task_struct *task) | ||
28 | { | ||
29 | if (task->ptrace & PT_SINGLESTEP) | ||
30 | ptrace_cancel_bpt(task); | ||
31 | } | ||
32 | |||
33 | static inline void single_step_set(struct task_struct *task) | ||
34 | { | ||
35 | if (task->ptrace & PT_SINGLESTEP) | ||
36 | ptrace_set_bpt(task); | ||
37 | } | ||
diff --git a/arch/arm/kernel/return_address.c b/arch/arm/kernel/return_address.c index df246da4ceca..0b13a72f855d 100644 --- a/arch/arm/kernel/return_address.c +++ b/arch/arm/kernel/return_address.c | |||
@@ -9,6 +9,7 @@ | |||
9 | * the Free Software Foundation. | 9 | * the Free Software Foundation. |
10 | */ | 10 | */ |
11 | #include <linux/module.h> | 11 | #include <linux/module.h> |
12 | #include <linux/ftrace.h> | ||
12 | 13 | ||
13 | #if defined(CONFIG_FRAME_POINTER) && !defined(CONFIG_ARM_UNWIND) | 14 | #if defined(CONFIG_FRAME_POINTER) && !defined(CONFIG_ARM_UNWIND) |
14 | #include <linux/sched.h> | 15 | #include <linux/sched.h> |
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c index 5ea4fb718b97..db2382853450 100644 --- a/arch/arm/kernel/setup.c +++ b/arch/arm/kernel/setup.c | |||
@@ -308,7 +308,44 @@ static void __init cacheid_init(void) | |||
308 | * already provide the required functionality. | 308 | * already provide the required functionality. |
309 | */ | 309 | */ |
310 | extern struct proc_info_list *lookup_processor_type(unsigned int); | 310 | extern struct proc_info_list *lookup_processor_type(unsigned int); |
311 | extern struct machine_desc *lookup_machine_type(unsigned int); | 311 | |
312 | static void __init early_print(const char *str, ...) | ||
313 | { | ||
314 | extern void printascii(const char *); | ||
315 | char buf[256]; | ||
316 | va_list ap; | ||
317 | |||
318 | va_start(ap, str); | ||
319 | vsnprintf(buf, sizeof(buf), str, ap); | ||
320 | va_end(ap); | ||
321 | |||
322 | #ifdef CONFIG_DEBUG_LL | ||
323 | printascii(buf); | ||
324 | #endif | ||
325 | printk("%s", buf); | ||
326 | } | ||
327 | |||
328 | static struct machine_desc * __init lookup_machine_type(unsigned int type) | ||
329 | { | ||
330 | extern struct machine_desc __arch_info_begin[], __arch_info_end[]; | ||
331 | struct machine_desc *p; | ||
332 | |||
333 | for (p = __arch_info_begin; p < __arch_info_end; p++) | ||
334 | if (type == p->nr) | ||
335 | return p; | ||
336 | |||
337 | early_print("\n" | ||
338 | "Error: unrecognized/unsupported machine ID (r1 = 0x%08x).\n\n" | ||
339 | "Available machine support:\n\nID (hex)\tNAME\n", type); | ||
340 | |||
341 | for (p = __arch_info_begin; p < __arch_info_end; p++) | ||
342 | early_print("%08x\t%s\n", p->nr, p->name); | ||
343 | |||
344 | early_print("\nPlease check your kernel config and/or bootloader.\n"); | ||
345 | |||
346 | while (true) | ||
347 | /* can't use cpu_relax() here as it may require MMU setup */; | ||
348 | } | ||
312 | 349 | ||
313 | static void __init feat_v6_fixup(void) | 350 | static void __init feat_v6_fixup(void) |
314 | { | 351 | { |
diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c index abaf8445ce25..cb8398317644 100644 --- a/arch/arm/kernel/signal.c +++ b/arch/arm/kernel/signal.c | |||
@@ -20,7 +20,6 @@ | |||
20 | #include <asm/unistd.h> | 20 | #include <asm/unistd.h> |
21 | #include <asm/vfp.h> | 21 | #include <asm/vfp.h> |
22 | 22 | ||
23 | #include "ptrace.h" | ||
24 | #include "signal.h" | 23 | #include "signal.h" |
25 | 24 | ||
26 | #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) | 25 | #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) |
@@ -348,8 +347,6 @@ asmlinkage int sys_sigreturn(struct pt_regs *regs) | |||
348 | if (restore_sigframe(regs, frame)) | 347 | if (restore_sigframe(regs, frame)) |
349 | goto badframe; | 348 | goto badframe; |
350 | 349 | ||
351 | single_step_trap(current); | ||
352 | |||
353 | return regs->ARM_r0; | 350 | return regs->ARM_r0; |
354 | 351 | ||
355 | badframe: | 352 | badframe: |
@@ -383,8 +380,6 @@ asmlinkage int sys_rt_sigreturn(struct pt_regs *regs) | |||
383 | if (do_sigaltstack(&frame->sig.uc.uc_stack, NULL, regs->ARM_sp) == -EFAULT) | 380 | if (do_sigaltstack(&frame->sig.uc.uc_stack, NULL, regs->ARM_sp) == -EFAULT) |
384 | goto badframe; | 381 | goto badframe; |
385 | 382 | ||
386 | single_step_trap(current); | ||
387 | |||
388 | return regs->ARM_r0; | 383 | return regs->ARM_r0; |
389 | 384 | ||
390 | badframe: | 385 | badframe: |
@@ -706,8 +701,6 @@ static void do_signal(struct pt_regs *regs, int syscall) | |||
706 | if (try_to_freeze()) | 701 | if (try_to_freeze()) |
707 | goto no_signal; | 702 | goto no_signal; |
708 | 703 | ||
709 | single_step_clear(current); | ||
710 | |||
711 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); | 704 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); |
712 | if (signr > 0) { | 705 | if (signr > 0) { |
713 | sigset_t *oldset; | 706 | sigset_t *oldset; |
@@ -726,7 +719,6 @@ static void do_signal(struct pt_regs *regs, int syscall) | |||
726 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) | 719 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) |
727 | clear_thread_flag(TIF_RESTORE_SIGMASK); | 720 | clear_thread_flag(TIF_RESTORE_SIGMASK); |
728 | } | 721 | } |
729 | single_step_set(current); | ||
730 | return; | 722 | return; |
731 | } | 723 | } |
732 | 724 | ||
@@ -772,7 +764,6 @@ static void do_signal(struct pt_regs *regs, int syscall) | |||
772 | sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); | 764 | sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); |
773 | } | 765 | } |
774 | } | 766 | } |
775 | single_step_set(current); | ||
776 | } | 767 | } |
777 | 768 | ||
778 | asmlinkage void | 769 | asmlinkage void |
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index ee57640ba2bb..21ac43f1c2d0 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <linux/kexec.h> | 23 | #include <linux/kexec.h> |
24 | #include <linux/delay.h> | 24 | #include <linux/delay.h> |
25 | #include <linux/init.h> | 25 | #include <linux/init.h> |
26 | #include <linux/sched.h> | ||
26 | 27 | ||
27 | #include <asm/atomic.h> | 28 | #include <asm/atomic.h> |
28 | #include <asm/cacheflush.h> | 29 | #include <asm/cacheflush.h> |
@@ -32,7 +33,6 @@ | |||
32 | #include <asm/unwind.h> | 33 | #include <asm/unwind.h> |
33 | #include <asm/tls.h> | 34 | #include <asm/tls.h> |
34 | 35 | ||
35 | #include "ptrace.h" | ||
36 | #include "signal.h" | 36 | #include "signal.h" |
37 | 37 | ||
38 | static const char *handler[]= { "prefetch abort", "data abort", "address exception", "interrupt" }; | 38 | static const char *handler[]= { "prefetch abort", "data abort", "address exception", "interrupt" }; |
@@ -256,7 +256,7 @@ static int __die(const char *str, int err, struct thread_info *thread, struct pt | |||
256 | return ret; | 256 | return ret; |
257 | } | 257 | } |
258 | 258 | ||
259 | DEFINE_SPINLOCK(die_lock); | 259 | static DEFINE_SPINLOCK(die_lock); |
260 | 260 | ||
261 | /* | 261 | /* |
262 | * This function is protected against re-entrancy. | 262 | * This function is protected against re-entrancy. |