aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/kernel')
-rw-r--r--arch/arm/kernel/bios32.c5
-rw-r--r--arch/arm/kernel/head-common.S90
-rw-r--r--arch/arm/kernel/head-nommu.S3
-rw-r--r--arch/arm/kernel/head.S9
-rw-r--r--arch/arm/kernel/irq.c50
-rw-r--r--arch/arm/kernel/module.c27
-rw-r--r--arch/arm/kernel/ptrace.c383
-rw-r--r--arch/arm/kernel/ptrace.h37
-rw-r--r--arch/arm/kernel/return_address.c1
-rw-r--r--arch/arm/kernel/setup.c39
-rw-r--r--arch/arm/kernel/signal.c9
-rw-r--r--arch/arm/kernel/traps.c4
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
421: 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
57ENDPROC(__error_a)
58
59str_a1: .asciz "\nError: unrecognized/unsupported machine ID (r1 = 0x"
60str_a2: .asciz ").\n\nAvailable machine support:\n\nID (hex)\tNAME\n"
61str_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
841: 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
912: mov pc, lr
92ENDPROC(__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 */
190ENTRY(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}
196ENDPROC(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 */
201ENTRY(lookup_processor_type) 111ENTRY(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
182static void route_irq(struct irq_desc *desc, unsigned int irq, unsigned int cpu) 182static 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
187static inline int
188read_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
197static inline int
198read_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 */
219static unsigned long
220ptrace_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 */
235static unsigned long
236ptrace_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 */
273static unsigned long
274ptrace_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
311static unsigned long
312get_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
433static int
434swap_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
445static void
446add_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 */
469static 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
494void 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 */
538void 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
553void user_disable_single_step(struct task_struct *task)
554{
555 task->ptrace &= ~PT_SINGLESTEP;
556 ptrace_cancel_bpt(task);
557}
558
559void 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 */
567void ptrace_disable(struct task_struct *child) 188void 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
12extern void ptrace_cancel_bpt(struct task_struct *);
13extern void ptrace_set_bpt(struct task_struct *);
14extern void ptrace_break(struct task_struct *, struct pt_regs *);
15
16/*
17 * Send SIGTRAP if we're single-stepping
18 */
19static 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
27static inline void single_step_clear(struct task_struct *task)
28{
29 if (task->ptrace & PT_SINGLESTEP)
30 ptrace_cancel_bpt(task);
31}
32
33static 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 */
310extern struct proc_info_list *lookup_processor_type(unsigned int); 310extern struct proc_info_list *lookup_processor_type(unsigned int);
311extern struct machine_desc *lookup_machine_type(unsigned int); 311
312static 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
328static 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
313static void __init feat_v6_fixup(void) 350static 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
355badframe: 352badframe:
@@ -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
390badframe: 385badframe:
@@ -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, &current->saved_sigmask, NULL); 764 sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
773 } 765 }
774 } 766 }
775 single_step_set(current);
776} 767}
777 768
778asmlinkage void 769asmlinkage 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
38static const char *handler[]= { "prefetch abort", "data abort", "address exception", "interrupt" }; 38static 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
259DEFINE_SPINLOCK(die_lock); 259static DEFINE_SPINLOCK(die_lock);
260 260
261/* 261/*
262 * This function is protected against re-entrancy. 262 * This function is protected against re-entrancy.