diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-03-29 19:53:48 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-03-29 19:53:48 -0400 |
commit | 12679a2d7e3bfbdc7586e3e86d1ca90c46659363 (patch) | |
tree | d9c00f2e599d1c3e04a349229a6a19906d01f99e /arch/arm/kernel | |
parent | 1c036588772d01655d851f75dffc27c971e072e2 (diff) | |
parent | b0df89868006517417251e02cc4ce5d4b0165885 (diff) |
Merge branch 'for-linus' of git://git.linaro.org/people/rmk/linux-arm
Pull more ARM updates from Russell King.
This got a fair number of conflicts with the <asm/system.h> split, but
also with some other sparse-irq and header file include cleanups. They
all looked pretty trivial, though.
* 'for-linus' of git://git.linaro.org/people/rmk/linux-arm: (59 commits)
ARM: fix Kconfig warning for HAVE_BPF_JIT
ARM: 7361/1: provide XIP_VIRT_ADDR for no-MMU builds
ARM: 7349/1: integrator: convert to sparse irqs
ARM: 7259/3: net: JIT compiler for packet filters
ARM: 7334/1: add jump label support
ARM: 7333/2: jump label: detect %c support for ARM
ARM: 7338/1: add support for early console output via semihosting
ARM: use set_current_blocked() and block_sigmask()
ARM: exec: remove redundant set_fs(USER_DS)
ARM: 7332/1: extract out code patch function from kprobes
ARM: 7331/1: extract out insn generation code from ftrace
ARM: 7330/1: ftrace: use canonical Thumb-2 wide instruction format
ARM: 7351/1: ftrace: remove useless memory checks
ARM: 7316/1: kexec: EOI active and mask all interrupts in kexec crash path
ARM: Versatile Express: add NO_IOPORT
ARM: get rid of asm/irq.h in asm/prom.h
ARM: 7319/1: Print debug info for SIGBUS in user faults
ARM: 7318/1: gic: refactor irq_start assignment
ARM: 7317/1: irq: avoid NULL check in for_each_irq_desc loop
ARM: 7315/1: perf: add support for the Cortex-A7 PMU
...
Diffstat (limited to 'arch/arm/kernel')
-rw-r--r-- | arch/arm/kernel/Makefile | 14 | ||||
-rw-r--r-- | arch/arm/kernel/debug.S | 25 | ||||
-rw-r--r-- | arch/arm/kernel/ftrace.c | 100 | ||||
-rw-r--r-- | arch/arm/kernel/head.S | 8 | ||||
-rw-r--r-- | arch/arm/kernel/insn.c | 61 | ||||
-rw-r--r-- | arch/arm/kernel/insn.h | 29 | ||||
-rw-r--r-- | arch/arm/kernel/irq.c | 5 | ||||
-rw-r--r-- | arch/arm/kernel/jump_label.c | 39 | ||||
-rw-r--r-- | arch/arm/kernel/kprobes.c | 86 | ||||
-rw-r--r-- | arch/arm/kernel/machine_kexec.c | 25 | ||||
-rw-r--r-- | arch/arm/kernel/patch.c | 75 | ||||
-rw-r--r-- | arch/arm/kernel/patch.h | 7 | ||||
-rw-r--r-- | arch/arm/kernel/perf_event.c | 3 | ||||
-rw-r--r-- | arch/arm/kernel/perf_event_v7.c | 145 | ||||
-rw-r--r-- | arch/arm/kernel/process.c | 36 | ||||
-rw-r--r-- | arch/arm/kernel/sched_clock.c | 18 | ||||
-rw-r--r-- | arch/arm/kernel/setup.c | 1 | ||||
-rw-r--r-- | arch/arm/kernel/signal.c | 24 | ||||
-rw-r--r-- | arch/arm/kernel/smp.c | 17 | ||||
-rw-r--r-- | arch/arm/kernel/time.c | 4 | ||||
-rw-r--r-- | arch/arm/kernel/traps.c | 19 |
21 files changed, 543 insertions, 198 deletions
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile index 3a274878412e..8269d8928742 100644 --- a/arch/arm/kernel/Makefile +++ b/arch/arm/kernel/Makefile | |||
@@ -7,6 +7,8 @@ AFLAGS_head.o := -DTEXT_OFFSET=$(TEXT_OFFSET) | |||
7 | 7 | ||
8 | ifdef CONFIG_FUNCTION_TRACER | 8 | ifdef CONFIG_FUNCTION_TRACER |
9 | CFLAGS_REMOVE_ftrace.o = -pg | 9 | CFLAGS_REMOVE_ftrace.o = -pg |
10 | CFLAGS_REMOVE_insn.o = -pg | ||
11 | CFLAGS_REMOVE_patch.o = -pg | ||
10 | endif | 12 | endif |
11 | 13 | ||
12 | CFLAGS_REMOVE_return_address.o = -pg | 14 | CFLAGS_REMOVE_return_address.o = -pg |
@@ -14,8 +16,8 @@ CFLAGS_REMOVE_return_address.o = -pg | |||
14 | # Object file lists. | 16 | # Object file lists. |
15 | 17 | ||
16 | obj-y := elf.o entry-armv.o entry-common.o irq.o opcodes.o \ | 18 | obj-y := elf.o entry-armv.o entry-common.o irq.o opcodes.o \ |
17 | process.o ptrace.o return_address.o setup.o signal.o \ | 19 | process.o ptrace.o return_address.o sched_clock.o \ |
18 | sys_arm.o stacktrace.o time.o traps.o | 20 | setup.o signal.o stacktrace.o sys_arm.o time.o traps.o |
19 | 21 | ||
20 | obj-$(CONFIG_DEPRECATED_PARAM_STRUCT) += compat.o | 22 | obj-$(CONFIG_DEPRECATED_PARAM_STRUCT) += compat.o |
21 | 23 | ||
@@ -29,14 +31,14 @@ obj-$(CONFIG_ARTHUR) += arthur.o | |||
29 | obj-$(CONFIG_ISA_DMA) += dma-isa.o | 31 | obj-$(CONFIG_ISA_DMA) += dma-isa.o |
30 | obj-$(CONFIG_PCI) += bios32.o isa.o | 32 | obj-$(CONFIG_PCI) += bios32.o isa.o |
31 | obj-$(CONFIG_ARM_CPU_SUSPEND) += sleep.o suspend.o | 33 | obj-$(CONFIG_ARM_CPU_SUSPEND) += sleep.o suspend.o |
32 | 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 |
35 | obj-$(CONFIG_HAVE_ARM_TWD) += smp_twd.o | 36 | obj-$(CONFIG_HAVE_ARM_TWD) += smp_twd.o |
36 | obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o | 37 | obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o insn.o |
37 | obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o | 38 | obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o insn.o |
39 | obj-$(CONFIG_JUMP_LABEL) += jump_label.o insn.o patch.o | ||
38 | obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o | 40 | obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o |
39 | obj-$(CONFIG_KPROBES) += kprobes.o kprobes-common.o | 41 | obj-$(CONFIG_KPROBES) += kprobes.o kprobes-common.o patch.o |
40 | ifdef CONFIG_THUMB2_KERNEL | 42 | ifdef CONFIG_THUMB2_KERNEL |
41 | obj-$(CONFIG_KPROBES) += kprobes-thumb.o | 43 | obj-$(CONFIG_KPROBES) += kprobes-thumb.o |
42 | else | 44 | else |
diff --git a/arch/arm/kernel/debug.S b/arch/arm/kernel/debug.S index 204e2160cfcc..e5a765c5f06a 100644 --- a/arch/arm/kernel/debug.S +++ b/arch/arm/kernel/debug.S | |||
@@ -100,7 +100,7 @@ | |||
100 | 100 | ||
101 | #endif /* CONFIG_CPU_V6 */ | 101 | #endif /* CONFIG_CPU_V6 */ |
102 | 102 | ||
103 | #else | 103 | #elif !defined(CONFIG_DEBUG_SEMIHOSTING) |
104 | #include <mach/debug-macro.S> | 104 | #include <mach/debug-macro.S> |
105 | #endif /* CONFIG_DEBUG_ICEDCC */ | 105 | #endif /* CONFIG_DEBUG_ICEDCC */ |
106 | 106 | ||
@@ -155,6 +155,8 @@ hexbuf: .space 16 | |||
155 | 155 | ||
156 | .ltorg | 156 | .ltorg |
157 | 157 | ||
158 | #ifndef CONFIG_DEBUG_SEMIHOSTING | ||
159 | |||
158 | ENTRY(printascii) | 160 | ENTRY(printascii) |
159 | addruart_current r3, r1, r2 | 161 | addruart_current r3, r1, r2 |
160 | b 2f | 162 | b 2f |
@@ -177,3 +179,24 @@ ENTRY(printch) | |||
177 | mov r0, #0 | 179 | mov r0, #0 |
178 | b 1b | 180 | b 1b |
179 | ENDPROC(printch) | 181 | ENDPROC(printch) |
182 | |||
183 | #else | ||
184 | |||
185 | ENTRY(printascii) | ||
186 | mov r1, r0 | ||
187 | mov r0, #0x04 @ SYS_WRITE0 | ||
188 | ARM( svc #0x123456 ) | ||
189 | THUMB( svc #0xab ) | ||
190 | mov pc, lr | ||
191 | ENDPROC(printascii) | ||
192 | |||
193 | ENTRY(printch) | ||
194 | adr r1, hexbuf | ||
195 | strb r0, [r1] | ||
196 | mov r0, #0x03 @ SYS_WRITEC | ||
197 | ARM( svc #0x123456 ) | ||
198 | THUMB( svc #0xab ) | ||
199 | mov pc, lr | ||
200 | ENDPROC(printch) | ||
201 | |||
202 | #endif | ||
diff --git a/arch/arm/kernel/ftrace.c b/arch/arm/kernel/ftrace.c index c0062ad1e847..df0bf0c8cb79 100644 --- a/arch/arm/kernel/ftrace.c +++ b/arch/arm/kernel/ftrace.c | |||
@@ -16,10 +16,13 @@ | |||
16 | #include <linux/uaccess.h> | 16 | #include <linux/uaccess.h> |
17 | 17 | ||
18 | #include <asm/cacheflush.h> | 18 | #include <asm/cacheflush.h> |
19 | #include <asm/opcodes.h> | ||
19 | #include <asm/ftrace.h> | 20 | #include <asm/ftrace.h> |
20 | 21 | ||
22 | #include "insn.h" | ||
23 | |||
21 | #ifdef CONFIG_THUMB2_KERNEL | 24 | #ifdef CONFIG_THUMB2_KERNEL |
22 | #define NOP 0xeb04f85d /* pop.w {lr} */ | 25 | #define NOP 0xf85deb04 /* pop.w {lr} */ |
23 | #else | 26 | #else |
24 | #define NOP 0xe8bd4000 /* pop {lr} */ | 27 | #define NOP 0xe8bd4000 /* pop {lr} */ |
25 | #endif | 28 | #endif |
@@ -60,76 +63,31 @@ static unsigned long adjust_address(struct dyn_ftrace *rec, unsigned long addr) | |||
60 | } | 63 | } |
61 | #endif | 64 | #endif |
62 | 65 | ||
63 | #ifdef CONFIG_THUMB2_KERNEL | ||
64 | static unsigned long ftrace_gen_branch(unsigned long pc, unsigned long addr, | ||
65 | bool link) | ||
66 | { | ||
67 | unsigned long s, j1, j2, i1, i2, imm10, imm11; | ||
68 | unsigned long first, second; | ||
69 | long offset; | ||
70 | |||
71 | offset = (long)addr - (long)(pc + 4); | ||
72 | if (offset < -16777216 || offset > 16777214) { | ||
73 | WARN_ON_ONCE(1); | ||
74 | return 0; | ||
75 | } | ||
76 | |||
77 | s = (offset >> 24) & 0x1; | ||
78 | i1 = (offset >> 23) & 0x1; | ||
79 | i2 = (offset >> 22) & 0x1; | ||
80 | imm10 = (offset >> 12) & 0x3ff; | ||
81 | imm11 = (offset >> 1) & 0x7ff; | ||
82 | |||
83 | j1 = (!i1) ^ s; | ||
84 | j2 = (!i2) ^ s; | ||
85 | |||
86 | first = 0xf000 | (s << 10) | imm10; | ||
87 | second = 0x9000 | (j1 << 13) | (j2 << 11) | imm11; | ||
88 | if (link) | ||
89 | second |= 1 << 14; | ||
90 | |||
91 | return (second << 16) | first; | ||
92 | } | ||
93 | #else | ||
94 | static unsigned long ftrace_gen_branch(unsigned long pc, unsigned long addr, | ||
95 | bool link) | ||
96 | { | ||
97 | unsigned long opcode = 0xea000000; | ||
98 | long offset; | ||
99 | |||
100 | if (link) | ||
101 | opcode |= 1 << 24; | ||
102 | |||
103 | offset = (long)addr - (long)(pc + 8); | ||
104 | if (unlikely(offset < -33554432 || offset > 33554428)) { | ||
105 | /* Can't generate branches that far (from ARM ARM). Ftrace | ||
106 | * doesn't generate branches outside of kernel text. | ||
107 | */ | ||
108 | WARN_ON_ONCE(1); | ||
109 | return 0; | ||
110 | } | ||
111 | |||
112 | offset = (offset >> 2) & 0x00ffffff; | ||
113 | |||
114 | return opcode | offset; | ||
115 | } | ||
116 | #endif | ||
117 | |||
118 | static unsigned long ftrace_call_replace(unsigned long pc, unsigned long addr) | 66 | static unsigned long ftrace_call_replace(unsigned long pc, unsigned long addr) |
119 | { | 67 | { |
120 | return ftrace_gen_branch(pc, addr, true); | 68 | return arm_gen_branch_link(pc, addr); |
121 | } | 69 | } |
122 | 70 | ||
123 | static int ftrace_modify_code(unsigned long pc, unsigned long old, | 71 | static int ftrace_modify_code(unsigned long pc, unsigned long old, |
124 | unsigned long new) | 72 | unsigned long new, bool validate) |
125 | { | 73 | { |
126 | unsigned long replaced; | 74 | unsigned long replaced; |
127 | 75 | ||
128 | if (probe_kernel_read(&replaced, (void *)pc, MCOUNT_INSN_SIZE)) | 76 | if (IS_ENABLED(CONFIG_THUMB2_KERNEL)) { |
129 | return -EFAULT; | 77 | old = __opcode_to_mem_thumb32(old); |
78 | new = __opcode_to_mem_thumb32(new); | ||
79 | } else { | ||
80 | old = __opcode_to_mem_arm(old); | ||
81 | new = __opcode_to_mem_arm(new); | ||
82 | } | ||
130 | 83 | ||
131 | if (replaced != old) | 84 | if (validate) { |
132 | return -EINVAL; | 85 | if (probe_kernel_read(&replaced, (void *)pc, MCOUNT_INSN_SIZE)) |
86 | return -EFAULT; | ||
87 | |||
88 | if (replaced != old) | ||
89 | return -EINVAL; | ||
90 | } | ||
133 | 91 | ||
134 | if (probe_kernel_write((void *)pc, &new, MCOUNT_INSN_SIZE)) | 92 | if (probe_kernel_write((void *)pc, &new, MCOUNT_INSN_SIZE)) |
135 | return -EPERM; | 93 | return -EPERM; |
@@ -141,23 +99,21 @@ static int ftrace_modify_code(unsigned long pc, unsigned long old, | |||
141 | 99 | ||
142 | int ftrace_update_ftrace_func(ftrace_func_t func) | 100 | int ftrace_update_ftrace_func(ftrace_func_t func) |
143 | { | 101 | { |
144 | unsigned long pc, old; | 102 | unsigned long pc; |
145 | unsigned long new; | 103 | unsigned long new; |
146 | int ret; | 104 | int ret; |
147 | 105 | ||
148 | pc = (unsigned long)&ftrace_call; | 106 | pc = (unsigned long)&ftrace_call; |
149 | memcpy(&old, &ftrace_call, MCOUNT_INSN_SIZE); | ||
150 | new = ftrace_call_replace(pc, (unsigned long)func); | 107 | new = ftrace_call_replace(pc, (unsigned long)func); |
151 | 108 | ||
152 | ret = ftrace_modify_code(pc, old, new); | 109 | ret = ftrace_modify_code(pc, 0, new, false); |
153 | 110 | ||
154 | #ifdef CONFIG_OLD_MCOUNT | 111 | #ifdef CONFIG_OLD_MCOUNT |
155 | if (!ret) { | 112 | if (!ret) { |
156 | pc = (unsigned long)&ftrace_call_old; | 113 | pc = (unsigned long)&ftrace_call_old; |
157 | memcpy(&old, &ftrace_call_old, MCOUNT_INSN_SIZE); | ||
158 | new = ftrace_call_replace(pc, (unsigned long)func); | 114 | new = ftrace_call_replace(pc, (unsigned long)func); |
159 | 115 | ||
160 | ret = ftrace_modify_code(pc, old, new); | 116 | ret = ftrace_modify_code(pc, 0, new, false); |
161 | } | 117 | } |
162 | #endif | 118 | #endif |
163 | 119 | ||
@@ -172,7 +128,7 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) | |||
172 | old = ftrace_nop_replace(rec); | 128 | old = ftrace_nop_replace(rec); |
173 | new = ftrace_call_replace(ip, adjust_address(rec, addr)); | 129 | new = ftrace_call_replace(ip, adjust_address(rec, addr)); |
174 | 130 | ||
175 | return ftrace_modify_code(rec->ip, old, new); | 131 | return ftrace_modify_code(rec->ip, old, new, true); |
176 | } | 132 | } |
177 | 133 | ||
178 | int ftrace_make_nop(struct module *mod, | 134 | int ftrace_make_nop(struct module *mod, |
@@ -185,7 +141,7 @@ int ftrace_make_nop(struct module *mod, | |||
185 | 141 | ||
186 | old = ftrace_call_replace(ip, adjust_address(rec, addr)); | 142 | old = ftrace_call_replace(ip, adjust_address(rec, addr)); |
187 | new = ftrace_nop_replace(rec); | 143 | new = ftrace_nop_replace(rec); |
188 | ret = ftrace_modify_code(ip, old, new); | 144 | ret = ftrace_modify_code(ip, old, new, true); |
189 | 145 | ||
190 | #ifdef CONFIG_OLD_MCOUNT | 146 | #ifdef CONFIG_OLD_MCOUNT |
191 | if (ret == -EINVAL && addr == MCOUNT_ADDR) { | 147 | if (ret == -EINVAL && addr == MCOUNT_ADDR) { |
@@ -193,7 +149,7 @@ int ftrace_make_nop(struct module *mod, | |||
193 | 149 | ||
194 | old = ftrace_call_replace(ip, adjust_address(rec, addr)); | 150 | old = ftrace_call_replace(ip, adjust_address(rec, addr)); |
195 | new = ftrace_nop_replace(rec); | 151 | new = ftrace_nop_replace(rec); |
196 | ret = ftrace_modify_code(ip, old, new); | 152 | ret = ftrace_modify_code(ip, old, new, true); |
197 | } | 153 | } |
198 | #endif | 154 | #endif |
199 | 155 | ||
@@ -249,12 +205,12 @@ static int __ftrace_modify_caller(unsigned long *callsite, | |||
249 | { | 205 | { |
250 | unsigned long caller_fn = (unsigned long) func; | 206 | unsigned long caller_fn = (unsigned long) func; |
251 | unsigned long pc = (unsigned long) callsite; | 207 | unsigned long pc = (unsigned long) callsite; |
252 | unsigned long branch = ftrace_gen_branch(pc, caller_fn, false); | 208 | unsigned long branch = arm_gen_branch(pc, caller_fn); |
253 | unsigned long nop = 0xe1a00000; /* mov r0, r0 */ | 209 | unsigned long nop = 0xe1a00000; /* mov r0, r0 */ |
254 | unsigned long old = enable ? nop : branch; | 210 | unsigned long old = enable ? nop : branch; |
255 | unsigned long new = enable ? branch : nop; | 211 | unsigned long new = enable ? branch : nop; |
256 | 212 | ||
257 | return ftrace_modify_code(pc, old, new); | 213 | return ftrace_modify_code(pc, old, new, true); |
258 | } | 214 | } |
259 | 215 | ||
260 | static int ftrace_modify_graph_caller(bool enable) | 216 | static int ftrace_modify_graph_caller(bool enable) |
diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S index a2e9694a68ee..3bf0c7f8b043 100644 --- a/arch/arm/kernel/head.S +++ b/arch/arm/kernel/head.S | |||
@@ -265,7 +265,7 @@ __create_page_tables: | |||
265 | str r6, [r3] | 265 | str r6, [r3] |
266 | 266 | ||
267 | #ifdef CONFIG_DEBUG_LL | 267 | #ifdef CONFIG_DEBUG_LL |
268 | #ifndef CONFIG_DEBUG_ICEDCC | 268 | #if !defined(CONFIG_DEBUG_ICEDCC) && !defined(CONFIG_DEBUG_SEMIHOSTING) |
269 | /* | 269 | /* |
270 | * Map in IO space for serial debugging. | 270 | * Map in IO space for serial debugging. |
271 | * This allows debug messages to be output | 271 | * This allows debug messages to be output |
@@ -297,10 +297,10 @@ __create_page_tables: | |||
297 | cmp r0, r6 | 297 | cmp r0, r6 |
298 | blo 1b | 298 | blo 1b |
299 | 299 | ||
300 | #else /* CONFIG_DEBUG_ICEDCC */ | 300 | #else /* CONFIG_DEBUG_ICEDCC || CONFIG_DEBUG_SEMIHOSTING */ |
301 | /* we don't need any serial debugging mappings for ICEDCC */ | 301 | /* we don't need any serial debugging mappings */ |
302 | ldr r7, [r10, #PROCINFO_IO_MMUFLAGS] @ io_mmuflags | 302 | ldr r7, [r10, #PROCINFO_IO_MMUFLAGS] @ io_mmuflags |
303 | #endif /* !CONFIG_DEBUG_ICEDCC */ | 303 | #endif |
304 | 304 | ||
305 | #if defined(CONFIG_ARCH_NETWINDER) || defined(CONFIG_ARCH_CATS) | 305 | #if defined(CONFIG_ARCH_NETWINDER) || defined(CONFIG_ARCH_CATS) |
306 | /* | 306 | /* |
diff --git a/arch/arm/kernel/insn.c b/arch/arm/kernel/insn.c new file mode 100644 index 000000000000..ab312e516546 --- /dev/null +++ b/arch/arm/kernel/insn.c | |||
@@ -0,0 +1,61 @@ | |||
1 | #include <linux/kernel.h> | ||
2 | #include <asm/opcodes.h> | ||
3 | |||
4 | static unsigned long | ||
5 | __arm_gen_branch_thumb2(unsigned long pc, unsigned long addr, bool link) | ||
6 | { | ||
7 | unsigned long s, j1, j2, i1, i2, imm10, imm11; | ||
8 | unsigned long first, second; | ||
9 | long offset; | ||
10 | |||
11 | offset = (long)addr - (long)(pc + 4); | ||
12 | if (offset < -16777216 || offset > 16777214) { | ||
13 | WARN_ON_ONCE(1); | ||
14 | return 0; | ||
15 | } | ||
16 | |||
17 | s = (offset >> 24) & 0x1; | ||
18 | i1 = (offset >> 23) & 0x1; | ||
19 | i2 = (offset >> 22) & 0x1; | ||
20 | imm10 = (offset >> 12) & 0x3ff; | ||
21 | imm11 = (offset >> 1) & 0x7ff; | ||
22 | |||
23 | j1 = (!i1) ^ s; | ||
24 | j2 = (!i2) ^ s; | ||
25 | |||
26 | first = 0xf000 | (s << 10) | imm10; | ||
27 | second = 0x9000 | (j1 << 13) | (j2 << 11) | imm11; | ||
28 | if (link) | ||
29 | second |= 1 << 14; | ||
30 | |||
31 | return __opcode_thumb32_compose(first, second); | ||
32 | } | ||
33 | |||
34 | static unsigned long | ||
35 | __arm_gen_branch_arm(unsigned long pc, unsigned long addr, bool link) | ||
36 | { | ||
37 | unsigned long opcode = 0xea000000; | ||
38 | long offset; | ||
39 | |||
40 | if (link) | ||
41 | opcode |= 1 << 24; | ||
42 | |||
43 | offset = (long)addr - (long)(pc + 8); | ||
44 | if (unlikely(offset < -33554432 || offset > 33554428)) { | ||
45 | WARN_ON_ONCE(1); | ||
46 | return 0; | ||
47 | } | ||
48 | |||
49 | offset = (offset >> 2) & 0x00ffffff; | ||
50 | |||
51 | return opcode | offset; | ||
52 | } | ||
53 | |||
54 | unsigned long | ||
55 | __arm_gen_branch(unsigned long pc, unsigned long addr, bool link) | ||
56 | { | ||
57 | if (IS_ENABLED(CONFIG_THUMB2_KERNEL)) | ||
58 | return __arm_gen_branch_thumb2(pc, addr, link); | ||
59 | else | ||
60 | return __arm_gen_branch_arm(pc, addr, link); | ||
61 | } | ||
diff --git a/arch/arm/kernel/insn.h b/arch/arm/kernel/insn.h new file mode 100644 index 000000000000..e96065da4dae --- /dev/null +++ b/arch/arm/kernel/insn.h | |||
@@ -0,0 +1,29 @@ | |||
1 | #ifndef __ASM_ARM_INSN_H | ||
2 | #define __ASM_ARM_INSN_H | ||
3 | |||
4 | static inline unsigned long | ||
5 | arm_gen_nop(void) | ||
6 | { | ||
7 | #ifdef CONFIG_THUMB2_KERNEL | ||
8 | return 0xf3af8000; /* nop.w */ | ||
9 | #else | ||
10 | return 0xe1a00000; /* mov r0, r0 */ | ||
11 | #endif | ||
12 | } | ||
13 | |||
14 | unsigned long | ||
15 | __arm_gen_branch(unsigned long pc, unsigned long addr, bool link); | ||
16 | |||
17 | static inline unsigned long | ||
18 | arm_gen_branch(unsigned long pc, unsigned long addr) | ||
19 | { | ||
20 | return __arm_gen_branch(pc, addr, false); | ||
21 | } | ||
22 | |||
23 | static inline unsigned long | ||
24 | arm_gen_branch_link(unsigned long pc, unsigned long addr) | ||
25 | { | ||
26 | return __arm_gen_branch(pc, addr, true); | ||
27 | } | ||
28 | |||
29 | #endif | ||
diff --git a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c index 6a6a097edd61..71ccdbfed662 100644 --- a/arch/arm/kernel/irq.c +++ b/arch/arm/kernel/irq.c | |||
@@ -180,10 +180,7 @@ void migrate_irqs(void) | |||
180 | local_irq_save(flags); | 180 | local_irq_save(flags); |
181 | 181 | ||
182 | for_each_irq_desc(i, desc) { | 182 | for_each_irq_desc(i, desc) { |
183 | bool affinity_broken = false; | 183 | bool affinity_broken; |
184 | |||
185 | if (!desc) | ||
186 | continue; | ||
187 | 184 | ||
188 | raw_spin_lock(&desc->lock); | 185 | raw_spin_lock(&desc->lock); |
189 | affinity_broken = migrate_one_irq(desc); | 186 | affinity_broken = migrate_one_irq(desc); |
diff --git a/arch/arm/kernel/jump_label.c b/arch/arm/kernel/jump_label.c new file mode 100644 index 000000000000..4ce4f789446d --- /dev/null +++ b/arch/arm/kernel/jump_label.c | |||
@@ -0,0 +1,39 @@ | |||
1 | #include <linux/kernel.h> | ||
2 | #include <linux/jump_label.h> | ||
3 | |||
4 | #include "insn.h" | ||
5 | #include "patch.h" | ||
6 | |||
7 | #ifdef HAVE_JUMP_LABEL | ||
8 | |||
9 | static void __arch_jump_label_transform(struct jump_entry *entry, | ||
10 | enum jump_label_type type, | ||
11 | bool is_static) | ||
12 | { | ||
13 | void *addr = (void *)entry->code; | ||
14 | unsigned int insn; | ||
15 | |||
16 | if (type == JUMP_LABEL_ENABLE) | ||
17 | insn = arm_gen_branch(entry->code, entry->target); | ||
18 | else | ||
19 | insn = arm_gen_nop(); | ||
20 | |||
21 | if (is_static) | ||
22 | __patch_text(addr, insn); | ||
23 | else | ||
24 | patch_text(addr, insn); | ||
25 | } | ||
26 | |||
27 | void arch_jump_label_transform(struct jump_entry *entry, | ||
28 | enum jump_label_type type) | ||
29 | { | ||
30 | __arch_jump_label_transform(entry, type, false); | ||
31 | } | ||
32 | |||
33 | void arch_jump_label_transform_static(struct jump_entry *entry, | ||
34 | enum jump_label_type type) | ||
35 | { | ||
36 | __arch_jump_label_transform(entry, type, true); | ||
37 | } | ||
38 | |||
39 | #endif | ||
diff --git a/arch/arm/kernel/kprobes.c b/arch/arm/kernel/kprobes.c index 129c1163248b..ab1869dac97a 100644 --- a/arch/arm/kernel/kprobes.c +++ b/arch/arm/kernel/kprobes.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include <asm/cacheflush.h> | 29 | #include <asm/cacheflush.h> |
30 | 30 | ||
31 | #include "kprobes.h" | 31 | #include "kprobes.h" |
32 | #include "patch.h" | ||
32 | 33 | ||
33 | #define MIN_STACK_SIZE(addr) \ | 34 | #define MIN_STACK_SIZE(addr) \ |
34 | min((unsigned long)MAX_STACK_SIZE, \ | 35 | min((unsigned long)MAX_STACK_SIZE, \ |
@@ -103,57 +104,33 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) | |||
103 | return 0; | 104 | return 0; |
104 | } | 105 | } |
105 | 106 | ||
106 | #ifdef CONFIG_THUMB2_KERNEL | ||
107 | |||
108 | /* | ||
109 | * For a 32-bit Thumb breakpoint spanning two memory words we need to take | ||
110 | * special precautions to insert the breakpoint atomically, especially on SMP | ||
111 | * systems. This is achieved by calling this arming function using stop_machine. | ||
112 | */ | ||
113 | static int __kprobes set_t32_breakpoint(void *addr) | ||
114 | { | ||
115 | ((u16 *)addr)[0] = KPROBE_THUMB32_BREAKPOINT_INSTRUCTION >> 16; | ||
116 | ((u16 *)addr)[1] = KPROBE_THUMB32_BREAKPOINT_INSTRUCTION & 0xffff; | ||
117 | flush_insns(addr, 2*sizeof(u16)); | ||
118 | return 0; | ||
119 | } | ||
120 | |||
121 | void __kprobes arch_arm_kprobe(struct kprobe *p) | 107 | void __kprobes arch_arm_kprobe(struct kprobe *p) |
122 | { | 108 | { |
123 | uintptr_t addr = (uintptr_t)p->addr & ~1; /* Remove any Thumb flag */ | 109 | unsigned int brkp; |
124 | 110 | void *addr; | |
125 | if (!is_wide_instruction(p->opcode)) { | 111 | |
126 | *(u16 *)addr = KPROBE_THUMB16_BREAKPOINT_INSTRUCTION; | 112 | if (IS_ENABLED(CONFIG_THUMB2_KERNEL)) { |
127 | flush_insns(addr, sizeof(u16)); | 113 | /* Remove any Thumb flag */ |
128 | } else if (addr & 2) { | 114 | addr = (void *)((uintptr_t)p->addr & ~1); |
129 | /* A 32-bit instruction spanning two words needs special care */ | 115 | |
130 | stop_machine(set_t32_breakpoint, (void *)addr, &cpu_online_map); | 116 | if (is_wide_instruction(p->opcode)) |
117 | brkp = KPROBE_THUMB32_BREAKPOINT_INSTRUCTION; | ||
118 | else | ||
119 | brkp = KPROBE_THUMB16_BREAKPOINT_INSTRUCTION; | ||
131 | } else { | 120 | } else { |
132 | /* Word aligned 32-bit instruction can be written atomically */ | 121 | kprobe_opcode_t insn = p->opcode; |
133 | u32 bkp = KPROBE_THUMB32_BREAKPOINT_INSTRUCTION; | ||
134 | #ifndef __ARMEB__ /* Swap halfwords for little-endian */ | ||
135 | bkp = (bkp >> 16) | (bkp << 16); | ||
136 | #endif | ||
137 | *(u32 *)addr = bkp; | ||
138 | flush_insns(addr, sizeof(u32)); | ||
139 | } | ||
140 | } | ||
141 | 122 | ||
142 | #else /* !CONFIG_THUMB2_KERNEL */ | 123 | addr = p->addr; |
124 | brkp = KPROBE_ARM_BREAKPOINT_INSTRUCTION; | ||
143 | 125 | ||
144 | void __kprobes arch_arm_kprobe(struct kprobe *p) | 126 | if (insn >= 0xe0000000) |
145 | { | 127 | brkp |= 0xe0000000; /* Unconditional instruction */ |
146 | kprobe_opcode_t insn = p->opcode; | 128 | else |
147 | kprobe_opcode_t brkp = KPROBE_ARM_BREAKPOINT_INSTRUCTION; | 129 | brkp |= insn & 0xf0000000; /* Copy condition from insn */ |
148 | if (insn >= 0xe0000000) | 130 | } |
149 | brkp |= 0xe0000000; /* Unconditional instruction */ | ||
150 | else | ||
151 | brkp |= insn & 0xf0000000; /* Copy condition from insn */ | ||
152 | *p->addr = brkp; | ||
153 | flush_insns(p->addr, sizeof(p->addr[0])); | ||
154 | } | ||
155 | 131 | ||
156 | #endif /* !CONFIG_THUMB2_KERNEL */ | 132 | patch_text(addr, brkp); |
133 | } | ||
157 | 134 | ||
158 | /* | 135 | /* |
159 | * The actual disarming is done here on each CPU and synchronized using | 136 | * The actual disarming is done here on each CPU and synchronized using |
@@ -166,25 +143,10 @@ void __kprobes arch_arm_kprobe(struct kprobe *p) | |||
166 | int __kprobes __arch_disarm_kprobe(void *p) | 143 | int __kprobes __arch_disarm_kprobe(void *p) |
167 | { | 144 | { |
168 | struct kprobe *kp = p; | 145 | struct kprobe *kp = p; |
169 | #ifdef CONFIG_THUMB2_KERNEL | 146 | void *addr = (void *)((uintptr_t)kp->addr & ~1); |
170 | u16 *addr = (u16 *)((uintptr_t)kp->addr & ~1); | ||
171 | kprobe_opcode_t insn = kp->opcode; | ||
172 | unsigned int len; | ||
173 | 147 | ||
174 | if (is_wide_instruction(insn)) { | 148 | __patch_text(addr, kp->opcode); |
175 | ((u16 *)addr)[0] = insn>>16; | ||
176 | ((u16 *)addr)[1] = insn; | ||
177 | len = 2*sizeof(u16); | ||
178 | } else { | ||
179 | ((u16 *)addr)[0] = insn; | ||
180 | len = sizeof(u16); | ||
181 | } | ||
182 | flush_insns(addr, len); | ||
183 | 149 | ||
184 | #else /* !CONFIG_THUMB2_KERNEL */ | ||
185 | *kp->addr = kp->opcode; | ||
186 | flush_insns(kp->addr, sizeof(kp->addr[0])); | ||
187 | #endif | ||
188 | return 0; | 150 | return 0; |
189 | } | 151 | } |
190 | 152 | ||
diff --git a/arch/arm/kernel/machine_kexec.c b/arch/arm/kernel/machine_kexec.c index 56995983eed8..dfcdb9f7c126 100644 --- a/arch/arm/kernel/machine_kexec.c +++ b/arch/arm/kernel/machine_kexec.c | |||
@@ -7,6 +7,7 @@ | |||
7 | #include <linux/delay.h> | 7 | #include <linux/delay.h> |
8 | #include <linux/reboot.h> | 8 | #include <linux/reboot.h> |
9 | #include <linux/io.h> | 9 | #include <linux/io.h> |
10 | #include <linux/irq.h> | ||
10 | #include <asm/pgtable.h> | 11 | #include <asm/pgtable.h> |
11 | #include <asm/pgalloc.h> | 12 | #include <asm/pgalloc.h> |
12 | #include <asm/mmu_context.h> | 13 | #include <asm/mmu_context.h> |
@@ -53,6 +54,29 @@ void machine_crash_nonpanic_core(void *unused) | |||
53 | cpu_relax(); | 54 | cpu_relax(); |
54 | } | 55 | } |
55 | 56 | ||
57 | static void machine_kexec_mask_interrupts(void) | ||
58 | { | ||
59 | unsigned int i; | ||
60 | struct irq_desc *desc; | ||
61 | |||
62 | for_each_irq_desc(i, desc) { | ||
63 | struct irq_chip *chip; | ||
64 | |||
65 | chip = irq_desc_get_chip(desc); | ||
66 | if (!chip) | ||
67 | continue; | ||
68 | |||
69 | if (chip->irq_eoi && irqd_irq_inprogress(&desc->irq_data)) | ||
70 | chip->irq_eoi(&desc->irq_data); | ||
71 | |||
72 | if (chip->irq_mask) | ||
73 | chip->irq_mask(&desc->irq_data); | ||
74 | |||
75 | if (chip->irq_disable && !irqd_irq_disabled(&desc->irq_data)) | ||
76 | chip->irq_disable(&desc->irq_data); | ||
77 | } | ||
78 | } | ||
79 | |||
56 | void machine_crash_shutdown(struct pt_regs *regs) | 80 | void machine_crash_shutdown(struct pt_regs *regs) |
57 | { | 81 | { |
58 | unsigned long msecs; | 82 | unsigned long msecs; |
@@ -70,6 +94,7 @@ void machine_crash_shutdown(struct pt_regs *regs) | |||
70 | printk(KERN_WARNING "Non-crashing CPUs did not react to IPI\n"); | 94 | printk(KERN_WARNING "Non-crashing CPUs did not react to IPI\n"); |
71 | 95 | ||
72 | crash_save_cpu(regs, smp_processor_id()); | 96 | crash_save_cpu(regs, smp_processor_id()); |
97 | machine_kexec_mask_interrupts(); | ||
73 | 98 | ||
74 | printk(KERN_INFO "Loading crashdump kernel...\n"); | 99 | printk(KERN_INFO "Loading crashdump kernel...\n"); |
75 | } | 100 | } |
diff --git a/arch/arm/kernel/patch.c b/arch/arm/kernel/patch.c new file mode 100644 index 000000000000..07314af47733 --- /dev/null +++ b/arch/arm/kernel/patch.c | |||
@@ -0,0 +1,75 @@ | |||
1 | #include <linux/kernel.h> | ||
2 | #include <linux/kprobes.h> | ||
3 | #include <linux/stop_machine.h> | ||
4 | |||
5 | #include <asm/cacheflush.h> | ||
6 | #include <asm/smp_plat.h> | ||
7 | #include <asm/opcodes.h> | ||
8 | |||
9 | #include "patch.h" | ||
10 | |||
11 | struct patch { | ||
12 | void *addr; | ||
13 | unsigned int insn; | ||
14 | }; | ||
15 | |||
16 | void __kprobes __patch_text(void *addr, unsigned int insn) | ||
17 | { | ||
18 | bool thumb2 = IS_ENABLED(CONFIG_THUMB2_KERNEL); | ||
19 | int size; | ||
20 | |||
21 | if (thumb2 && __opcode_is_thumb16(insn)) { | ||
22 | *(u16 *)addr = __opcode_to_mem_thumb16(insn); | ||
23 | size = sizeof(u16); | ||
24 | } else if (thumb2 && ((uintptr_t)addr & 2)) { | ||
25 | u16 first = __opcode_thumb32_first(insn); | ||
26 | u16 second = __opcode_thumb32_second(insn); | ||
27 | u16 *addrh = addr; | ||
28 | |||
29 | addrh[0] = __opcode_to_mem_thumb16(first); | ||
30 | addrh[1] = __opcode_to_mem_thumb16(second); | ||
31 | |||
32 | size = sizeof(u32); | ||
33 | } else { | ||
34 | if (thumb2) | ||
35 | insn = __opcode_to_mem_thumb32(insn); | ||
36 | else | ||
37 | insn = __opcode_to_mem_arm(insn); | ||
38 | |||
39 | *(u32 *)addr = insn; | ||
40 | size = sizeof(u32); | ||
41 | } | ||
42 | |||
43 | flush_icache_range((uintptr_t)(addr), | ||
44 | (uintptr_t)(addr) + size); | ||
45 | } | ||
46 | |||
47 | static int __kprobes patch_text_stop_machine(void *data) | ||
48 | { | ||
49 | struct patch *patch = data; | ||
50 | |||
51 | __patch_text(patch->addr, patch->insn); | ||
52 | |||
53 | return 0; | ||
54 | } | ||
55 | |||
56 | void __kprobes patch_text(void *addr, unsigned int insn) | ||
57 | { | ||
58 | struct patch patch = { | ||
59 | .addr = addr, | ||
60 | .insn = insn, | ||
61 | }; | ||
62 | |||
63 | if (cache_ops_need_broadcast()) { | ||
64 | stop_machine(patch_text_stop_machine, &patch, cpu_online_mask); | ||
65 | } else { | ||
66 | bool straddles_word = IS_ENABLED(CONFIG_THUMB2_KERNEL) | ||
67 | && __opcode_is_thumb32(insn) | ||
68 | && ((uintptr_t)addr & 2); | ||
69 | |||
70 | if (straddles_word) | ||
71 | stop_machine(patch_text_stop_machine, &patch, NULL); | ||
72 | else | ||
73 | __patch_text(addr, insn); | ||
74 | } | ||
75 | } | ||
diff --git a/arch/arm/kernel/patch.h b/arch/arm/kernel/patch.h new file mode 100644 index 000000000000..b4731f2dac38 --- /dev/null +++ b/arch/arm/kernel/patch.h | |||
@@ -0,0 +1,7 @@ | |||
1 | #ifndef _ARM_KERNEL_PATCH_H | ||
2 | #define _ARM_KERNEL_PATCH_H | ||
3 | |||
4 | void patch_text(void *addr, unsigned int insn); | ||
5 | void __patch_text(void *addr, unsigned int insn); | ||
6 | |||
7 | #endif | ||
diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c index 8a89d3b7626b..186c8cb982c5 100644 --- a/arch/arm/kernel/perf_event.c +++ b/arch/arm/kernel/perf_event.c | |||
@@ -738,6 +738,9 @@ init_hw_perf_events(void) | |||
738 | case 0xC0F0: /* Cortex-A15 */ | 738 | case 0xC0F0: /* Cortex-A15 */ |
739 | cpu_pmu = armv7_a15_pmu_init(); | 739 | cpu_pmu = armv7_a15_pmu_init(); |
740 | break; | 740 | break; |
741 | case 0xC070: /* Cortex-A7 */ | ||
742 | cpu_pmu = armv7_a7_pmu_init(); | ||
743 | break; | ||
741 | } | 744 | } |
742 | /* Intel CPUs [xscale]. */ | 745 | /* Intel CPUs [xscale]. */ |
743 | } else if (0x69 == implementor) { | 746 | } else if (0x69 == implementor) { |
diff --git a/arch/arm/kernel/perf_event_v7.c b/arch/arm/kernel/perf_event_v7.c index 4d7095af2ab3..00755d82e2f2 100644 --- a/arch/arm/kernel/perf_event_v7.c +++ b/arch/arm/kernel/perf_event_v7.c | |||
@@ -610,6 +610,130 @@ static const unsigned armv7_a15_perf_cache_map[PERF_COUNT_HW_CACHE_MAX] | |||
610 | }; | 610 | }; |
611 | 611 | ||
612 | /* | 612 | /* |
613 | * Cortex-A7 HW events mapping | ||
614 | */ | ||
615 | static const unsigned armv7_a7_perf_map[PERF_COUNT_HW_MAX] = { | ||
616 | [PERF_COUNT_HW_CPU_CYCLES] = ARMV7_PERFCTR_CPU_CYCLES, | ||
617 | [PERF_COUNT_HW_INSTRUCTIONS] = ARMV7_PERFCTR_INSTR_EXECUTED, | ||
618 | [PERF_COUNT_HW_CACHE_REFERENCES] = ARMV7_PERFCTR_L1_DCACHE_ACCESS, | ||
619 | [PERF_COUNT_HW_CACHE_MISSES] = ARMV7_PERFCTR_L1_DCACHE_REFILL, | ||
620 | [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = ARMV7_PERFCTR_PC_WRITE, | ||
621 | [PERF_COUNT_HW_BRANCH_MISSES] = ARMV7_PERFCTR_PC_BRANCH_MIS_PRED, | ||
622 | [PERF_COUNT_HW_BUS_CYCLES] = ARMV7_PERFCTR_BUS_CYCLES, | ||
623 | [PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] = HW_OP_UNSUPPORTED, | ||
624 | [PERF_COUNT_HW_STALLED_CYCLES_BACKEND] = HW_OP_UNSUPPORTED, | ||
625 | }; | ||
626 | |||
627 | static const unsigned armv7_a7_perf_cache_map[PERF_COUNT_HW_CACHE_MAX] | ||
628 | [PERF_COUNT_HW_CACHE_OP_MAX] | ||
629 | [PERF_COUNT_HW_CACHE_RESULT_MAX] = { | ||
630 | [C(L1D)] = { | ||
631 | /* | ||
632 | * The performance counters don't differentiate between read | ||
633 | * and write accesses/misses so this isn't strictly correct, | ||
634 | * but it's the best we can do. Writes and reads get | ||
635 | * combined. | ||
636 | */ | ||
637 | [C(OP_READ)] = { | ||
638 | [C(RESULT_ACCESS)] = ARMV7_PERFCTR_L1_DCACHE_ACCESS, | ||
639 | [C(RESULT_MISS)] = ARMV7_PERFCTR_L1_DCACHE_REFILL, | ||
640 | }, | ||
641 | [C(OP_WRITE)] = { | ||
642 | [C(RESULT_ACCESS)] = ARMV7_PERFCTR_L1_DCACHE_ACCESS, | ||
643 | [C(RESULT_MISS)] = ARMV7_PERFCTR_L1_DCACHE_REFILL, | ||
644 | }, | ||
645 | [C(OP_PREFETCH)] = { | ||
646 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
647 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
648 | }, | ||
649 | }, | ||
650 | [C(L1I)] = { | ||
651 | [C(OP_READ)] = { | ||
652 | [C(RESULT_ACCESS)] = ARMV7_PERFCTR_L1_ICACHE_ACCESS, | ||
653 | [C(RESULT_MISS)] = ARMV7_PERFCTR_L1_ICACHE_REFILL, | ||
654 | }, | ||
655 | [C(OP_WRITE)] = { | ||
656 | [C(RESULT_ACCESS)] = ARMV7_PERFCTR_L1_ICACHE_ACCESS, | ||
657 | [C(RESULT_MISS)] = ARMV7_PERFCTR_L1_ICACHE_REFILL, | ||
658 | }, | ||
659 | [C(OP_PREFETCH)] = { | ||
660 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
661 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
662 | }, | ||
663 | }, | ||
664 | [C(LL)] = { | ||
665 | [C(OP_READ)] = { | ||
666 | [C(RESULT_ACCESS)] = ARMV7_PERFCTR_L2_CACHE_ACCESS, | ||
667 | [C(RESULT_MISS)] = ARMV7_PERFCTR_L2_CACHE_REFILL, | ||
668 | }, | ||
669 | [C(OP_WRITE)] = { | ||
670 | [C(RESULT_ACCESS)] = ARMV7_PERFCTR_L2_CACHE_ACCESS, | ||
671 | [C(RESULT_MISS)] = ARMV7_PERFCTR_L2_CACHE_REFILL, | ||
672 | }, | ||
673 | [C(OP_PREFETCH)] = { | ||
674 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
675 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
676 | }, | ||
677 | }, | ||
678 | [C(DTLB)] = { | ||
679 | [C(OP_READ)] = { | ||
680 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
681 | [C(RESULT_MISS)] = ARMV7_PERFCTR_DTLB_REFILL, | ||
682 | }, | ||
683 | [C(OP_WRITE)] = { | ||
684 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
685 | [C(RESULT_MISS)] = ARMV7_PERFCTR_DTLB_REFILL, | ||
686 | }, | ||
687 | [C(OP_PREFETCH)] = { | ||
688 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
689 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
690 | }, | ||
691 | }, | ||
692 | [C(ITLB)] = { | ||
693 | [C(OP_READ)] = { | ||
694 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
695 | [C(RESULT_MISS)] = ARMV7_PERFCTR_ITLB_REFILL, | ||
696 | }, | ||
697 | [C(OP_WRITE)] = { | ||
698 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
699 | [C(RESULT_MISS)] = ARMV7_PERFCTR_ITLB_REFILL, | ||
700 | }, | ||
701 | [C(OP_PREFETCH)] = { | ||
702 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
703 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
704 | }, | ||
705 | }, | ||
706 | [C(BPU)] = { | ||
707 | [C(OP_READ)] = { | ||
708 | [C(RESULT_ACCESS)] = ARMV7_PERFCTR_PC_BRANCH_PRED, | ||
709 | [C(RESULT_MISS)] = ARMV7_PERFCTR_PC_BRANCH_MIS_PRED, | ||
710 | }, | ||
711 | [C(OP_WRITE)] = { | ||
712 | [C(RESULT_ACCESS)] = ARMV7_PERFCTR_PC_BRANCH_PRED, | ||
713 | [C(RESULT_MISS)] = ARMV7_PERFCTR_PC_BRANCH_MIS_PRED, | ||
714 | }, | ||
715 | [C(OP_PREFETCH)] = { | ||
716 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
717 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
718 | }, | ||
719 | }, | ||
720 | [C(NODE)] = { | ||
721 | [C(OP_READ)] = { | ||
722 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
723 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
724 | }, | ||
725 | [C(OP_WRITE)] = { | ||
726 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
727 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
728 | }, | ||
729 | [C(OP_PREFETCH)] = { | ||
730 | [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, | ||
731 | [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, | ||
732 | }, | ||
733 | }, | ||
734 | }; | ||
735 | |||
736 | /* | ||
613 | * Perf Events' indices | 737 | * Perf Events' indices |
614 | */ | 738 | */ |
615 | #define ARMV7_IDX_CYCLE_COUNTER 0 | 739 | #define ARMV7_IDX_CYCLE_COUNTER 0 |
@@ -1104,6 +1228,12 @@ static int armv7_a15_map_event(struct perf_event *event) | |||
1104 | &armv7_a15_perf_cache_map, 0xFF); | 1228 | &armv7_a15_perf_cache_map, 0xFF); |
1105 | } | 1229 | } |
1106 | 1230 | ||
1231 | static int armv7_a7_map_event(struct perf_event *event) | ||
1232 | { | ||
1233 | return map_cpu_event(event, &armv7_a7_perf_map, | ||
1234 | &armv7_a7_perf_cache_map, 0xFF); | ||
1235 | } | ||
1236 | |||
1107 | static struct arm_pmu armv7pmu = { | 1237 | static struct arm_pmu armv7pmu = { |
1108 | .handle_irq = armv7pmu_handle_irq, | 1238 | .handle_irq = armv7pmu_handle_irq, |
1109 | .enable = armv7pmu_enable_event, | 1239 | .enable = armv7pmu_enable_event, |
@@ -1164,6 +1294,16 @@ static struct arm_pmu *__init armv7_a15_pmu_init(void) | |||
1164 | armv7pmu.set_event_filter = armv7pmu_set_event_filter; | 1294 | armv7pmu.set_event_filter = armv7pmu_set_event_filter; |
1165 | return &armv7pmu; | 1295 | return &armv7pmu; |
1166 | } | 1296 | } |
1297 | |||
1298 | static struct arm_pmu *__init armv7_a7_pmu_init(void) | ||
1299 | { | ||
1300 | armv7pmu.id = ARM_PERF_PMU_ID_CA7; | ||
1301 | armv7pmu.name = "ARMv7 Cortex-A7"; | ||
1302 | armv7pmu.map_event = armv7_a7_map_event; | ||
1303 | armv7pmu.num_events = armv7_read_num_pmnc_events(); | ||
1304 | armv7pmu.set_event_filter = armv7pmu_set_event_filter; | ||
1305 | return &armv7pmu; | ||
1306 | } | ||
1167 | #else | 1307 | #else |
1168 | static struct arm_pmu *__init armv7_a8_pmu_init(void) | 1308 | static struct arm_pmu *__init armv7_a8_pmu_init(void) |
1169 | { | 1309 | { |
@@ -1184,4 +1324,9 @@ static struct arm_pmu *__init armv7_a15_pmu_init(void) | |||
1184 | { | 1324 | { |
1185 | return NULL; | 1325 | return NULL; |
1186 | } | 1326 | } |
1327 | |||
1328 | static struct arm_pmu *__init armv7_a7_pmu_init(void) | ||
1329 | { | ||
1330 | return NULL; | ||
1331 | } | ||
1187 | #endif /* CONFIG_CPU_V7 */ | 1332 | #endif /* CONFIG_CPU_V7 */ |
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c index 7b9cddef6e53..2b7b017a20cd 100644 --- a/arch/arm/kernel/process.c +++ b/arch/arm/kernel/process.c | |||
@@ -528,21 +528,39 @@ unsigned long arch_randomize_brk(struct mm_struct *mm) | |||
528 | #ifdef CONFIG_MMU | 528 | #ifdef CONFIG_MMU |
529 | /* | 529 | /* |
530 | * The vectors page is always readable from user space for the | 530 | * The vectors page is always readable from user space for the |
531 | * atomic helpers and the signal restart code. Let's declare a mapping | 531 | * atomic helpers and the signal restart code. Insert it into the |
532 | * for it so it is visible through ptrace and /proc/<pid>/mem. | 532 | * gate_vma so that it is visible through ptrace and /proc/<pid>/mem. |
533 | */ | 533 | */ |
534 | static struct vm_area_struct gate_vma; | ||
534 | 535 | ||
535 | int vectors_user_mapping(void) | 536 | static int __init gate_vma_init(void) |
536 | { | 537 | { |
537 | struct mm_struct *mm = current->mm; | 538 | gate_vma.vm_start = 0xffff0000; |
538 | return install_special_mapping(mm, 0xffff0000, PAGE_SIZE, | 539 | gate_vma.vm_end = 0xffff0000 + PAGE_SIZE; |
539 | VM_READ | VM_EXEC | | 540 | gate_vma.vm_page_prot = PAGE_READONLY_EXEC; |
540 | VM_MAYREAD | VM_MAYEXEC | VM_RESERVED, | 541 | gate_vma.vm_flags = VM_READ | VM_EXEC | |
541 | NULL); | 542 | VM_MAYREAD | VM_MAYEXEC; |
543 | return 0; | ||
544 | } | ||
545 | arch_initcall(gate_vma_init); | ||
546 | |||
547 | struct vm_area_struct *get_gate_vma(struct mm_struct *mm) | ||
548 | { | ||
549 | return &gate_vma; | ||
550 | } | ||
551 | |||
552 | int in_gate_area(struct mm_struct *mm, unsigned long addr) | ||
553 | { | ||
554 | return (addr >= gate_vma.vm_start) && (addr < gate_vma.vm_end); | ||
555 | } | ||
556 | |||
557 | int in_gate_area_no_mm(unsigned long addr) | ||
558 | { | ||
559 | return in_gate_area(NULL, addr); | ||
542 | } | 560 | } |
543 | 561 | ||
544 | const char *arch_vma_name(struct vm_area_struct *vma) | 562 | const char *arch_vma_name(struct vm_area_struct *vma) |
545 | { | 563 | { |
546 | return (vma->vm_start == 0xffff0000) ? "[vectors]" : NULL; | 564 | return (vma == &gate_vma) ? "[vectors]" : NULL; |
547 | } | 565 | } |
548 | #endif | 566 | #endif |
diff --git a/arch/arm/kernel/sched_clock.c b/arch/arm/kernel/sched_clock.c index 5416c7c12528..27d186abbc06 100644 --- a/arch/arm/kernel/sched_clock.c +++ b/arch/arm/kernel/sched_clock.c | |||
@@ -10,6 +10,7 @@ | |||
10 | #include <linux/jiffies.h> | 10 | #include <linux/jiffies.h> |
11 | #include <linux/kernel.h> | 11 | #include <linux/kernel.h> |
12 | #include <linux/sched.h> | 12 | #include <linux/sched.h> |
13 | #include <linux/syscore_ops.h> | ||
13 | #include <linux/timer.h> | 14 | #include <linux/timer.h> |
14 | 15 | ||
15 | #include <asm/sched_clock.h> | 16 | #include <asm/sched_clock.h> |
@@ -164,3 +165,20 @@ void __init sched_clock_postinit(void) | |||
164 | 165 | ||
165 | sched_clock_poll(sched_clock_timer.data); | 166 | sched_clock_poll(sched_clock_timer.data); |
166 | } | 167 | } |
168 | |||
169 | static int sched_clock_suspend(void) | ||
170 | { | ||
171 | sched_clock_poll(sched_clock_timer.data); | ||
172 | return 0; | ||
173 | } | ||
174 | |||
175 | static struct syscore_ops sched_clock_ops = { | ||
176 | .suspend = sched_clock_suspend, | ||
177 | }; | ||
178 | |||
179 | static int __init sched_clock_syscore_init(void) | ||
180 | { | ||
181 | register_syscore_ops(&sched_clock_ops); | ||
182 | return 0; | ||
183 | } | ||
184 | device_initcall(sched_clock_syscore_init); | ||
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c index 9e0fdb3a1988..b91411371ae1 100644 --- a/arch/arm/kernel/setup.c +++ b/arch/arm/kernel/setup.c | |||
@@ -976,7 +976,6 @@ void __init setup_arch(char **cmdline_p) | |||
976 | conswitchp = &dummy_con; | 976 | conswitchp = &dummy_con; |
977 | #endif | 977 | #endif |
978 | #endif | 978 | #endif |
979 | early_trap_init(); | ||
980 | 979 | ||
981 | if (mdesc->init_early) | 980 | if (mdesc->init_early) |
982 | mdesc->init_early(); | 981 | mdesc->init_early(); |
diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c index 9e617bd4a146..7cb532fc8aa4 100644 --- a/arch/arm/kernel/signal.c +++ b/arch/arm/kernel/signal.c | |||
@@ -66,12 +66,13 @@ const unsigned long syscall_restart_code[2] = { | |||
66 | */ | 66 | */ |
67 | asmlinkage int sys_sigsuspend(int restart, unsigned long oldmask, old_sigset_t mask) | 67 | asmlinkage int sys_sigsuspend(int restart, unsigned long oldmask, old_sigset_t mask) |
68 | { | 68 | { |
69 | mask &= _BLOCKABLE; | 69 | sigset_t blocked; |
70 | spin_lock_irq(¤t->sighand->siglock); | 70 | |
71 | current->saved_sigmask = current->blocked; | 71 | current->saved_sigmask = current->blocked; |
72 | siginitset(¤t->blocked, mask); | 72 | |
73 | recalc_sigpending(); | 73 | mask &= _BLOCKABLE; |
74 | spin_unlock_irq(¤t->sighand->siglock); | 74 | siginitset(&blocked, mask); |
75 | set_current_blocked(&blocked); | ||
75 | 76 | ||
76 | current->state = TASK_INTERRUPTIBLE; | 77 | current->state = TASK_INTERRUPTIBLE; |
77 | schedule(); | 78 | schedule(); |
@@ -280,10 +281,7 @@ static int restore_sigframe(struct pt_regs *regs, struct sigframe __user *sf) | |||
280 | err = __copy_from_user(&set, &sf->uc.uc_sigmask, sizeof(set)); | 281 | err = __copy_from_user(&set, &sf->uc.uc_sigmask, sizeof(set)); |
281 | if (err == 0) { | 282 | if (err == 0) { |
282 | sigdelsetmask(&set, ~_BLOCKABLE); | 283 | sigdelsetmask(&set, ~_BLOCKABLE); |
283 | spin_lock_irq(¤t->sighand->siglock); | 284 | set_current_blocked(&set); |
284 | current->blocked = set; | ||
285 | recalc_sigpending(); | ||
286 | spin_unlock_irq(¤t->sighand->siglock); | ||
287 | } | 285 | } |
288 | 286 | ||
289 | __get_user_error(regs->ARM_r0, &sf->uc.uc_mcontext.arm_r0, err); | 287 | __get_user_error(regs->ARM_r0, &sf->uc.uc_mcontext.arm_r0, err); |
@@ -636,13 +634,7 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, | |||
636 | /* | 634 | /* |
637 | * Block the signal if we were successful. | 635 | * Block the signal if we were successful. |
638 | */ | 636 | */ |
639 | spin_lock_irq(&tsk->sighand->siglock); | 637 | block_sigmask(ka, sig); |
640 | sigorsets(&tsk->blocked, &tsk->blocked, | ||
641 | &ka->sa.sa_mask); | ||
642 | if (!(ka->sa.sa_flags & SA_NODEFER)) | ||
643 | sigaddset(&tsk->blocked, sig); | ||
644 | recalc_sigpending(); | ||
645 | spin_unlock_irq(&tsk->sighand->siglock); | ||
646 | 638 | ||
647 | return 0; | 639 | return 0; |
648 | } | 640 | } |
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index 8f8cce2c46c4..2cee7d1eb958 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c | |||
@@ -58,6 +58,8 @@ enum ipi_msg_type { | |||
58 | IPI_CPU_STOP, | 58 | IPI_CPU_STOP, |
59 | }; | 59 | }; |
60 | 60 | ||
61 | static DECLARE_COMPLETION(cpu_running); | ||
62 | |||
61 | int __cpuinit __cpu_up(unsigned int cpu) | 63 | int __cpuinit __cpu_up(unsigned int cpu) |
62 | { | 64 | { |
63 | struct cpuinfo_arm *ci = &per_cpu(cpu_data, cpu); | 65 | struct cpuinfo_arm *ci = &per_cpu(cpu_data, cpu); |
@@ -98,20 +100,12 @@ int __cpuinit __cpu_up(unsigned int cpu) | |||
98 | */ | 100 | */ |
99 | ret = boot_secondary(cpu, idle); | 101 | ret = boot_secondary(cpu, idle); |
100 | if (ret == 0) { | 102 | if (ret == 0) { |
101 | unsigned long timeout; | ||
102 | |||
103 | /* | 103 | /* |
104 | * CPU was successfully started, wait for it | 104 | * CPU was successfully started, wait for it |
105 | * to come online or time out. | 105 | * to come online or time out. |
106 | */ | 106 | */ |
107 | timeout = jiffies + HZ; | 107 | wait_for_completion_timeout(&cpu_running, |
108 | while (time_before(jiffies, timeout)) { | 108 | msecs_to_jiffies(1000)); |
109 | if (cpu_online(cpu)) | ||
110 | break; | ||
111 | |||
112 | udelay(10); | ||
113 | barrier(); | ||
114 | } | ||
115 | 109 | ||
116 | if (!cpu_online(cpu)) { | 110 | if (!cpu_online(cpu)) { |
117 | pr_crit("CPU%u: failed to come online\n", cpu); | 111 | pr_crit("CPU%u: failed to come online\n", cpu); |
@@ -288,9 +282,10 @@ asmlinkage void __cpuinit secondary_start_kernel(void) | |||
288 | /* | 282 | /* |
289 | * OK, now it's safe to let the boot CPU continue. Wait for | 283 | * OK, now it's safe to let the boot CPU continue. Wait for |
290 | * the CPU migration code to notice that the CPU is online | 284 | * the CPU migration code to notice that the CPU is online |
291 | * before we continue. | 285 | * before we continue - which happens after __cpu_up returns. |
292 | */ | 286 | */ |
293 | set_cpu_online(cpu, true); | 287 | set_cpu_online(cpu, true); |
288 | complete(&cpu_running); | ||
294 | 289 | ||
295 | /* | 290 | /* |
296 | * Setup the percpu timer for this CPU. | 291 | * Setup the percpu timer for this CPU. |
diff --git a/arch/arm/kernel/time.c b/arch/arm/kernel/time.c index 8c57dd3680e9..fe31b22f18fd 100644 --- a/arch/arm/kernel/time.c +++ b/arch/arm/kernel/time.c | |||
@@ -25,8 +25,6 @@ | |||
25 | #include <linux/timer.h> | 25 | #include <linux/timer.h> |
26 | #include <linux/irq.h> | 26 | #include <linux/irq.h> |
27 | 27 | ||
28 | #include <linux/mc146818rtc.h> | ||
29 | |||
30 | #include <asm/leds.h> | 28 | #include <asm/leds.h> |
31 | #include <asm/thread_info.h> | 29 | #include <asm/thread_info.h> |
32 | #include <asm/sched_clock.h> | 30 | #include <asm/sched_clock.h> |
@@ -149,8 +147,6 @@ void __init time_init(void) | |||
149 | { | 147 | { |
150 | system_timer = machine_desc->timer; | 148 | system_timer = machine_desc->timer; |
151 | system_timer->init(); | 149 | system_timer->init(); |
152 | #ifdef CONFIG_HAVE_SCHED_CLOCK | ||
153 | sched_clock_postinit(); | 150 | sched_clock_postinit(); |
154 | #endif | ||
155 | } | 151 | } |
156 | 152 | ||
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index cd77743472a2..778454750a6c 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c | |||
@@ -227,6 +227,11 @@ void show_stack(struct task_struct *tsk, unsigned long *sp) | |||
227 | #else | 227 | #else |
228 | #define S_SMP "" | 228 | #define S_SMP "" |
229 | #endif | 229 | #endif |
230 | #ifdef CONFIG_THUMB2_KERNEL | ||
231 | #define S_ISA " THUMB2" | ||
232 | #else | ||
233 | #define S_ISA " ARM" | ||
234 | #endif | ||
230 | 235 | ||
231 | static int __die(const char *str, int err, struct thread_info *thread, struct pt_regs *regs) | 236 | static int __die(const char *str, int err, struct thread_info *thread, struct pt_regs *regs) |
232 | { | 237 | { |
@@ -234,8 +239,8 @@ static int __die(const char *str, int err, struct thread_info *thread, struct pt | |||
234 | static int die_counter; | 239 | static int die_counter; |
235 | int ret; | 240 | int ret; |
236 | 241 | ||
237 | printk(KERN_EMERG "Internal error: %s: %x [#%d]" S_PREEMPT S_SMP "\n", | 242 | printk(KERN_EMERG "Internal error: %s: %x [#%d]" S_PREEMPT S_SMP |
238 | str, err, ++die_counter); | 243 | S_ISA "\n", str, err, ++die_counter); |
239 | 244 | ||
240 | /* trap and error numbers are mostly meaningless on ARM */ | 245 | /* trap and error numbers are mostly meaningless on ARM */ |
241 | ret = notify_die(DIE_OOPS, str, regs, err, tsk->thread.trap_no, SIGSEGV); | 246 | ret = notify_die(DIE_OOPS, str, regs, err, tsk->thread.trap_no, SIGSEGV); |
@@ -784,18 +789,16 @@ static void __init kuser_get_tls_init(unsigned long vectors) | |||
784 | memcpy((void *)vectors + 0xfe0, (void *)vectors + 0xfe8, 4); | 789 | memcpy((void *)vectors + 0xfe0, (void *)vectors + 0xfe8, 4); |
785 | } | 790 | } |
786 | 791 | ||
787 | void __init early_trap_init(void) | 792 | void __init early_trap_init(void *vectors_base) |
788 | { | 793 | { |
789 | #if defined(CONFIG_CPU_USE_DOMAINS) | 794 | unsigned long vectors = (unsigned long)vectors_base; |
790 | unsigned long vectors = CONFIG_VECTORS_BASE; | ||
791 | #else | ||
792 | unsigned long vectors = (unsigned long)vectors_page; | ||
793 | #endif | ||
794 | extern char __stubs_start[], __stubs_end[]; | 795 | extern char __stubs_start[], __stubs_end[]; |
795 | extern char __vectors_start[], __vectors_end[]; | 796 | extern char __vectors_start[], __vectors_end[]; |
796 | extern char __kuser_helper_start[], __kuser_helper_end[]; | 797 | extern char __kuser_helper_start[], __kuser_helper_end[]; |
797 | int kuser_sz = __kuser_helper_end - __kuser_helper_start; | 798 | int kuser_sz = __kuser_helper_end - __kuser_helper_start; |
798 | 799 | ||
800 | vectors_page = vectors_base; | ||
801 | |||
799 | /* | 802 | /* |
800 | * Copy the vectors, stubs and kuser helpers (in entry-armv.S) | 803 | * Copy the vectors, stubs and kuser helpers (in entry-armv.S) |
801 | * into the vector page, mapped at 0xffff0000, and ensure these | 804 | * into the vector page, mapped at 0xffff0000, and ensure these |