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