aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBernd Schmidt <bernd.schmidt@analog.com>2007-06-20 23:34:16 -0400
committerBryan Wu <bryan.wu@analog.com>2007-06-20 23:34:16 -0400
commit7adfb58fbd0a27469d26536f99b66391c4c8e2a0 (patch)
tree59e511ac2ddca77fe7c9d51bc6f6c6f0049a313b
parent0ba9e350a2c129ce2878d415cf51e88611cbc0e5 (diff)
Blackfin arch: defines and provides entry points for certain user space functions at fixed addresses
This patch defines (and provides) entry points for certain user space functions at fixed addresses. The Blackfin has no usable atomic instructions, but we can ensure that these code sequences appear atomic from a user space point of view by detecting when we're in the process of executing them during the interrupt handler return path. This allows much more efficient pthread lock implementations than the bfin_spinlock syscall we're currently using. Also provided is a small sys_rt_sigreturn stub which can be used by the signal handler setup code. The signal.c part will be committed separately. Signed-off-by: Bernd Schmidt <bernd.schmidt@analog.com> Signed-off-by: Bryan Wu <bryan.wu@analog.com>
-rw-r--r--arch/blackfin/kernel/Makefile3
-rw-r--r--arch/blackfin/kernel/fixed_code.S132
-rw-r--r--arch/blackfin/kernel/process.c65
-rw-r--r--arch/blackfin/kernel/setup.c22
-rw-r--r--arch/blackfin/mach-common/entry.S4
-rw-r--r--include/asm-blackfin/Kbuild2
-rw-r--r--include/asm-blackfin/bfin-global.h12
-rw-r--r--include/asm-blackfin/cplbinit.h4
-rw-r--r--include/asm-blackfin/fixed_code.h20
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
7obj-y := \ 7obj-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
11obj-$(CONFIG_BF53x) += bfin_gpio.o 12obj-$(CONFIG_BF53x) += bfin_gpio.o
12obj-$(CONFIG_BF561) += bfin_gpio.o 13obj-$(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
15ENTRY(_fixed_code_start)
16
17.align 16
18ENTRY(_sigreturn_stub)
19 P0 = __NR_rt_sigreturn;
20 EXCPT 0;
21 /* Speculative execution paranoia. */
220: JUMP.S 0b;
23ENDPROC (_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 */
32ENTRY(_atomic_xchg32)
33 R0 = [P0];
34 [P0] = R1;
35 rts;
36ENDPROC (_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 */
48ENTRY(_atomic_cas32)
49 R0 = [P0];
50 CC = R0 == R1;
51 IF !CC JUMP 1f;
52 [P0] = R2;
531:
54 rts;
55ENDPROC (_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 */
65ENTRY(_atomic_add32)
66 R1 = [P0];
67 R0 = R1 + R0;
68 [P0] = R0;
69 rts;
70ENDPROC (_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 */
80ENTRY(_atomic_sub32)
81 R1 = [P0];
82 R0 = R1 - R0;
83 [P0] = R0;
84 rts;
85ENDPROC (_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 */
95ENTRY(_atomic_ior32)
96 R1 = [P0];
97 R0 = R1 | R0;
98 [P0] = R0;
99 rts;
100ENDPROC (_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 */
110ENTRY(_atomic_and32)
111 R1 = [P0];
112 R0 = R1 & R0;
113 [P0] = R0;
114 rts;
115ENDPROC (_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 */
125ENTRY(_atomic_xor32)
126 R1 = [P0];
127 R0 = R1 ^ R0;
128 [P0] = R0;
129 rts;
130ENDPROC (_atomic_ior32)
131
132ENTRY(_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
354void 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)
354int _access_ok(unsigned long addr, unsigned long size) 419int _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
46u16 _bfin_swrst; 47u16 _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
409static int __init topology_init(void) 431static 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 @@
1include include/asm-generic/Kbuild.asm 1include include/asm-generic/Kbuild.asm
2
3header-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);
67extern asmlinkage void asm_do_IRQ(unsigned int irq, struct pt_regs *regs); 67extern asmlinkage void asm_do_IRQ(unsigned int irq, struct pt_regs *regs);
68extern void bfin_gpio_interrupt_setup(int irq, int irq_pfx, int type); 68extern void bfin_gpio_interrupt_setup(int irq, int irq_pfx, int type);
69 69
70extern asmlinkage void finish_atomic_sections (struct pt_regs *regs);
71extern char fixed_code_start;
72extern char fixed_code_end;
73extern int atomic_xchg32(void);
74extern int atomic_cas32(void);
75extern int atomic_add32(void);
76extern int atomic_sub32(void);
77extern int atomic_ior32(void);
78extern int atomic_and32(void);
79extern int atomic_xor32(void);
80extern void sigreturn_stub(void);
81
70extern void *l1_data_A_sram_alloc(size_t); 82extern void *l1_data_A_sram_alloc(size_t);
71extern void *l1_data_B_sram_alloc(size_t); 83extern void *l1_data_B_sram_alloc(size_t);
72extern void *l1_inst_sram_alloc(size_t); 84extern 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 {
101static struct cplb_desc cplb_data[] = { 101static 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