diff options
Diffstat (limited to 'arch/arm/kernel')
-rw-r--r-- | arch/arm/kernel/Makefile | 1 | ||||
-rw-r--r-- | arch/arm/kernel/armksyms.c | 22 | ||||
-rw-r--r-- | arch/arm/kernel/asm-offsets.c | 11 | ||||
-rw-r--r-- | arch/arm/kernel/bios32.c | 5 | ||||
-rw-r--r-- | arch/arm/kernel/debug.S | 2 | ||||
-rw-r--r-- | arch/arm/kernel/entry-armv.S | 3 | ||||
-rw-r--r-- | arch/arm/kernel/entry-header.S | 14 | ||||
-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 | 191 | ||||
-rw-r--r-- | arch/arm/kernel/irq.c | 50 | ||||
-rw-r--r-- | arch/arm/kernel/module.c | 35 | ||||
-rw-r--r-- | arch/arm/kernel/perf_event_v6.c | 4 | ||||
-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 | 68 | ||||
-rw-r--r-- | arch/arm/kernel/signal.c | 9 | ||||
-rw-r--r-- | arch/arm/kernel/sleep.S | 134 | ||||
-rw-r--r-- | arch/arm/kernel/smp_scu.c | 23 | ||||
-rw-r--r-- | arch/arm/kernel/tcm.c | 2 | ||||
-rw-r--r-- | arch/arm/kernel/traps.c | 4 | ||||
-rw-r--r-- | arch/arm/kernel/vmlinux.lds.S | 4 |
23 files changed, 472 insertions, 624 deletions
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile index 185ee822c935..74554f1742d7 100644 --- a/arch/arm/kernel/Makefile +++ b/arch/arm/kernel/Makefile | |||
@@ -29,6 +29,7 @@ obj-$(CONFIG_MODULES) += armksyms.o module.o | |||
29 | obj-$(CONFIG_ARTHUR) += arthur.o | 29 | obj-$(CONFIG_ARTHUR) += arthur.o |
30 | obj-$(CONFIG_ISA_DMA) += dma-isa.o | 30 | obj-$(CONFIG_ISA_DMA) += dma-isa.o |
31 | obj-$(CONFIG_PCI) += bios32.o isa.o | 31 | obj-$(CONFIG_PCI) += bios32.o isa.o |
32 | obj-$(CONFIG_PM) += sleep.o | ||
32 | obj-$(CONFIG_HAVE_SCHED_CLOCK) += sched_clock.o | 33 | obj-$(CONFIG_HAVE_SCHED_CLOCK) += sched_clock.o |
33 | obj-$(CONFIG_SMP) += smp.o smp_tlb.o | 34 | obj-$(CONFIG_SMP) += smp.o smp_tlb.o |
34 | obj-$(CONFIG_HAVE_ARM_SCU) += smp_scu.o | 35 | obj-$(CONFIG_HAVE_ARM_SCU) += smp_scu.o |
diff --git a/arch/arm/kernel/armksyms.c b/arch/arm/kernel/armksyms.c index e5e1e5387678..acca35aebe28 100644 --- a/arch/arm/kernel/armksyms.c +++ b/arch/arm/kernel/armksyms.c | |||
@@ -140,24 +140,18 @@ EXPORT_SYMBOL(__aeabi_ulcmp); | |||
140 | #endif | 140 | #endif |
141 | 141 | ||
142 | /* bitops */ | 142 | /* bitops */ |
143 | EXPORT_SYMBOL(_set_bit_le); | 143 | EXPORT_SYMBOL(_set_bit); |
144 | EXPORT_SYMBOL(_test_and_set_bit_le); | 144 | EXPORT_SYMBOL(_test_and_set_bit); |
145 | EXPORT_SYMBOL(_clear_bit_le); | 145 | EXPORT_SYMBOL(_clear_bit); |
146 | EXPORT_SYMBOL(_test_and_clear_bit_le); | 146 | EXPORT_SYMBOL(_test_and_clear_bit); |
147 | EXPORT_SYMBOL(_change_bit_le); | 147 | EXPORT_SYMBOL(_change_bit); |
148 | EXPORT_SYMBOL(_test_and_change_bit_le); | 148 | EXPORT_SYMBOL(_test_and_change_bit); |
149 | EXPORT_SYMBOL(_find_first_zero_bit_le); | 149 | EXPORT_SYMBOL(_find_first_zero_bit_le); |
150 | EXPORT_SYMBOL(_find_next_zero_bit_le); | 150 | EXPORT_SYMBOL(_find_next_zero_bit_le); |
151 | EXPORT_SYMBOL(_find_first_bit_le); | 151 | EXPORT_SYMBOL(_find_first_bit_le); |
152 | EXPORT_SYMBOL(_find_next_bit_le); | 152 | EXPORT_SYMBOL(_find_next_bit_le); |
153 | 153 | ||
154 | #ifdef __ARMEB__ | 154 | #ifdef __ARMEB__ |
155 | EXPORT_SYMBOL(_set_bit_be); | ||
156 | EXPORT_SYMBOL(_test_and_set_bit_be); | ||
157 | EXPORT_SYMBOL(_clear_bit_be); | ||
158 | EXPORT_SYMBOL(_test_and_clear_bit_be); | ||
159 | EXPORT_SYMBOL(_change_bit_be); | ||
160 | EXPORT_SYMBOL(_test_and_change_bit_be); | ||
161 | EXPORT_SYMBOL(_find_first_zero_bit_be); | 155 | EXPORT_SYMBOL(_find_first_zero_bit_be); |
162 | EXPORT_SYMBOL(_find_next_zero_bit_be); | 156 | EXPORT_SYMBOL(_find_next_zero_bit_be); |
163 | EXPORT_SYMBOL(_find_first_bit_be); | 157 | EXPORT_SYMBOL(_find_first_bit_be); |
@@ -170,3 +164,7 @@ EXPORT_SYMBOL(mcount); | |||
170 | #endif | 164 | #endif |
171 | EXPORT_SYMBOL(__gnu_mcount_nc); | 165 | EXPORT_SYMBOL(__gnu_mcount_nc); |
172 | #endif | 166 | #endif |
167 | |||
168 | #ifdef CONFIG_ARM_PATCH_PHYS_VIRT | ||
169 | EXPORT_SYMBOL(__pv_phys_offset); | ||
170 | #endif | ||
diff --git a/arch/arm/kernel/asm-offsets.c b/arch/arm/kernel/asm-offsets.c index 82da66172132..927522cfc12e 100644 --- a/arch/arm/kernel/asm-offsets.c +++ b/arch/arm/kernel/asm-offsets.c | |||
@@ -13,6 +13,9 @@ | |||
13 | #include <linux/sched.h> | 13 | #include <linux/sched.h> |
14 | #include <linux/mm.h> | 14 | #include <linux/mm.h> |
15 | #include <linux/dma-mapping.h> | 15 | #include <linux/dma-mapping.h> |
16 | #include <asm/cacheflush.h> | ||
17 | #include <asm/glue-df.h> | ||
18 | #include <asm/glue-pf.h> | ||
16 | #include <asm/mach/arch.h> | 19 | #include <asm/mach/arch.h> |
17 | #include <asm/thread_info.h> | 20 | #include <asm/thread_info.h> |
18 | #include <asm/memory.h> | 21 | #include <asm/memory.h> |
@@ -114,6 +117,14 @@ int main(void) | |||
114 | #ifdef MULTI_PABORT | 117 | #ifdef MULTI_PABORT |
115 | DEFINE(PROCESSOR_PABT_FUNC, offsetof(struct processor, _prefetch_abort)); | 118 | DEFINE(PROCESSOR_PABT_FUNC, offsetof(struct processor, _prefetch_abort)); |
116 | #endif | 119 | #endif |
120 | #ifdef MULTI_CPU | ||
121 | DEFINE(CPU_SLEEP_SIZE, offsetof(struct processor, suspend_size)); | ||
122 | DEFINE(CPU_DO_SUSPEND, offsetof(struct processor, do_suspend)); | ||
123 | DEFINE(CPU_DO_RESUME, offsetof(struct processor, do_resume)); | ||
124 | #endif | ||
125 | #ifdef MULTI_CACHE | ||
126 | DEFINE(CACHE_FLUSH_KERN_ALL, offsetof(struct cpu_cache_fns, flush_kern_all)); | ||
127 | #endif | ||
117 | BLANK(); | 128 | BLANK(); |
118 | DEFINE(DMA_BIDIRECTIONAL, DMA_BIDIRECTIONAL); | 129 | DEFINE(DMA_BIDIRECTIONAL, DMA_BIDIRECTIONAL); |
119 | DEFINE(DMA_TO_DEVICE, DMA_TO_DEVICE); | 130 | DEFINE(DMA_TO_DEVICE, DMA_TO_DEVICE); |
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/debug.S b/arch/arm/kernel/debug.S index a0f07521ca8a..d2d983be096d 100644 --- a/arch/arm/kernel/debug.S +++ b/arch/arm/kernel/debug.S | |||
@@ -25,7 +25,7 @@ | |||
25 | .macro addruart, rp, rv | 25 | .macro addruart, rp, rv |
26 | .endm | 26 | .endm |
27 | 27 | ||
28 | #if defined(CONFIG_CPU_V6) | 28 | #if defined(CONFIG_CPU_V6) || defined(CONFIG_CPU_V6K) |
29 | 29 | ||
30 | .macro senduart, rd, rx | 30 | .macro senduart, rd, rx |
31 | mcr p14, 0, \rd, c0, c5, 0 | 31 | mcr p14, 0, \rd, c0, c5, 0 |
diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index 2b46fea36c9f..e8d885676807 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S | |||
@@ -16,7 +16,8 @@ | |||
16 | */ | 16 | */ |
17 | 17 | ||
18 | #include <asm/memory.h> | 18 | #include <asm/memory.h> |
19 | #include <asm/glue.h> | 19 | #include <asm/glue-df.h> |
20 | #include <asm/glue-pf.h> | ||
20 | #include <asm/vfpmacros.h> | 21 | #include <asm/vfpmacros.h> |
21 | #include <mach/entry-macro.S> | 22 | #include <mach/entry-macro.S> |
22 | #include <asm/thread_notify.h> | 23 | #include <asm/thread_notify.h> |
diff --git a/arch/arm/kernel/entry-header.S b/arch/arm/kernel/entry-header.S index ae9464900168..051166c2a932 100644 --- a/arch/arm/kernel/entry-header.S +++ b/arch/arm/kernel/entry-header.S | |||
@@ -76,13 +76,13 @@ | |||
76 | #ifndef CONFIG_THUMB2_KERNEL | 76 | #ifndef CONFIG_THUMB2_KERNEL |
77 | .macro svc_exit, rpsr | 77 | .macro svc_exit, rpsr |
78 | msr spsr_cxsf, \rpsr | 78 | msr spsr_cxsf, \rpsr |
79 | #if defined(CONFIG_CPU_32v6K) | 79 | #if defined(CONFIG_CPU_V6) |
80 | clrex @ clear the exclusive monitor | ||
81 | ldmia sp, {r0 - pc}^ @ load r0 - pc, cpsr | ||
82 | #elif defined (CONFIG_CPU_V6) | ||
83 | ldr r0, [sp] | 80 | ldr r0, [sp] |
84 | strex r1, r2, [sp] @ clear the exclusive monitor | 81 | strex r1, r2, [sp] @ clear the exclusive monitor |
85 | ldmib sp, {r1 - pc}^ @ load r1 - pc, cpsr | 82 | ldmib sp, {r1 - pc}^ @ load r1 - pc, cpsr |
83 | #elif defined(CONFIG_CPU_32v6K) | ||
84 | clrex @ clear the exclusive monitor | ||
85 | ldmia sp, {r0 - pc}^ @ load r0 - pc, cpsr | ||
86 | #else | 86 | #else |
87 | ldmia sp, {r0 - pc}^ @ load r0 - pc, cpsr | 87 | ldmia sp, {r0 - pc}^ @ load r0 - pc, cpsr |
88 | #endif | 88 | #endif |
@@ -92,10 +92,10 @@ | |||
92 | ldr r1, [sp, #\offset + S_PSR] @ get calling cpsr | 92 | ldr r1, [sp, #\offset + S_PSR] @ get calling cpsr |
93 | ldr lr, [sp, #\offset + S_PC]! @ get pc | 93 | ldr lr, [sp, #\offset + S_PC]! @ get pc |
94 | msr spsr_cxsf, r1 @ save in spsr_svc | 94 | msr spsr_cxsf, r1 @ save in spsr_svc |
95 | #if defined(CONFIG_CPU_32v6K) | 95 | #if defined(CONFIG_CPU_V6) |
96 | clrex @ clear the exclusive monitor | ||
97 | #elif defined (CONFIG_CPU_V6) | ||
98 | strex r1, r2, [sp] @ clear the exclusive monitor | 96 | strex r1, r2, [sp] @ clear the exclusive monitor |
97 | #elif defined(CONFIG_CPU_32v6K) | ||
98 | clrex @ clear the exclusive monitor | ||
99 | #endif | 99 | #endif |
100 | .if \fast | 100 | .if \fast |
101 | ldmdb sp, {r1 - lr}^ @ get calling r1 - lr | 101 | ldmdb sp, {r1 - lr}^ @ get calling r1 - lr |
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..c9173cfbbc74 100644 --- a/arch/arm/kernel/head.S +++ b/arch/arm/kernel/head.S | |||
@@ -26,14 +26,6 @@ | |||
26 | #include <mach/debug-macro.S> | 26 | #include <mach/debug-macro.S> |
27 | #endif | 27 | #endif |
28 | 28 | ||
29 | #if (PHYS_OFFSET & 0x001fffff) | ||
30 | #error "PHYS_OFFSET must be at an even 2MiB boundary!" | ||
31 | #endif | ||
32 | |||
33 | #define KERNEL_RAM_VADDR (PAGE_OFFSET + TEXT_OFFSET) | ||
34 | #define KERNEL_RAM_PADDR (PHYS_OFFSET + TEXT_OFFSET) | ||
35 | |||
36 | |||
37 | /* | 29 | /* |
38 | * swapper_pg_dir is the virtual address of the initial page table. | 30 | * swapper_pg_dir is the virtual address of the initial page table. |
39 | * We place the page tables 16K below KERNEL_RAM_VADDR. Therefore, we must | 31 | * We place the page tables 16K below KERNEL_RAM_VADDR. Therefore, we must |
@@ -41,6 +33,7 @@ | |||
41 | * the least significant 16 bits to be 0x8000, but we could probably | 33 | * the least significant 16 bits to be 0x8000, but we could probably |
42 | * relax this restriction to KERNEL_RAM_VADDR >= PAGE_OFFSET + 0x4000. | 34 | * relax this restriction to KERNEL_RAM_VADDR >= PAGE_OFFSET + 0x4000. |
43 | */ | 35 | */ |
36 | #define KERNEL_RAM_VADDR (PAGE_OFFSET + TEXT_OFFSET) | ||
44 | #if (KERNEL_RAM_VADDR & 0xffff) != 0x8000 | 37 | #if (KERNEL_RAM_VADDR & 0xffff) != 0x8000 |
45 | #error KERNEL_RAM_VADDR must start at 0xXXXX8000 | 38 | #error KERNEL_RAM_VADDR must start at 0xXXXX8000 |
46 | #endif | 39 | #endif |
@@ -48,8 +41,8 @@ | |||
48 | .globl swapper_pg_dir | 41 | .globl swapper_pg_dir |
49 | .equ swapper_pg_dir, KERNEL_RAM_VADDR - 0x4000 | 42 | .equ swapper_pg_dir, KERNEL_RAM_VADDR - 0x4000 |
50 | 43 | ||
51 | .macro pgtbl, rd | 44 | .macro pgtbl, rd, phys |
52 | ldr \rd, =(KERNEL_RAM_PADDR - 0x4000) | 45 | add \rd, \phys, #TEXT_OFFSET - 0x4000 |
53 | .endm | 46 | .endm |
54 | 47 | ||
55 | #ifdef CONFIG_XIP_KERNEL | 48 | #ifdef CONFIG_XIP_KERNEL |
@@ -87,25 +80,33 @@ ENTRY(stext) | |||
87 | movs r10, r5 @ invalid processor (r5=0)? | 80 | movs r10, r5 @ invalid processor (r5=0)? |
88 | THUMB( it eq ) @ force fixup-able long branch encoding | 81 | THUMB( it eq ) @ force fixup-able long branch encoding |
89 | beq __error_p @ yes, error 'p' | 82 | beq __error_p @ yes, error 'p' |
90 | bl __lookup_machine_type @ r5=machinfo | 83 | |
91 | movs r8, r5 @ invalid machine (r5=0)? | 84 | #ifndef CONFIG_XIP_KERNEL |
92 | THUMB( it eq ) @ force fixup-able long branch encoding | 85 | adr r3, 2f |
93 | beq __error_a @ yes, error 'a' | 86 | ldmia r3, {r4, r8} |
87 | sub r4, r3, r4 @ (PHYS_OFFSET - PAGE_OFFSET) | ||
88 | add r8, r8, r4 @ PHYS_OFFSET | ||
89 | #else | ||
90 | ldr r8, =PLAT_PHYS_OFFSET | ||
91 | #endif | ||
94 | 92 | ||
95 | /* | 93 | /* |
96 | * r1 = machine no, r2 = atags, | 94 | * r1 = machine no, r2 = atags, |
97 | * r8 = machinfo, r9 = cpuid, r10 = procinfo | 95 | * r8 = phys_offset, r9 = cpuid, r10 = procinfo |
98 | */ | 96 | */ |
99 | bl __vet_atags | 97 | bl __vet_atags |
100 | #ifdef CONFIG_SMP_ON_UP | 98 | #ifdef CONFIG_SMP_ON_UP |
101 | bl __fixup_smp | 99 | bl __fixup_smp |
102 | #endif | 100 | #endif |
101 | #ifdef CONFIG_ARM_PATCH_PHYS_VIRT | ||
102 | bl __fixup_pv_table | ||
103 | #endif | ||
103 | bl __create_page_tables | 104 | bl __create_page_tables |
104 | 105 | ||
105 | /* | 106 | /* |
106 | * The following calls CPU specific code in a position independent | 107 | * The following calls CPU specific code in a position independent |
107 | * manner. See arch/arm/mm/proc-*.S for details. r10 = base of | 108 | * manner. See arch/arm/mm/proc-*.S for details. r10 = base of |
108 | * xxx_proc_info structure selected by __lookup_machine_type | 109 | * xxx_proc_info structure selected by __lookup_processor_type |
109 | * above. On return, the CPU will be ready for the MMU to be | 110 | * 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. | 111 | * turned on, and r0 will hold the CPU control register value. |
111 | */ | 112 | */ |
@@ -118,22 +119,24 @@ ENTRY(stext) | |||
118 | 1: b __enable_mmu | 119 | 1: b __enable_mmu |
119 | ENDPROC(stext) | 120 | ENDPROC(stext) |
120 | .ltorg | 121 | .ltorg |
122 | #ifndef CONFIG_XIP_KERNEL | ||
123 | 2: .long . | ||
124 | .long PAGE_OFFSET | ||
125 | #endif | ||
121 | 126 | ||
122 | /* | 127 | /* |
123 | * Setup the initial page tables. We only setup the barest | 128 | * Setup the initial page tables. We only setup the barest |
124 | * amount which are required to get the kernel running, which | 129 | * amount which are required to get the kernel running, which |
125 | * generally means mapping in the kernel code. | 130 | * generally means mapping in the kernel code. |
126 | * | 131 | * |
127 | * r8 = machinfo | 132 | * r8 = phys_offset, r9 = cpuid, r10 = procinfo |
128 | * r9 = cpuid | ||
129 | * r10 = procinfo | ||
130 | * | 133 | * |
131 | * Returns: | 134 | * Returns: |
132 | * r0, r3, r5-r7 corrupted | 135 | * r0, r3, r5-r7 corrupted |
133 | * r4 = physical page table address | 136 | * r4 = physical page table address |
134 | */ | 137 | */ |
135 | __create_page_tables: | 138 | __create_page_tables: |
136 | pgtbl r4 @ page table address | 139 | pgtbl r4, r8 @ page table address |
137 | 140 | ||
138 | /* | 141 | /* |
139 | * Clear the 16K level 1 swapper page table | 142 | * Clear the 16K level 1 swapper page table |
@@ -189,10 +192,8 @@ __create_page_tables: | |||
189 | /* | 192 | /* |
190 | * Map some ram to cover our .data and .bss areas. | 193 | * Map some ram to cover our .data and .bss areas. |
191 | */ | 194 | */ |
192 | orr r3, r7, #(KERNEL_RAM_PADDR & 0xff000000) | 195 | add r3, r8, #TEXT_OFFSET |
193 | .if (KERNEL_RAM_PADDR & 0x00f00000) | 196 | orr r3, r3, r7 |
194 | orr r3, r3, #(KERNEL_RAM_PADDR & 0x00f00000) | ||
195 | .endif | ||
196 | add r0, r4, #(KERNEL_RAM_VADDR & 0xff000000) >> 18 | 197 | add r0, r4, #(KERNEL_RAM_VADDR & 0xff000000) >> 18 |
197 | str r3, [r0, #(KERNEL_RAM_VADDR & 0x00f00000) >> 18]! | 198 | str r3, [r0, #(KERNEL_RAM_VADDR & 0x00f00000) >> 18]! |
198 | ldr r6, =(_end - 1) | 199 | ldr r6, =(_end - 1) |
@@ -205,14 +206,17 @@ __create_page_tables: | |||
205 | #endif | 206 | #endif |
206 | 207 | ||
207 | /* | 208 | /* |
208 | * Then map first 1MB of ram in case it contains our boot params. | 209 | * Then map boot params address in r2 or |
210 | * the first 1MB of ram if boot params address is not specified. | ||
209 | */ | 211 | */ |
210 | add r0, r4, #PAGE_OFFSET >> 18 | 212 | mov r0, r2, lsr #20 |
211 | orr r6, r7, #(PHYS_OFFSET & 0xff000000) | 213 | movs r0, r0, lsl #20 |
212 | .if (PHYS_OFFSET & 0x00f00000) | 214 | moveq r0, r8 |
213 | orr r6, r6, #(PHYS_OFFSET & 0x00f00000) | 215 | sub r3, r0, r8 |
214 | .endif | 216 | add r3, r3, #PAGE_OFFSET |
215 | str r6, [r0] | 217 | add r3, r4, r3, lsr #18 |
218 | orr r6, r7, r0 | ||
219 | str r6, [r3] | ||
216 | 220 | ||
217 | #ifdef CONFIG_DEBUG_LL | 221 | #ifdef CONFIG_DEBUG_LL |
218 | #ifndef CONFIG_DEBUG_ICEDCC | 222 | #ifndef CONFIG_DEBUG_ICEDCC |
@@ -457,4 +461,129 @@ ENTRY(fixup_smp) | |||
457 | ldmfd sp!, {r4 - r6, pc} | 461 | ldmfd sp!, {r4 - r6, pc} |
458 | ENDPROC(fixup_smp) | 462 | ENDPROC(fixup_smp) |
459 | 463 | ||
464 | #ifdef CONFIG_ARM_PATCH_PHYS_VIRT | ||
465 | |||
466 | /* __fixup_pv_table - patch the stub instructions with the delta between | ||
467 | * PHYS_OFFSET and PAGE_OFFSET, which is assumed to be 16MiB aligned and | ||
468 | * can be expressed by an immediate shifter operand. The stub instruction | ||
469 | * has a form of '(add|sub) rd, rn, #imm'. | ||
470 | */ | ||
471 | __HEAD | ||
472 | __fixup_pv_table: | ||
473 | adr r0, 1f | ||
474 | ldmia r0, {r3-r5, r7} | ||
475 | sub r3, r0, r3 @ PHYS_OFFSET - PAGE_OFFSET | ||
476 | add r4, r4, r3 @ adjust table start address | ||
477 | add r5, r5, r3 @ adjust table end address | ||
478 | add r7, r7, r3 @ adjust __pv_phys_offset address | ||
479 | str r8, [r7] @ save computed PHYS_OFFSET to __pv_phys_offset | ||
480 | #ifndef CONFIG_ARM_PATCH_PHYS_VIRT_16BIT | ||
481 | mov r6, r3, lsr #24 @ constant for add/sub instructions | ||
482 | teq r3, r6, lsl #24 @ must be 16MiB aligned | ||
483 | #else | ||
484 | mov r6, r3, lsr #16 @ constant for add/sub instructions | ||
485 | teq r3, r6, lsl #16 @ must be 64kiB aligned | ||
486 | #endif | ||
487 | THUMB( it ne @ cross section branch ) | ||
488 | bne __error | ||
489 | str r6, [r7, #4] @ save to __pv_offset | ||
490 | b __fixup_a_pv_table | ||
491 | ENDPROC(__fixup_pv_table) | ||
492 | |||
493 | .align | ||
494 | 1: .long . | ||
495 | .long __pv_table_begin | ||
496 | .long __pv_table_end | ||
497 | 2: .long __pv_phys_offset | ||
498 | |||
499 | .text | ||
500 | __fixup_a_pv_table: | ||
501 | #ifdef CONFIG_THUMB2_KERNEL | ||
502 | #ifdef CONFIG_ARM_PATCH_PHYS_VIRT_16BIT | ||
503 | lsls r0, r6, #24 | ||
504 | lsr r6, #8 | ||
505 | beq 1f | ||
506 | clz r7, r0 | ||
507 | lsr r0, #24 | ||
508 | lsl r0, r7 | ||
509 | bic r0, 0x0080 | ||
510 | lsrs r7, #1 | ||
511 | orrcs r0, #0x0080 | ||
512 | orr r0, r0, r7, lsl #12 | ||
513 | #endif | ||
514 | 1: lsls r6, #24 | ||
515 | beq 4f | ||
516 | clz r7, r6 | ||
517 | lsr r6, #24 | ||
518 | lsl r6, r7 | ||
519 | bic r6, #0x0080 | ||
520 | lsrs r7, #1 | ||
521 | orrcs r6, #0x0080 | ||
522 | orr r6, r6, r7, lsl #12 | ||
523 | orr r6, #0x4000 | ||
524 | b 4f | ||
525 | 2: @ at this point the C flag is always clear | ||
526 | add r7, r3 | ||
527 | #ifdef CONFIG_ARM_PATCH_PHYS_VIRT_16BIT | ||
528 | ldrh ip, [r7] | ||
529 | tst ip, 0x0400 @ the i bit tells us LS or MS byte | ||
530 | beq 3f | ||
531 | cmp r0, #0 @ set C flag, and ... | ||
532 | biceq ip, 0x0400 @ immediate zero value has a special encoding | ||
533 | streqh ip, [r7] @ that requires the i bit cleared | ||
534 | #endif | ||
535 | 3: ldrh ip, [r7, #2] | ||
536 | and ip, 0x8f00 | ||
537 | orrcc ip, r6 @ mask in offset bits 31-24 | ||
538 | orrcs ip, r0 @ mask in offset bits 23-16 | ||
539 | strh ip, [r7, #2] | ||
540 | 4: cmp r4, r5 | ||
541 | ldrcc r7, [r4], #4 @ use branch for delay slot | ||
542 | bcc 2b | ||
543 | bx lr | ||
544 | #else | ||
545 | #ifdef CONFIG_ARM_PATCH_PHYS_VIRT_16BIT | ||
546 | and r0, r6, #255 @ offset bits 23-16 | ||
547 | mov r6, r6, lsr #8 @ offset bits 31-24 | ||
548 | #else | ||
549 | mov r0, #0 @ just in case... | ||
550 | #endif | ||
551 | b 3f | ||
552 | 2: ldr ip, [r7, r3] | ||
553 | bic ip, ip, #0x000000ff | ||
554 | tst ip, #0x400 @ rotate shift tells us LS or MS byte | ||
555 | orrne ip, ip, r6 @ mask in offset bits 31-24 | ||
556 | orreq ip, ip, r0 @ mask in offset bits 23-16 | ||
557 | str ip, [r7, r3] | ||
558 | 3: cmp r4, r5 | ||
559 | ldrcc r7, [r4], #4 @ use branch for delay slot | ||
560 | bcc 2b | ||
561 | mov pc, lr | ||
562 | #endif | ||
563 | ENDPROC(__fixup_a_pv_table) | ||
564 | |||
565 | ENTRY(fixup_pv_table) | ||
566 | stmfd sp!, {r4 - r7, lr} | ||
567 | ldr r2, 2f @ get address of __pv_phys_offset | ||
568 | mov r3, #0 @ no offset | ||
569 | mov r4, r0 @ r0 = table start | ||
570 | add r5, r0, r1 @ r1 = table size | ||
571 | ldr r6, [r2, #4] @ get __pv_offset | ||
572 | bl __fixup_a_pv_table | ||
573 | ldmfd sp!, {r4 - r7, pc} | ||
574 | ENDPROC(fixup_pv_table) | ||
575 | |||
576 | .align | ||
577 | 2: .long __pv_phys_offset | ||
578 | |||
579 | .data | ||
580 | .globl __pv_phys_offset | ||
581 | .type __pv_phys_offset, %object | ||
582 | __pv_phys_offset: | ||
583 | .long 0 | ||
584 | .size __pv_phys_offset, . - __pv_phys_offset | ||
585 | __pv_offset: | ||
586 | .long 0 | ||
587 | #endif | ||
588 | |||
460 | #include "head-common.S" | 589 | #include "head-common.S" |
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..fee7c36349eb 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 | ||
@@ -282,12 +283,13 @@ static const Elf_Shdr *find_mod_section(const Elf32_Ehdr *hdr, | |||
282 | return NULL; | 283 | return NULL; |
283 | } | 284 | } |
284 | 285 | ||
286 | extern void fixup_pv_table(const void *, unsigned long); | ||
285 | extern void fixup_smp(const void *, unsigned long); | 287 | extern void fixup_smp(const void *, unsigned long); |
286 | 288 | ||
287 | int module_finalize(const Elf32_Ehdr *hdr, const Elf_Shdr *sechdrs, | 289 | int module_finalize(const Elf32_Ehdr *hdr, const Elf_Shdr *sechdrs, |
288 | struct module *mod) | 290 | struct module *mod) |
289 | { | 291 | { |
290 | const Elf_Shdr * __maybe_unused s = NULL; | 292 | const Elf_Shdr *s = NULL; |
291 | #ifdef CONFIG_ARM_UNWIND | 293 | #ifdef CONFIG_ARM_UNWIND |
292 | const char *secstrs = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; | 294 | const char *secstrs = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; |
293 | const Elf_Shdr *sechdrs_end = sechdrs + hdr->e_shnum; | 295 | const Elf_Shdr *sechdrs_end = sechdrs + hdr->e_shnum; |
@@ -332,6 +334,11 @@ int module_finalize(const Elf32_Ehdr *hdr, const Elf_Shdr *sechdrs, | |||
332 | maps[i].txt_sec->sh_addr, | 334 | maps[i].txt_sec->sh_addr, |
333 | maps[i].txt_sec->sh_size); | 335 | maps[i].txt_sec->sh_size); |
334 | #endif | 336 | #endif |
337 | #ifdef CONFIG_ARM_PATCH_PHYS_VIRT | ||
338 | s = find_mod_section(hdr, sechdrs, ".pv_table"); | ||
339 | if (s) | ||
340 | fixup_pv_table((void *)s->sh_addr, s->sh_size); | ||
341 | #endif | ||
335 | s = find_mod_section(hdr, sechdrs, ".alt.smp.init"); | 342 | s = find_mod_section(hdr, sechdrs, ".alt.smp.init"); |
336 | if (s && !is_smp()) | 343 | if (s && !is_smp()) |
337 | fixup_smp((void *)s->sh_addr, s->sh_size); | 344 | fixup_smp((void *)s->sh_addr, s->sh_size); |
diff --git a/arch/arm/kernel/perf_event_v6.c b/arch/arm/kernel/perf_event_v6.c index c058bfc8532b..6fc2d228db55 100644 --- a/arch/arm/kernel/perf_event_v6.c +++ b/arch/arm/kernel/perf_event_v6.c | |||
@@ -30,7 +30,7 @@ | |||
30 | * enable the interrupt. | 30 | * enable the interrupt. |
31 | */ | 31 | */ |
32 | 32 | ||
33 | #ifdef CONFIG_CPU_V6 | 33 | #if defined(CONFIG_CPU_V6) || defined(CONFIG_CPU_V6K) |
34 | enum armv6_perf_types { | 34 | enum armv6_perf_types { |
35 | ARMV6_PERFCTR_ICACHE_MISS = 0x0, | 35 | ARMV6_PERFCTR_ICACHE_MISS = 0x0, |
36 | ARMV6_PERFCTR_IBUF_STALL = 0x1, | 36 | ARMV6_PERFCTR_IBUF_STALL = 0x1, |
@@ -669,4 +669,4 @@ static const struct arm_pmu *__init armv6mpcore_pmu_init(void) | |||
669 | { | 669 | { |
670 | return NULL; | 670 | return NULL; |
671 | } | 671 | } |
672 | #endif /* CONFIG_CPU_V6 */ | 672 | #endif /* CONFIG_CPU_V6 || CONFIG_CPU_V6K */ |
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..d1da92174277 100644 --- a/arch/arm/kernel/setup.c +++ b/arch/arm/kernel/setup.c | |||
@@ -308,7 +308,22 @@ 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 | } | ||
312 | 327 | ||
313 | static void __init feat_v6_fixup(void) | 328 | static void __init feat_v6_fixup(void) |
314 | { | 329 | { |
@@ -426,21 +441,29 @@ void cpu_init(void) | |||
426 | 441 | ||
427 | static struct machine_desc * __init setup_machine(unsigned int nr) | 442 | static struct machine_desc * __init setup_machine(unsigned int nr) |
428 | { | 443 | { |
429 | struct machine_desc *list; | 444 | extern struct machine_desc __arch_info_begin[], __arch_info_end[]; |
445 | struct machine_desc *p; | ||
430 | 446 | ||
431 | /* | 447 | /* |
432 | * locate machine in the list of supported machines. | 448 | * locate machine in the list of supported machines. |
433 | */ | 449 | */ |
434 | list = lookup_machine_type(nr); | 450 | for (p = __arch_info_begin; p < __arch_info_end; p++) |
435 | if (!list) { | 451 | if (nr == p->nr) { |
436 | printk("Machine configuration botched (nr %d), unable " | 452 | printk("Machine: %s\n", p->name); |
437 | "to continue.\n", nr); | 453 | return p; |
438 | while (1); | 454 | } |
439 | } | ||
440 | 455 | ||
441 | printk("Machine: %s\n", list->name); | 456 | early_print("\n" |
457 | "Error: unrecognized/unsupported machine ID (r1 = 0x%08x).\n\n" | ||
458 | "Available machine support:\n\nID (hex)\tNAME\n", nr); | ||
442 | 459 | ||
443 | return list; | 460 | for (p = __arch_info_begin; p < __arch_info_end; p++) |
461 | early_print("%08x\t%s\n", p->nr, p->name); | ||
462 | |||
463 | early_print("\nPlease check your kernel config and/or bootloader.\n"); | ||
464 | |||
465 | while (true) | ||
466 | /* can't use cpu_relax() here as it may require MMU setup */; | ||
444 | } | 467 | } |
445 | 468 | ||
446 | static int __init arm_add_memory(unsigned long start, unsigned long size) | 469 | static int __init arm_add_memory(unsigned long start, unsigned long size) |
@@ -703,7 +726,7 @@ static struct init_tags { | |||
703 | { tag_size(tag_core), ATAG_CORE }, | 726 | { tag_size(tag_core), ATAG_CORE }, |
704 | { 1, PAGE_SIZE, 0xff }, | 727 | { 1, PAGE_SIZE, 0xff }, |
705 | { tag_size(tag_mem32), ATAG_MEM }, | 728 | { tag_size(tag_mem32), ATAG_MEM }, |
706 | { MEM_SIZE, PHYS_OFFSET }, | 729 | { MEM_SIZE }, |
707 | { 0, ATAG_NONE } | 730 | { 0, ATAG_NONE } |
708 | }; | 731 | }; |
709 | 732 | ||
@@ -802,6 +825,8 @@ void __init setup_arch(char **cmdline_p) | |||
802 | struct machine_desc *mdesc; | 825 | struct machine_desc *mdesc; |
803 | char *from = default_command_line; | 826 | char *from = default_command_line; |
804 | 827 | ||
828 | init_tags.mem.start = PHYS_OFFSET; | ||
829 | |||
805 | unwind_init(); | 830 | unwind_init(); |
806 | 831 | ||
807 | setup_processor(); | 832 | setup_processor(); |
@@ -814,8 +839,25 @@ void __init setup_arch(char **cmdline_p) | |||
814 | 839 | ||
815 | if (__atags_pointer) | 840 | if (__atags_pointer) |
816 | tags = phys_to_virt(__atags_pointer); | 841 | tags = phys_to_virt(__atags_pointer); |
817 | else if (mdesc->boot_params) | 842 | else if (mdesc->boot_params) { |
818 | tags = phys_to_virt(mdesc->boot_params); | 843 | #ifdef CONFIG_MMU |
844 | /* | ||
845 | * We still are executing with a minimal MMU mapping created | ||
846 | * with the presumption that the machine default for this | ||
847 | * is located in the first MB of RAM. Anything else will | ||
848 | * fault and silently hang the kernel at this point. | ||
849 | */ | ||
850 | if (mdesc->boot_params < PHYS_OFFSET || | ||
851 | mdesc->boot_params >= PHYS_OFFSET + SZ_1M) { | ||
852 | printk(KERN_WARNING | ||
853 | "Default boot params at physical 0x%08lx out of reach\n", | ||
854 | mdesc->boot_params); | ||
855 | } else | ||
856 | #endif | ||
857 | { | ||
858 | tags = phys_to_virt(mdesc->boot_params); | ||
859 | } | ||
860 | } | ||
819 | 861 | ||
820 | #if defined(CONFIG_DEPRECATED_PARAM_STRUCT) | 862 | #if defined(CONFIG_DEPRECATED_PARAM_STRUCT) |
821 | /* | 863 | /* |
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/sleep.S b/arch/arm/kernel/sleep.S new file mode 100644 index 000000000000..bfad698a02e7 --- /dev/null +++ b/arch/arm/kernel/sleep.S | |||
@@ -0,0 +1,134 @@ | |||
1 | #include <linux/linkage.h> | ||
2 | #include <linux/threads.h> | ||
3 | #include <asm/asm-offsets.h> | ||
4 | #include <asm/assembler.h> | ||
5 | #include <asm/glue-cache.h> | ||
6 | #include <asm/glue-proc.h> | ||
7 | #include <asm/system.h> | ||
8 | .text | ||
9 | |||
10 | /* | ||
11 | * Save CPU state for a suspend | ||
12 | * r1 = v:p offset | ||
13 | * r3 = virtual return function | ||
14 | * Note: sp is decremented to allocate space for CPU state on stack | ||
15 | * r0-r3,r9,r10,lr corrupted | ||
16 | */ | ||
17 | ENTRY(cpu_suspend) | ||
18 | mov r9, lr | ||
19 | #ifdef MULTI_CPU | ||
20 | ldr r10, =processor | ||
21 | mov r2, sp @ current virtual SP | ||
22 | ldr r0, [r10, #CPU_SLEEP_SIZE] @ size of CPU sleep state | ||
23 | ldr ip, [r10, #CPU_DO_RESUME] @ virtual resume function | ||
24 | sub sp, sp, r0 @ allocate CPU state on stack | ||
25 | mov r0, sp @ save pointer | ||
26 | add ip, ip, r1 @ convert resume fn to phys | ||
27 | stmfd sp!, {r1, r2, r3, ip} @ save v:p, virt SP, retfn, phys resume fn | ||
28 | ldr r3, =sleep_save_sp | ||
29 | add r2, sp, r1 @ convert SP to phys | ||
30 | #ifdef CONFIG_SMP | ||
31 | ALT_SMP(mrc p15, 0, lr, c0, c0, 5) | ||
32 | ALT_UP(mov lr, #0) | ||
33 | and lr, lr, #15 | ||
34 | str r2, [r3, lr, lsl #2] @ save phys SP | ||
35 | #else | ||
36 | str r2, [r3] @ save phys SP | ||
37 | #endif | ||
38 | mov lr, pc | ||
39 | ldr pc, [r10, #CPU_DO_SUSPEND] @ save CPU state | ||
40 | #else | ||
41 | mov r2, sp @ current virtual SP | ||
42 | ldr r0, =cpu_suspend_size | ||
43 | sub sp, sp, r0 @ allocate CPU state on stack | ||
44 | mov r0, sp @ save pointer | ||
45 | stmfd sp!, {r1, r2, r3} @ save v:p, virt SP, return fn | ||
46 | ldr r3, =sleep_save_sp | ||
47 | add r2, sp, r1 @ convert SP to phys | ||
48 | #ifdef CONFIG_SMP | ||
49 | ALT_SMP(mrc p15, 0, lr, c0, c0, 5) | ||
50 | ALT_UP(mov lr, #0) | ||
51 | and lr, lr, #15 | ||
52 | str r2, [r3, lr, lsl #2] @ save phys SP | ||
53 | #else | ||
54 | str r2, [r3] @ save phys SP | ||
55 | #endif | ||
56 | bl cpu_do_suspend | ||
57 | #endif | ||
58 | |||
59 | @ flush data cache | ||
60 | #ifdef MULTI_CACHE | ||
61 | ldr r10, =cpu_cache | ||
62 | mov lr, r9 | ||
63 | ldr pc, [r10, #CACHE_FLUSH_KERN_ALL] | ||
64 | #else | ||
65 | mov lr, r9 | ||
66 | b __cpuc_flush_kern_all | ||
67 | #endif | ||
68 | ENDPROC(cpu_suspend) | ||
69 | .ltorg | ||
70 | |||
71 | /* | ||
72 | * r0 = control register value | ||
73 | * r1 = v:p offset (preserved by cpu_do_resume) | ||
74 | * r2 = phys page table base | ||
75 | * r3 = L1 section flags | ||
76 | */ | ||
77 | ENTRY(cpu_resume_mmu) | ||
78 | adr r4, cpu_resume_turn_mmu_on | ||
79 | mov r4, r4, lsr #20 | ||
80 | orr r3, r3, r4, lsl #20 | ||
81 | ldr r5, [r2, r4, lsl #2] @ save old mapping | ||
82 | str r3, [r2, r4, lsl #2] @ setup 1:1 mapping for mmu code | ||
83 | sub r2, r2, r1 | ||
84 | ldr r3, =cpu_resume_after_mmu | ||
85 | bic r1, r0, #CR_C @ ensure D-cache is disabled | ||
86 | b cpu_resume_turn_mmu_on | ||
87 | ENDPROC(cpu_resume_mmu) | ||
88 | .ltorg | ||
89 | .align 5 | ||
90 | cpu_resume_turn_mmu_on: | ||
91 | mcr p15, 0, r1, c1, c0, 0 @ turn on MMU, I-cache, etc | ||
92 | mrc p15, 0, r1, c0, c0, 0 @ read id reg | ||
93 | mov r1, r1 | ||
94 | mov r1, r1 | ||
95 | mov pc, r3 @ jump to virtual address | ||
96 | ENDPROC(cpu_resume_turn_mmu_on) | ||
97 | cpu_resume_after_mmu: | ||
98 | str r5, [r2, r4, lsl #2] @ restore old mapping | ||
99 | mcr p15, 0, r0, c1, c0, 0 @ turn on D-cache | ||
100 | mov pc, lr | ||
101 | ENDPROC(cpu_resume_after_mmu) | ||
102 | |||
103 | /* | ||
104 | * Note: Yes, part of the following code is located into the .data section. | ||
105 | * This is to allow sleep_save_sp to be accessed with a relative load | ||
106 | * while we can't rely on any MMU translation. We could have put | ||
107 | * sleep_save_sp in the .text section as well, but some setups might | ||
108 | * insist on it to be truly read-only. | ||
109 | */ | ||
110 | .data | ||
111 | .align | ||
112 | ENTRY(cpu_resume) | ||
113 | #ifdef CONFIG_SMP | ||
114 | adr r0, sleep_save_sp | ||
115 | ALT_SMP(mrc p15, 0, r1, c0, c0, 5) | ||
116 | ALT_UP(mov r1, #0) | ||
117 | and r1, r1, #15 | ||
118 | ldr r0, [r0, r1, lsl #2] @ stack phys addr | ||
119 | #else | ||
120 | ldr r0, sleep_save_sp @ stack phys addr | ||
121 | #endif | ||
122 | msr cpsr_c, #PSR_I_BIT | PSR_F_BIT | SVC_MODE @ set SVC, irqs off | ||
123 | #ifdef MULTI_CPU | ||
124 | ldmia r0!, {r1, sp, lr, pc} @ load v:p, stack, return fn, resume fn | ||
125 | #else | ||
126 | ldmia r0!, {r1, sp, lr} @ load v:p, stack, return fn | ||
127 | b cpu_do_resume | ||
128 | #endif | ||
129 | ENDPROC(cpu_resume) | ||
130 | |||
131 | sleep_save_sp: | ||
132 | .rept CONFIG_NR_CPUS | ||
133 | .long 0 @ preserve stack phys ptr here | ||
134 | .endr | ||
diff --git a/arch/arm/kernel/smp_scu.c b/arch/arm/kernel/smp_scu.c index 9ab4149bd983..a1e757c3439b 100644 --- a/arch/arm/kernel/smp_scu.c +++ b/arch/arm/kernel/smp_scu.c | |||
@@ -50,3 +50,26 @@ void __init scu_enable(void __iomem *scu_base) | |||
50 | */ | 50 | */ |
51 | flush_cache_all(); | 51 | flush_cache_all(); |
52 | } | 52 | } |
53 | |||
54 | /* | ||
55 | * Set the executing CPUs power mode as defined. This will be in | ||
56 | * preparation for it executing a WFI instruction. | ||
57 | * | ||
58 | * This function must be called with preemption disabled, and as it | ||
59 | * has the side effect of disabling coherency, caches must have been | ||
60 | * flushed. Interrupts must also have been disabled. | ||
61 | */ | ||
62 | int scu_power_mode(void __iomem *scu_base, unsigned int mode) | ||
63 | { | ||
64 | unsigned int val; | ||
65 | int cpu = smp_processor_id(); | ||
66 | |||
67 | if (mode > 3 || mode == 1 || cpu > 3) | ||
68 | return -EINVAL; | ||
69 | |||
70 | val = __raw_readb(scu_base + SCU_CPU_STATUS + cpu) & ~0x03; | ||
71 | val |= mode; | ||
72 | __raw_writeb(val, scu_base + SCU_CPU_STATUS + cpu); | ||
73 | |||
74 | return 0; | ||
75 | } | ||
diff --git a/arch/arm/kernel/tcm.c b/arch/arm/kernel/tcm.c index 26685c2f7a49..f5cf660eefcc 100644 --- a/arch/arm/kernel/tcm.c +++ b/arch/arm/kernel/tcm.c | |||
@@ -15,7 +15,7 @@ | |||
15 | #include <linux/string.h> /* memcpy */ | 15 | #include <linux/string.h> /* memcpy */ |
16 | #include <asm/cputype.h> | 16 | #include <asm/cputype.h> |
17 | #include <asm/mach/map.h> | 17 | #include <asm/mach/map.h> |
18 | #include <mach/memory.h> | 18 | #include <asm/memory.h> |
19 | #include "tcm.h" | 19 | #include "tcm.h" |
20 | 20 | ||
21 | static struct gen_pool *tcm_pool; | 21 | static struct gen_pool *tcm_pool; |
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. |
diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S index 28fea9b2d129..b4348e62ef06 100644 --- a/arch/arm/kernel/vmlinux.lds.S +++ b/arch/arm/kernel/vmlinux.lds.S | |||
@@ -64,6 +64,10 @@ SECTIONS | |||
64 | __smpalt_end = .; | 64 | __smpalt_end = .; |
65 | #endif | 65 | #endif |
66 | 66 | ||
67 | __pv_table_begin = .; | ||
68 | *(.pv_table) | ||
69 | __pv_table_end = .; | ||
70 | |||
67 | INIT_SETUP(16) | 71 | INIT_SETUP(16) |
68 | 72 | ||
69 | INIT_CALLS | 73 | INIT_CALLS |