1/* SPDX-License-Identifier: GPL-2.0 */ 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 */ 710: 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 821: 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: 99