Commit | Line | Data |
---|---|---|
26025bbf JH |
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 | */ | |
70 | 0: 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 | |
81 | 1: 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: |