diff options
-rw-r--r-- | arch/blackfin/kernel/Makefile | 3 | ||||
-rw-r--r-- | arch/blackfin/kernel/fixed_code.S | 132 | ||||
-rw-r--r-- | arch/blackfin/kernel/process.c | 65 | ||||
-rw-r--r-- | arch/blackfin/kernel/setup.c | 22 | ||||
-rw-r--r-- | arch/blackfin/mach-common/entry.S | 4 | ||||
-rw-r--r-- | include/asm-blackfin/Kbuild | 2 | ||||
-rw-r--r-- | include/asm-blackfin/bfin-global.h | 12 | ||||
-rw-r--r-- | include/asm-blackfin/cplbinit.h | 4 | ||||
-rw-r--r-- | include/asm-blackfin/fixed_code.h | 20 |
9 files changed, 261 insertions, 3 deletions
diff --git a/arch/blackfin/kernel/Makefile b/arch/blackfin/kernel/Makefile index 93d21406cade..b7b6de824011 100644 --- a/arch/blackfin/kernel/Makefile +++ b/arch/blackfin/kernel/Makefile | |||
@@ -6,7 +6,8 @@ extra-y := init_task.o vmlinux.lds | |||
6 | 6 | ||
7 | obj-y := \ | 7 | obj-y := \ |
8 | entry.o process.o bfin_ksyms.o ptrace.o setup.o signal.o \ | 8 | entry.o process.o bfin_ksyms.o ptrace.o setup.o signal.o \ |
9 | sys_bfin.o time.o traps.o irqchip.o dma-mapping.o flat.o | 9 | sys_bfin.o time.o traps.o irqchip.o dma-mapping.o flat.o \ |
10 | fixed_code.o | ||
10 | 11 | ||
11 | obj-$(CONFIG_BF53x) += bfin_gpio.o | 12 | obj-$(CONFIG_BF53x) += bfin_gpio.o |
12 | obj-$(CONFIG_BF561) += bfin_gpio.o | 13 | obj-$(CONFIG_BF561) += bfin_gpio.o |
diff --git a/arch/blackfin/kernel/fixed_code.S b/arch/blackfin/kernel/fixed_code.S new file mode 100644 index 000000000000..99ea296c82c7 --- /dev/null +++ b/arch/blackfin/kernel/fixed_code.S | |||
@@ -0,0 +1,132 @@ | |||
1 | /* | ||
2 | * This file contains sequences of code that will be copied to a | ||
3 | * fixed location, defined in <asm/atomic_seq.h>. The interrupt | ||
4 | * handlers ensure that these sequences appear to be atomic when | ||
5 | * executed from userspace. | ||
6 | * These are aligned to 16 bytes, so that we have some space to replace | ||
7 | * these sequences with something else (e.g. kernel traps if we ever do | ||
8 | * BF561 SMP). | ||
9 | */ | ||
10 | #include <linux/linkage.h> | ||
11 | #include <asm/entry.h> | ||
12 | #include <asm/unistd.h> | ||
13 | |||
14 | .text | ||
15 | ENTRY(_fixed_code_start) | ||
16 | |||
17 | .align 16 | ||
18 | ENTRY(_sigreturn_stub) | ||
19 | P0 = __NR_rt_sigreturn; | ||
20 | EXCPT 0; | ||
21 | /* Speculative execution paranoia. */ | ||
22 | 0: JUMP.S 0b; | ||
23 | ENDPROC (_sigreturn_stub) | ||
24 | |||
25 | .align 16 | ||
26 | /* | ||
27 | * Atomic swap, 8 bit. | ||
28 | * Inputs: P0: memory address to use | ||
29 | * R1: value to store | ||
30 | * Output: R0: old contents of the memory address, zero extended. | ||
31 | */ | ||
32 | ENTRY(_atomic_xchg32) | ||
33 | R0 = [P0]; | ||
34 | [P0] = R1; | ||
35 | rts; | ||
36 | ENDPROC (_atomic_xchg32) | ||
37 | |||
38 | .align 16 | ||
39 | /* | ||
40 | * Compare and swap, 32 bit. | ||
41 | * Inputs: P0: memory address to use | ||
42 | * R1: compare value | ||
43 | * R2: new value to store | ||
44 | * The new value is stored if the contents of the memory | ||
45 | * address is equal to the compare value. | ||
46 | * Output: R0: old contents of the memory address. | ||
47 | */ | ||
48 | ENTRY(_atomic_cas32) | ||
49 | R0 = [P0]; | ||
50 | CC = R0 == R1; | ||
51 | IF !CC JUMP 1f; | ||
52 | [P0] = R2; | ||
53 | 1: | ||
54 | rts; | ||
55 | ENDPROC (_atomic_cas32) | ||
56 | |||
57 | .align 16 | ||
58 | /* | ||
59 | * Atomic add, 32 bit. | ||
60 | * Inputs: P0: memory address to use | ||
61 | * R0: value to add | ||
62 | * Outputs: R0: new contents of the memory address. | ||
63 | * R1: previous contents of the memory address. | ||
64 | */ | ||
65 | ENTRY(_atomic_add32) | ||
66 | R1 = [P0]; | ||
67 | R0 = R1 + R0; | ||
68 | [P0] = R0; | ||
69 | rts; | ||
70 | ENDPROC (_atomic_add32) | ||
71 | |||
72 | .align 16 | ||
73 | /* | ||
74 | * Atomic sub, 32 bit. | ||
75 | * Inputs: P0: memory address to use | ||
76 | * R0: value to subtract | ||
77 | * Outputs: R0: new contents of the memory address. | ||
78 | * R1: previous contents of the memory address. | ||
79 | */ | ||
80 | ENTRY(_atomic_sub32) | ||
81 | R1 = [P0]; | ||
82 | R0 = R1 - R0; | ||
83 | [P0] = R0; | ||
84 | rts; | ||
85 | ENDPROC (_atomic_sub32) | ||
86 | |||
87 | .align 16 | ||
88 | /* | ||
89 | * Atomic ior, 32 bit. | ||
90 | * Inputs: P0: memory address to use | ||
91 | * R0: value to ior | ||
92 | * Outputs: R0: new contents of the memory address. | ||
93 | * R1: previous contents of the memory address. | ||
94 | */ | ||
95 | ENTRY(_atomic_ior32) | ||
96 | R1 = [P0]; | ||
97 | R0 = R1 | R0; | ||
98 | [P0] = R0; | ||
99 | rts; | ||
100 | ENDPROC (_atomic_ior32) | ||
101 | |||
102 | .align 16 | ||
103 | /* | ||
104 | * Atomic ior, 32 bit. | ||
105 | * Inputs: P0: memory address to use | ||
106 | * R0: value to ior | ||
107 | * Outputs: R0: new contents of the memory address. | ||
108 | * R1: previous contents of the memory address. | ||
109 | */ | ||
110 | ENTRY(_atomic_and32) | ||
111 | R1 = [P0]; | ||
112 | R0 = R1 & R0; | ||
113 | [P0] = R0; | ||
114 | rts; | ||
115 | ENDPROC (_atomic_ior32) | ||
116 | |||
117 | .align 16 | ||
118 | /* | ||
119 | * Atomic ior, 32 bit. | ||
120 | * Inputs: P0: memory address to use | ||
121 | * R0: value to ior | ||
122 | * Outputs: R0: new contents of the memory address. | ||
123 | * R1: previous contents of the memory address. | ||
124 | */ | ||
125 | ENTRY(_atomic_xor32) | ||
126 | R1 = [P0]; | ||
127 | R0 = R1 ^ R0; | ||
128 | [P0] = R0; | ||
129 | rts; | ||
130 | ENDPROC (_atomic_ior32) | ||
131 | |||
132 | ENTRY(_fixed_code_end) | ||
diff --git a/arch/blackfin/kernel/process.c b/arch/blackfin/kernel/process.c index 3eff7439d8d3..6b7a94ab96c2 100644 --- a/arch/blackfin/kernel/process.c +++ b/arch/blackfin/kernel/process.c | |||
@@ -35,6 +35,7 @@ | |||
35 | 35 | ||
36 | #include <asm/blackfin.h> | 36 | #include <asm/blackfin.h> |
37 | #include <asm/uaccess.h> | 37 | #include <asm/uaccess.h> |
38 | #include <asm/fixed_code.h> | ||
38 | 39 | ||
39 | #define LED_ON 0 | 40 | #define LED_ON 0 |
40 | #define LED_OFF 1 | 41 | #define LED_OFF 1 |
@@ -350,6 +351,70 @@ unsigned long get_wchan(struct task_struct *p) | |||
350 | return 0; | 351 | return 0; |
351 | } | 352 | } |
352 | 353 | ||
354 | void finish_atomic_sections (struct pt_regs *regs) | ||
355 | { | ||
356 | if (regs->pc < ATOMIC_SEQS_START || regs->pc >= ATOMIC_SEQS_END) | ||
357 | return; | ||
358 | |||
359 | switch (regs->pc) { | ||
360 | case ATOMIC_XCHG32 + 2: | ||
361 | put_user(regs->r1, (int *)regs->p0); | ||
362 | regs->pc += 2; | ||
363 | break; | ||
364 | |||
365 | case ATOMIC_CAS32 + 2: | ||
366 | case ATOMIC_CAS32 + 4: | ||
367 | if (regs->r0 == regs->r1) | ||
368 | put_user(regs->r2, (int *)regs->p0); | ||
369 | regs->pc = ATOMIC_CAS32 + 8; | ||
370 | break; | ||
371 | case ATOMIC_CAS32 + 6: | ||
372 | put_user(regs->r2, (int *)regs->p0); | ||
373 | regs->pc += 2; | ||
374 | break; | ||
375 | |||
376 | case ATOMIC_ADD32 + 2: | ||
377 | regs->r0 = regs->r1 + regs->r0; | ||
378 | /* fall through */ | ||
379 | case ATOMIC_ADD32 + 4: | ||
380 | put_user(regs->r0, (int *)regs->p0); | ||
381 | regs->pc = ATOMIC_ADD32 + 6; | ||
382 | break; | ||
383 | |||
384 | case ATOMIC_SUB32 + 2: | ||
385 | regs->r0 = regs->r1 - regs->r0; | ||
386 | /* fall through */ | ||
387 | case ATOMIC_SUB32 + 4: | ||
388 | put_user(regs->r0, (int *)regs->p0); | ||
389 | regs->pc = ATOMIC_SUB32 + 6; | ||
390 | break; | ||
391 | |||
392 | case ATOMIC_IOR32 + 2: | ||
393 | regs->r0 = regs->r1 | regs->r0; | ||
394 | /* fall through */ | ||
395 | case ATOMIC_IOR32 + 4: | ||
396 | put_user(regs->r0, (int *)regs->p0); | ||
397 | regs->pc = ATOMIC_IOR32 + 6; | ||
398 | break; | ||
399 | |||
400 | case ATOMIC_AND32 + 2: | ||
401 | regs->r0 = regs->r1 & regs->r0; | ||
402 | /* fall through */ | ||
403 | case ATOMIC_AND32 + 4: | ||
404 | put_user(regs->r0, (int *)regs->p0); | ||
405 | regs->pc = ATOMIC_AND32 + 6; | ||
406 | break; | ||
407 | |||
408 | case ATOMIC_XOR32 + 2: | ||
409 | regs->r0 = regs->r1 ^ regs->r0; | ||
410 | /* fall through */ | ||
411 | case ATOMIC_XOR32 + 4: | ||
412 | put_user(regs->r0, (int *)regs->p0); | ||
413 | regs->pc = ATOMIC_XOR32 + 6; | ||
414 | break; | ||
415 | } | ||
416 | } | ||
417 | |||
353 | #if defined(CONFIG_ACCESS_CHECK) | 418 | #if defined(CONFIG_ACCESS_CHECK) |
354 | int _access_ok(unsigned long addr, unsigned long size) | 419 | int _access_ok(unsigned long addr, unsigned long size) |
355 | { | 420 | { |
diff --git a/arch/blackfin/kernel/setup.c b/arch/blackfin/kernel/setup.c index 76bf2cea61d7..534227f4da30 100644 --- a/arch/blackfin/kernel/setup.c +++ b/arch/blackfin/kernel/setup.c | |||
@@ -42,6 +42,7 @@ | |||
42 | #include <asm/cacheflush.h> | 42 | #include <asm/cacheflush.h> |
43 | #include <asm/blackfin.h> | 43 | #include <asm/blackfin.h> |
44 | #include <asm/cplbinit.h> | 44 | #include <asm/cplbinit.h> |
45 | #include <asm/fixed_code.h> | ||
45 | 46 | ||
46 | u16 _bfin_swrst; | 47 | u16 _bfin_swrst; |
47 | 48 | ||
@@ -404,6 +405,27 @@ void __init setup_arch(char **cmdline_p) | |||
404 | 405 | ||
405 | printk(KERN_INFO "Hardware Trace Enabled\n"); | 406 | printk(KERN_INFO "Hardware Trace Enabled\n"); |
406 | bfin_write_TBUFCTL(0x03); | 407 | bfin_write_TBUFCTL(0x03); |
408 | |||
409 | /* Copy atomic sequences to their fixed location, and sanity check that | ||
410 | these locations are the ones that we advertise to userspace. */ | ||
411 | memcpy((void *)FIXED_CODE_START, &fixed_code_start, | ||
412 | FIXED_CODE_END - FIXED_CODE_START); | ||
413 | BUG_ON((char *)&sigreturn_stub - (char *)&fixed_code_start | ||
414 | != SIGRETURN_STUB - FIXED_CODE_START); | ||
415 | BUG_ON((char *)&atomic_xchg32 - (char *)&fixed_code_start | ||
416 | != ATOMIC_XCHG32 - FIXED_CODE_START); | ||
417 | BUG_ON((char *)&atomic_cas32 - (char *)&fixed_code_start | ||
418 | != ATOMIC_CAS32 - FIXED_CODE_START); | ||
419 | BUG_ON((char *)&atomic_add32 - (char *)&fixed_code_start | ||
420 | != ATOMIC_ADD32 - FIXED_CODE_START); | ||
421 | BUG_ON((char *)&atomic_sub32 - (char *)&fixed_code_start | ||
422 | != ATOMIC_SUB32 - FIXED_CODE_START); | ||
423 | BUG_ON((char *)&atomic_ior32 - (char *)&fixed_code_start | ||
424 | != ATOMIC_IOR32 - FIXED_CODE_START); | ||
425 | BUG_ON((char *)&atomic_and32 - (char *)&fixed_code_start | ||
426 | != ATOMIC_AND32 - FIXED_CODE_START); | ||
427 | BUG_ON((char *)&atomic_xor32 - (char *)&fixed_code_start | ||
428 | != ATOMIC_XOR32 - FIXED_CODE_START); | ||
407 | } | 429 | } |
408 | 430 | ||
409 | static int __init topology_init(void) | 431 | static int __init topology_init(void) |
diff --git a/arch/blackfin/mach-common/entry.S b/arch/blackfin/mach-common/entry.S index 40045b1386ad..c4a32ea06c4b 100644 --- a/arch/blackfin/mach-common/entry.S +++ b/arch/blackfin/mach-common/entry.S | |||
@@ -741,6 +741,10 @@ _schedule_and_signal_from_int: | |||
741 | r0 = [p0]; | 741 | r0 = [p0]; |
742 | sti r0; | 742 | sti r0; |
743 | 743 | ||
744 | r0 = sp; | ||
745 | sp += -12; | ||
746 | call _finish_atomic_sections; | ||
747 | sp += 12; | ||
744 | jump.s .Lresume_userspace; | 748 | jump.s .Lresume_userspace; |
745 | 749 | ||
746 | _schedule_and_signal: | 750 | _schedule_and_signal: |
diff --git a/include/asm-blackfin/Kbuild b/include/asm-blackfin/Kbuild index c68e1680da01..71f8fe783258 100644 --- a/include/asm-blackfin/Kbuild +++ b/include/asm-blackfin/Kbuild | |||
@@ -1 +1,3 @@ | |||
1 | include include/asm-generic/Kbuild.asm | 1 | include include/asm-generic/Kbuild.asm |
2 | |||
3 | header-y += fixed_code.h | ||
diff --git a/include/asm-blackfin/bfin-global.h b/include/asm-blackfin/bfin-global.h index 57f37ccdcdf1..c4d6cbbf96d4 100644 --- a/include/asm-blackfin/bfin-global.h +++ b/include/asm-blackfin/bfin-global.h | |||
@@ -67,6 +67,18 @@ extern void evt14_softirq(void); | |||
67 | extern asmlinkage void asm_do_IRQ(unsigned int irq, struct pt_regs *regs); | 67 | extern asmlinkage void asm_do_IRQ(unsigned int irq, struct pt_regs *regs); |
68 | extern void bfin_gpio_interrupt_setup(int irq, int irq_pfx, int type); | 68 | extern void bfin_gpio_interrupt_setup(int irq, int irq_pfx, int type); |
69 | 69 | ||
70 | extern asmlinkage void finish_atomic_sections (struct pt_regs *regs); | ||
71 | extern char fixed_code_start; | ||
72 | extern char fixed_code_end; | ||
73 | extern int atomic_xchg32(void); | ||
74 | extern int atomic_cas32(void); | ||
75 | extern int atomic_add32(void); | ||
76 | extern int atomic_sub32(void); | ||
77 | extern int atomic_ior32(void); | ||
78 | extern int atomic_and32(void); | ||
79 | extern int atomic_xor32(void); | ||
80 | extern void sigreturn_stub(void); | ||
81 | |||
70 | extern void *l1_data_A_sram_alloc(size_t); | 82 | extern void *l1_data_A_sram_alloc(size_t); |
71 | extern void *l1_data_B_sram_alloc(size_t); | 83 | extern void *l1_data_B_sram_alloc(size_t); |
72 | extern void *l1_inst_sram_alloc(size_t); | 84 | extern void *l1_inst_sram_alloc(size_t); |
diff --git a/include/asm-blackfin/cplbinit.h b/include/asm-blackfin/cplbinit.h index 3bad2d1e6a8c..e14ea397cdbb 100644 --- a/include/asm-blackfin/cplbinit.h +++ b/include/asm-blackfin/cplbinit.h | |||
@@ -101,8 +101,8 @@ struct s_cplb { | |||
101 | static struct cplb_desc cplb_data[] = { | 101 | static struct cplb_desc cplb_data[] = { |
102 | { | 102 | { |
103 | .start = 0, | 103 | .start = 0, |
104 | .end = SIZE_4K, | 104 | .end = SIZE_1K, |
105 | .psize = SIZE_4K, | 105 | .psize = SIZE_1K, |
106 | .attr = INITIAL_T | SWITCH_T | I_CPLB | D_CPLB, | 106 | .attr = INITIAL_T | SWITCH_T | I_CPLB | D_CPLB, |
107 | .i_conf = SDRAM_OOPS, | 107 | .i_conf = SDRAM_OOPS, |
108 | .d_conf = SDRAM_OOPS, | 108 | .d_conf = SDRAM_OOPS, |
diff --git a/include/asm-blackfin/fixed_code.h b/include/asm-blackfin/fixed_code.h new file mode 100644 index 000000000000..e6df84ee1557 --- /dev/null +++ b/include/asm-blackfin/fixed_code.h | |||
@@ -0,0 +1,20 @@ | |||
1 | /* This file defines the fixed addresses where userspace programs can find | ||
2 | atomic code sequences. */ | ||
3 | |||
4 | #define FIXED_CODE_START 0x400 | ||
5 | |||
6 | #define SIGRETURN_STUB 0x400 | ||
7 | |||
8 | #define ATOMIC_SEQS_START 0x410 | ||
9 | |||
10 | #define ATOMIC_XCHG32 0x410 | ||
11 | #define ATOMIC_CAS32 0x420 | ||
12 | #define ATOMIC_ADD32 0x430 | ||
13 | #define ATOMIC_SUB32 0x440 | ||
14 | #define ATOMIC_IOR32 0x450 | ||
15 | #define ATOMIC_AND32 0x460 | ||
16 | #define ATOMIC_XOR32 0x470 | ||
17 | |||
18 | #define ATOMIC_SEQS_END 0x480 | ||
19 | |||
20 | #define FIXED_CODE_END 0x480 | ||