1 /* Assembler macros for ARM.
2    Copyright (C) 1997, 1998, 2003 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4 
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9 
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14 
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, see
17    <http://www.gnu.org/licenses/>.  */
18 
19 #ifndef _LINUX_ARM_SYSDEP_H
20 #define _LINUX_ARM_SYSDEP_H 1
21 
22 #include <common/sysdep.h>
23 #include <bits/arm_bx.h>
24 #include <sys/syscall.h>
25 /* For Linux we can use the system call table in the header file
26 	/usr/include/asm/unistd.h
27    of the kernel.  But these symbols do not follow the SYS_* syntax
28    so we have to redefine the `SYS_ify' macro here.  */
29 #undef SYS_ify
30 #define SWI_BASE  (0x900000)
31 #define SYS_ify(syscall_name)	(__NR_##syscall_name)
32 
33 #ifdef	__ASSEMBLER__
34 
35 /* Syntactic details of assembler.  */
36 
37 #define ALIGNARG(log2) log2
38 /* For ELF we need the `.type' directive to make shared libs work right.  */
39 #define ASM_TYPE_DIRECTIVE(name,typearg) .type name,%##typearg;
40 #define ASM_SIZE_DIRECTIVE(name) .size name,.-name
41 
42 /* In ELF C symbols are asm symbols.  */
43 #undef	NO_UNDERSCORES
44 #define NO_UNDERSCORES
45 
46 #define PLTJMP(_x)	_x##(PLT)
47 
48 /* APCS-32 doesn't preserve the condition codes across function call. */
49 #ifdef __APCS_32__
50 #define LOADREGS(cond, base, reglist...)\
51 	ldm##cond	base,reglist
52 #define RETINSTR(cond, reg) \
53 	BXC(cond, reg)
54 #define DO_RET(_reg)		\
55 	BX(_reg)
56 #else  /* APCS-26 */
57 #define LOADREGS(cond, base, reglist...)	\
58 	ldm##cond	base,reglist^
59 #define RETINSTR(cond, reg)	\
60 	mov##cond##s	pc, reg
61 #define DO_RET(_reg)		\
62 	movs pc, _reg
63 #endif
64 
65 /* Define an entry point visible from C.  */
66 #define	ENTRY(name)						\
67   .globl C_SYMBOL_NAME(name);			\
68   ASM_TYPE_DIRECTIVE (C_SYMBOL_NAME(name),function)		\
69   .align ALIGNARG(4);						\
70   name##:
71 
72 #undef	END
73 #define END(name)						\
74   ASM_SIZE_DIRECTIVE(name)
75 
76 #ifdef	NO_UNDERSCORES
77 /* Since C identifiers are not normally prefixed with an underscore
78    on this system, the asm identifier `syscall_error' intrudes on the
79    C name space.  Make sure we use an innocuous name.  */
80 #define	syscall_error	__syscall_error
81 #define mcount		_mcount
82 #endif
83 /* Linux uses a negative return value to indicate syscall errors,
84    unlike most Unices, which use the condition codes' carry flag.
85 
86    Since version 2.1 the return value of a system call might be
87    negative even if the call succeeded.  E.g., the `lseek' system call
88    might return a large offset.  Therefore we must not anymore test
89    for < 0, but test for a real error by making sure the value in R0
90    is a real error number.  Linus said he will make sure the no syscall
91    returns a value in -1 .. -4095 as a valid result so we can safely
92    test with -4095.  */
93 
94 #undef	PSEUDO
95 #define	PSEUDO(name, syscall_name, args)				\
96   .text;								\
97   ENTRY (name);								\
98     DO_CALL (syscall_name, args);					\
99     cmn r0, $4096;
100 
101 #define PSEUDO_RET							\
102     RETINSTR(cc, lr);							\
103     b PLTJMP(SYSCALL_ERROR)
104 #undef ret
105 #define ret PSEUDO_RET
106 
107 #undef	PSEUDO_END
108 #define	PSEUDO_END(name)						\
109   SYSCALL_ERROR_HANDLER							\
110   END (name)
111 
112 #undef	PSEUDO_NOERRNO
113 #define	PSEUDO_NOERRNO(name, syscall_name, args)			\
114   .text;								\
115   ENTRY (name);								\
116     DO_CALL (syscall_name, args);
117 
118 #define PSEUDO_RET_NOERRNO						\
119     DO_RET (lr);
120 
121 #undef ret_NOERRNO
122 #define ret_NOERRNO PSEUDO_RET_NOERRNO
123 
124 #undef	PSEUDO_END_NOERRNO
125 #define	PSEUDO_END_NOERRNO(name)					\
126   END (name)
127 
128 /* The function has to return the error code.  */
129 #undef	PSEUDO_ERRVAL
130 #define	PSEUDO_ERRVAL(name, syscall_name, args) \
131   .text;								\
132   ENTRY (name)								\
133     DO_CALL (syscall_name, args);					\
134     rsb r0, r0, #0
135 
136 #undef	PSEUDO_END_ERRVAL
137 #define	PSEUDO_END_ERRVAL(name) \
138   END (name)
139 
140 #if defined NOT_IN_libc
141 # define SYSCALL_ERROR __local_syscall_error
142 #  define SYSCALL_ERROR_HANDLER					\
143 __local_syscall_error:						\
144 	str	lr, [sp, #-4]!;					\
145 	str	r0, [sp, #-4]!;					\
146 	bl	PLTJMP(C_SYMBOL_NAME(__errno_location)); 	\
147 	ldr	r1, [sp], #4;					\
148 	rsb	r1, r1, #0;					\
149 	str	r1, [r0];					\
150 	mvn	r0, #0;						\
151 	ldr	pc, [sp], #4;
152 #else
153 # define SYSCALL_ERROR_HANDLER	/* Nothing here; code in sysdep.S is used.  */
154 # define SYSCALL_ERROR __syscall_error
155 #endif
156 
157 /* Linux takes system call args in registers:
158 	syscall number	in the SWI instruction
159 	arg 1		r0
160 	arg 2		r1
161 	arg 3		r2
162 	arg 4		r3
163 	arg 5		r4	(this is different from the APCS convention)
164 	arg 6		r5
165 	arg 7		r6
166 
167    The compiler is going to form a call by coming here, through PSEUDO, with
168    arguments
169 	syscall number	in the DO_CALL macro
170 	arg 1		r0
171 	arg 2		r1
172 	arg 3		r2
173 	arg 4		r3
174 	arg 5		[sp]
175 	arg 6		[sp+4]
176 	arg 7		[sp+8]
177 
178    We need to shuffle values between R4..R6 and the stack so that the
179    caller's v1..v3 and stack frame are not corrupted, and the kernel
180    sees the right arguments.
181 
182 */
183 #if __ARM_ARCH > 6 || defined (__ARM_ARCH_6K__) || defined (__ARM_ARCH_6ZK__)
184 # define ARCH_HAS_HARD_TP
185 #endif
186 
187 # ifdef __thumb2__
188 #  define NEGOFF_ADJ_BASE(R, OFF)	add R, R, $OFF
189 #  define NEGOFF_ADJ_BASE2(D, S, OFF)	add D, S, $OFF
190 #  define NEGOFF_OFF1(R, OFF)		[R]
191 #  define NEGOFF_OFF2(R, OFFA, OFFB)	[R, $((OFFA) - (OFFB))]
192 # else
193 #  define NEGOFF_ADJ_BASE(R, OFF)
194 #  define NEGOFF_ADJ_BASE2(D, S, OFF)	mov D, S
195 #  define NEGOFF_OFF1(R, OFF)		[R, $OFF]
196 #  define NEGOFF_OFF2(R, OFFA, OFFB)	[R, $OFFA]
197 # endif
198 
199 # ifdef ARCH_HAS_HARD_TP
200 /* If the cpu has cp15 available, use it.  */
201 #  define GET_TLS(TMP)		mrc p15, 0, r0, c13, c0, 3
202 # else
203 /* At this generic level we have no tricks to pull.  Call the ABI routine.  */
204 #  define GET_TLS(TMP)					\
205 	push	{ r1, r2, r3, lr };			\
206 	cfi_remember_state;				\
207 	cfi_adjust_cfa_offset (16);			\
208 	cfi_rel_offset (r1, 0);				\
209 	cfi_rel_offset (r2, 4);				\
210 	cfi_rel_offset (r3, 8);				\
211 	cfi_rel_offset (lr, 12);			\
212 	bl	__aeabi_read_tp;			\
213 	pop	{ r1, r2, r3, lr };			\
214 	cfi_restore_state
215 # endif /* ARCH_HAS_HARD_TP */
216 
217 
218 
219 
220 #undef	DO_CALL
221 #if defined(__ARM_EABI__)
222 #define DO_CALL(syscall_name, args)		\
223     DOARGS_##args				\
224     mov ip, r7;					\
225     ldr r7, =SYS_ify (syscall_name);		\
226     swi 0x0;					\
227     mov r7, ip;					\
228     UNDOARGS_##args
229 #else
230 #define DO_CALL(syscall_name, args)		\
231     DOARGS_##args				\
232     swi SYS_ify (syscall_name); 		\
233     UNDOARGS_##args
234 #endif
235 
236 #define DOARGS_0 /* nothing */
237 #define DOARGS_1 /* nothing */
238 #define DOARGS_2 /* nothing */
239 #define DOARGS_3 /* nothing */
240 #define DOARGS_4 /* nothing */
241 #define DOARGS_5 str r4, [sp, $-4]!; ldr r4, [sp, $4];
242 #define DOARGS_6 mov ip, sp; stmfd sp!, {r4, r5}; ldmia ip, {r4, r5};
243 #define DOARGS_7 mov ip, sp; stmfd sp!, {r4, r5, r6}; ldmia ip, {r4, r5, r6};
244 
245 #define UNDOARGS_0 /* nothing */
246 #define UNDOARGS_1 /* nothing */
247 #define UNDOARGS_2 /* nothing */
248 #define UNDOARGS_3 /* nothing */
249 #define UNDOARGS_4 /* nothing */
250 #define UNDOARGS_5 ldr r4, [sp], $4;
251 #define UNDOARGS_6 ldmfd sp!, {r4, r5};
252 #define UNDOARGS_7 ldmfd sp!, {r4, r5, r6};
253 
254 #endif	/* __ASSEMBLER__ */
255 #endif /* linux/arm/sysdep.h */
256