Commit 7adfb58fbd0a27469d26536f99b66391c4c8e2a0

Authored by Bernd Schmidt
Committed by Bryan Wu
1 parent 0ba9e350a2

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>

Showing 9 changed files with 261 additions and 3 deletions Side-by-side Diff

arch/blackfin/kernel/Makefile
... ... @@ -6,7 +6,8 @@
6 6  
7 7 obj-y := \
8 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 12 obj-$(CONFIG_BF53x) += bfin_gpio.o
12 13 obj-$(CONFIG_BF561) += bfin_gpio.o
arch/blackfin/kernel/fixed_code.S
  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)
arch/blackfin/kernel/process.c
... ... @@ -35,6 +35,7 @@
35 35  
36 36 #include <asm/blackfin.h>
37 37 #include <asm/uaccess.h>
  38 +#include <asm/fixed_code.h>
38 39  
39 40 #define LED_ON 0
40 41 #define LED_OFF 1
... ... @@ -348,6 +349,70 @@
348 349 }
349 350 while (count++ < 16);
350 351 return 0;
  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 + }
351 416 }
352 417  
353 418 #if defined(CONFIG_ACCESS_CHECK)
arch/blackfin/kernel/setup.c
... ... @@ -42,6 +42,7 @@
42 42 #include <asm/cacheflush.h>
43 43 #include <asm/blackfin.h>
44 44 #include <asm/cplbinit.h>
  45 +#include <asm/fixed_code.h>
45 46  
46 47 u16 _bfin_swrst;
47 48  
... ... @@ -404,6 +405,27 @@
404 405  
405 406 printk(KERN_INFO "Hardware Trace Enabled\n");
406 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 431 static int __init topology_init(void)
arch/blackfin/mach-common/entry.S
... ... @@ -741,6 +741,10 @@
741 741 r0 = [p0];
742 742 sti r0;
743 743  
  744 + r0 = sp;
  745 + sp += -12;
  746 + call _finish_atomic_sections;
  747 + sp += 12;
744 748 jump.s .Lresume_userspace;
745 749  
746 750 _schedule_and_signal:
include/asm-blackfin/Kbuild
1 1 include include/asm-generic/Kbuild.asm
  2 +
  3 +header-y += fixed_code.h
include/asm-blackfin/bfin-global.h
... ... @@ -67,6 +67,18 @@
67 67 extern asmlinkage void asm_do_IRQ(unsigned int irq, struct pt_regs *regs);
68 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 82 extern void *l1_data_A_sram_alloc(size_t);
71 83 extern void *l1_data_B_sram_alloc(size_t);
72 84 extern void *l1_inst_sram_alloc(size_t);
include/asm-blackfin/cplbinit.h
... ... @@ -101,8 +101,8 @@
101 101 static struct cplb_desc cplb_data[] = {
102 102 {
103 103 .start = 0,
104   - .end = SIZE_4K,
105   - .psize = SIZE_4K,
  104 + .end = SIZE_1K,
  105 + .psize = SIZE_1K,
106 106 .attr = INITIAL_T | SWITCH_T | I_CPLB | D_CPLB,
107 107 .i_conf = SDRAM_OOPS,
108 108 .d_conf = SDRAM_OOPS,
include/asm-blackfin/fixed_code.h
  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