linux/arch/metag/kernel/user_gateway.S
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2010 Imagination Technologies Ltd.
   3 *
   4 * This file contains code that can be accessed from userspace and can
   5 * access certain kernel data structures without the overhead of a system
   6 * call.
   7 */
   8
   9#include <asm/metag_regs.h>
  10#include <asm/user_gateway.h>
  11
  12/*
  13 * User helpers.
  14 *
  15 * These are segment of kernel provided user code reachable from user space
  16 * at a fixed address in kernel memory.  This is used to provide user space
  17 * with some operations which require kernel help because of unimplemented
  18 * native feature and/or instructions in some Meta CPUs. The idea is for
  19 * this code to be executed directly in user mode for best efficiency but
  20 * which is too intimate with the kernel counter part to be left to user
  21 * libraries.  The kernel reserves the right to change this code as needed
  22 * without warning. Only the entry points and their results are guaranteed
  23 * to be stable.
  24 *
  25 * Each segment is 64-byte aligned.  This mechanism should be used only for
  26 * for things that are really small and justified, and not be abused freely.
  27 */
  28        .text
  29        .global ___user_gateway_start
  30___user_gateway_start:
  31
  32        /* get_tls
  33         * Offset:       0
  34         * Description:  Get the TLS pointer for this process.
  35         */
  36        .global ___kuser_get_tls
  37        .type   ___kuser_get_tls,function
  38___kuser_get_tls:
  39        MOVT    D1Ar1,#HI(USER_GATEWAY_PAGE + USER_GATEWAY_TLS)
  40        ADD     D1Ar1,D1Ar1,#LO(USER_GATEWAY_PAGE + USER_GATEWAY_TLS)
  41        MOV     D1Ar3,TXENABLE
  42        AND     D1Ar3,D1Ar3,#(TXENABLE_THREAD_BITS)
  43        LSR     D1Ar3,D1Ar3,#(TXENABLE_THREAD_S - 2)
  44        GETD    D0Re0,[D1Ar1+D1Ar3]
  45___kuser_get_tls_end:           /* Beyond this point the read will complete */
  46        MOV     PC,D1RtP
  47        .size   ___kuser_get_tls,.-___kuser_get_tls
  48        .global ___kuser_get_tls_end
  49
  50        /* cmpxchg
  51         * Offset:       64
  52         * Description:  Replace the value at 'ptr' with 'newval' if the current
  53         *               value is 'oldval'. Return zero if we succeeded,
  54         *               non-zero otherwise.
  55         *
  56         * Reference prototype:
  57         *
  58         *      int __kuser_cmpxchg(int oldval, int newval, unsigned long *ptr)
  59         *
  60         */
  61        .balign 64
  62        .global ___kuser_cmpxchg
  63        .type   ___kuser_cmpxchg,function
  64___kuser_cmpxchg:
  65#ifdef CONFIG_SMP
  66        /*
  67         * We must use LNKGET/LNKSET with an SMP kernel because the other method
  68         * does not provide atomicity across multiple CPUs.
  69         */
  700:      LNKGETD D0Re0,[D1Ar3]
  71        CMP     D0Re0,D1Ar1
  72        LNKSETDZ [D1Ar3],D0Ar2
  73        BNZ     1f
  74        DEFR    D0Re0,TXSTAT
  75        ANDT    D0Re0,D0Re0,#HI(0x3f000000)
  76        CMPT    D0Re0,#HI(0x02000000)
  77        BNE     0b
  78#ifdef CONFIG_METAG_LNKGET_AROUND_CACHE
  79        DCACHE  [D1Ar3], D0Re0
  80#endif
  811:      MOV     D0Re0,#1
  82        XORZ    D0Re0,D0Re0,D0Re0
  83        MOV     PC,D1RtP
  84#else
  85        GETD    D0Re0,[D1Ar3]
  86        CMP     D0Re0,D1Ar1
  87        SETDZ   [D1Ar3],D0Ar2
  88___kuser_cmpxchg_end:           /* Beyond this point the write will complete */
  89        MOV     D0Re0,#1
  90        XORZ    D0Re0,D0Re0,D0Re0
  91        MOV     PC,D1RtP
  92#endif /* CONFIG_SMP */
  93        .size   ___kuser_cmpxchg,.-___kuser_cmpxchg
  94        .global ___kuser_cmpxchg_end
  95
  96        .global ___user_gateway_end
  97___user_gateway_end:
  98