1/*
2 * Copyright (c) 1999-2011 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28/* Copyright (c) 1992 NeXT Computer, Inc.  All rights reserved.
29 *
30 *	File:	SYS.h
31 *
32 *	Definition of the user side of the UNIX system call interface
33 *	for M98K.
34 *
35 *	Errors are flagged by the location of the trap return (ie., which
36 *	instruction is executed upon rfi):
37 *
38 *		SC PC + 4:	Error (typically branch to cerror())
39 *		SC PC + 8:	Success
40 *
41 * HISTORY
42 * 18-Nov-92	Ben Fathi (benf@next.com)
43 *	Ported to m98k.
44 *
45 *  9-Jan-92	Peter King (king@next.com)
46 *	Created.
47 */
48
49#include <sys/syscall.h>
50
51/* Binary compatibility stubs for syscalls that no longer exist */
52
53#ifndef SYS_setquota
54#define SYS_setquota	148
55#endif
56#ifndef SYS_quota
57#define SYS_quota	149
58#endif
59
60#if defined(__i386__)
61
62#include <architecture/i386/asm_help.h>
63#include <mach/i386/syscall_sw.h>
64
65/*
66 * We have two entry points. int's is used for syscalls which need to preserve
67 * %ecx across the call, or return a 64-bit value in %eax:%edx. sysenter is used
68 * for the majority of syscalls which just return a value in %eax.
69 */
70
71#define UNIX_SYSCALL_SYSENTER		call __sysenter_trap
72#define UNIX_SYSCALL(name, nargs)			\
73	.globl	cerror					;\
74LEAF(_##name, 0)					;\
75	movl	$ SYS_##name, %eax			;\
76	UNIX_SYSCALL_SYSENTER				;\
77	jnb	2f					;\
78	BRANCH_EXTERN(cerror)  				;\
792:
80
81#define UNIX_SYSCALL_INT(name, nargs)			\
82	.globl	cerror					;\
83LEAF(_##name, 0)					;\
84	movl	$ SYS_##name, %eax			;\
85	UNIX_SYSCALL_TRAP				;\
86	jnb	2f					;\
87	BRANCH_EXTERN(cerror)  				;\
882:
89
90#if defined(__SYSCALL_32BIT_ARG_BYTES) && ((__SYSCALL_32BIT_ARG_BYTES >= 4) && (__SYSCALL_32BIT_ARG_BYTES <= 20))
91#define UNIX_SYSCALL_NONAME(name, nargs, cerror)			\
92	movl	$(SYS_##name | (__SYSCALL_32BIT_ARG_BYTES << I386_SYSCALL_ARG_BYTES_SHIFT)), %eax		;\
93	UNIX_SYSCALL_SYSENTER					;\
94	jnb	2f						;\
95	BRANCH_EXTERN(cerror)					;\
962:
97#else /* __SYSCALL_32BIT_ARG_BYTES < 4 || > 20 */
98#define UNIX_SYSCALL_NONAME(name, nargs, cerror)		\
99	.globl	cerror					;\
100	movl	$ SYS_##name, %eax			;\
101	UNIX_SYSCALL_SYSENTER				;\
102	jnb	2f					;\
103	BRANCH_EXTERN(cerror)				;\
1042:
105#endif
106
107#define UNIX_SYSCALL_INT_NONAME(name, nargs)		\
108	.globl	cerror					;\
109	movl	$ SYS_##name, %eax			;\
110	UNIX_SYSCALL_TRAP				;\
111	jnb	2f					;\
112	BRANCH_EXTERN(cerror_nocancel) 				;\
1132:
114
115#define PSEUDO(pseudo, name, nargs, cerror)			\
116LEAF(pseudo, 0)					;\
117	UNIX_SYSCALL_NONAME(name, nargs, cerror)
118
119#define PSEUDO_INT(pseudo, name, nargs)			\
120LEAF(pseudo, 0)					;\
121	UNIX_SYSCALL_INT_NONAME(name, nargs)
122
123#define __SYSCALL2(pseudo, name, nargs, cerror)			\
124	PSEUDO(pseudo, name, nargs, cerror)			;\
125	ret
126
127#define __SYSCALL(pseudo, name, nargs)			\
128	PSEUDO(pseudo, name, nargs, cerror)			;\
129	ret
130
131#define __SYSCALL_INT(pseudo, name, nargs)		\
132	PSEUDO_INT(pseudo, name, nargs)			;\
133	ret
134
135#elif defined(__x86_64__)
136
137#include <architecture/i386/asm_help.h>
138#include <mach/i386/syscall_sw.h>
139
140#define UNIX_SYSCALL_SYSCALL	\
141	movq	%rcx, %r10		;\
142	syscall
143
144#define UNIX_SYSCALL(name, nargs)			\
145	.globl	cerror					;\
146LEAF(_##name, 0)					;\
147	movl	$ SYSCALL_CONSTRUCT_UNIX(SYS_##name), %eax	;\
148	UNIX_SYSCALL_SYSCALL				;\
149	jnb	2f					;\
150	BRANCH_EXTERN(cerror)  				;\
1512:
152
153#define UNIX_SYSCALL_NONAME(name, nargs, cerror)		\
154	.globl	cerror					;\
155	movl	$ SYSCALL_CONSTRUCT_UNIX(SYS_##name), %eax	;\
156	UNIX_SYSCALL_SYSCALL				;\
157	jnb	2f					;\
158	BRANCH_EXTERN(cerror)  				;\
1592:
160
161#define PSEUDO(pseudo, name, nargs, cerror)			\
162LEAF(pseudo, 0)					;\
163	UNIX_SYSCALL_NONAME(name, nargs, cerror)
164
165#define __SYSCALL2(pseudo, name, nargs, cerror) \
166	PSEUDO(pseudo, name, nargs, cerror)			;\
167	ret
168
169#define __SYSCALL(pseudo, name, nargs)			\
170	PSEUDO(pseudo, name, nargs, cerror)			;\
171	ret
172
173#elif defined(__arm__)
174
175#define SWI_SYSCALL 0x80	// from <mach/vm_param.h>
176
177/*
178 * ARM system call interface:
179 *
180 * swi 0x80
181 * args: r0-r6
182 * return code: r0
183 * on error, carry bit is set in the psr, otherwise carry bit is cleared.
184 */
185
186/*
187 * Macros.
188 */
189
190/*
191 * until we update the architecture project, these live here
192 */
193
194#if defined(__DYNAMIC__)
195#define MI_GET_ADDRESS(reg,var)  \
196	ldr	reg, 4f					;\
1973:	ldr	reg, [pc, reg]				;\
198	b	5f					;\
1994:	.long	6f - (3b + 8)				;\
2005:							;\
201	.non_lazy_symbol_pointer			;\
2026:							;\
203	.indirect_symbol var				;\
204	.long 0						;\
205	.text						;\
206	.align 2
207#else
208#define MI_GET_ADDRESS(reg,var)  \
209	ldr	reg, 3f	;\
210	b	4f	;\
2113:	.long var	;\
2124:
213#endif
214
215#if defined(__DYNAMIC__)
216#define MI_BRANCH_EXTERNAL(var)				\
217	.globl	var								;\
218	MI_GET_ADDRESS(ip, var)				;\
219 	bx	ip
220#else
221#define MI_BRANCH_EXTERNAL(var)				;\
222	.globl	var								;\
223 	b	var
224#endif
225
226#if defined(__DYNAMIC__)
227#define MI_CALL_EXTERNAL(var)    \
228	.globl	var				;\
229	MI_GET_ADDRESS(ip,var)	;\
230	mov	lr, pc		;\
231	bx	ip
232#else
233#define MI_CALL_EXTERNAL(var)				\
234	.globl	var								;\
235 	bl	var
236#endif
237
238#define MI_ENTRY_POINT(name)				\
239	.align 2	;\
240	.globl  name							;\
241	.text									;\
242name:
243
244/* load the syscall number into r12 and trap */
245#define DO_SYSCALL(num)		\
246	.if (((num) & 0xff) == (num)) 	       				;\
247	mov		r12, #(num)		       			;\
248	.elseif (((num) & 0x3fc) == (num))				;\
249	mov		r12, #(num)					;\
250	.else								;\
251	mov		r12, #((num) & 0xffffff00)	/* top half of the syscall number */ ;\
252	orr		r12, r12, #((num) & 0xff)	/* bottom half */ ;\
253	.endif								;\
254	swi		#SWI_SYSCALL
255
256/* simple syscalls (0 to 4 args) */
257#define	SYSCALL_0to4(name)					\
258	MI_ENTRY_POINT(_##name)					;\
259	DO_SYSCALL(SYS_##name)					;\
260	bxcc	lr								/* return if carry is clear (no error) */ ; \
2611:	MI_BRANCH_EXTERNAL(cerror)
262
263/* syscalls with 5 args is different, because of the single arg register load */
264#define	SYSCALL_5(name)						\
265	MI_ENTRY_POINT(_##name)					;\
266	mov		ip, sp							/* save a pointer to the args */ ; \
267	stmfd	sp!, { r4-r5 }					/* save r4-r5 */ ;\
268	ldr		r4, [ip]						/* load 5th arg */ ; \
269	DO_SYSCALL(SYS_##name)					;\
270	ldmfd	sp!, { r4-r5 }					/* restore r4-r5 */ ; \
271	bxcc	lr								/* return if carry is clear (no error) */ ; \
2721:	MI_BRANCH_EXTERNAL(cerror)
273
274/* syscalls with 6 to 8 args */
275#define SYSCALL_6to8(name, save_regs, arg_regs) \
276	MI_ENTRY_POINT(_##name)					;\
277	mov		ip, sp							/* save a pointer to the args */ ; \
278	stmfd	sp!, { save_regs }				/* callee saved regs */ ;\
279	ldmia	ip, { arg_regs }				/* load arg regs */ ; \
280	DO_SYSCALL(SYS_##name)					;\
281	ldmfd	sp!, { save_regs }				/* restore callee saved regs */ ; \
282	bxcc	lr								/* return if carry is clear (no error) */ ; \
2831:	MI_BRANCH_EXTERNAL(cerror)
284
285#define COMMA ,
286
287#define SYSCALL_0(name)						SYSCALL_0to4(name)
288#define SYSCALL_1(name)						SYSCALL_0to4(name)
289#define SYSCALL_2(name)						SYSCALL_0to4(name)
290#define SYSCALL_3(name)						SYSCALL_0to4(name)
291#define SYSCALL_4(name)						SYSCALL_0to4(name)
292/* SYSCALL_5 declared above */
293#define SYSCALL_6(name)						SYSCALL_6to8(name, r4-r5, r4-r5)
294#define SYSCALL_7(name)						SYSCALL_6to8(name, r4-r6 COMMA r8, r4-r6)
295#define SYSCALL_8(name)						SYSCALL_6to8(name, r4-r6 COMMA r8, r4-r6 COMMA r8)
296
297/* select the appropriate syscall code, based on the number of arguments */
298#define SYSCALL(name, nargs)	SYSCALL_##nargs(name)
299
300#define	SYSCALL_NONAME_0to4(name)			\
301	DO_SYSCALL(SYS_##name)					;\
302	bcc		1f								/* branch if carry bit is clear (no error) */ ; \
303	MI_BRANCH_EXTERNAL(cerror)				/* call cerror */ ; \
3041:
305
306#define	SYSCALL_NONAME_5(name)				\
307	mov		ip, sp 							/* save a pointer to the args */ ; \
308	stmfd	sp!, { r4-r5 }					/* save r4-r5 */ ;\
309	ldr		r4, [ip]						/* load 5th arg */ ; \
310	DO_SYSCALL(SYS_##name)					;\
311	ldmfd	sp!, { r4-r5 }					/* restore r4-r7 */ ; \
312	bcc		1f								/* branch if carry bit is clear (no error) */ ; \
313	MI_BRANCH_EXTERNAL(cerror)				/* call cerror */ ; \
3141:
315
316#define	SYSCALL_NONAME_6to8(name, save_regs, arg_regs)	\
317	mov		ip, sp 							/* save a pointer to the args */ ; \
318	stmfd	sp!, { save_regs }				/* callee save regs */ ;\
319	ldmia	ip, { arg_regs }				/* load arguments */ ; \
320	DO_SYSCALL(SYS_##name)					;\
321	ldmfd	sp!, { save_regs }				/* restore callee saved regs */ ; \
322	bcc		1f								/* branch if carry bit is clear (no error) */ ; \
323	MI_BRANCH_EXTERNAL(cerror)				/* call cerror */ ; \
3241:
325
326#define SYSCALL_NONAME_0(name)				SYSCALL_NONAME_0to4(name)
327#define SYSCALL_NONAME_1(name)				SYSCALL_NONAME_0to4(name)
328#define SYSCALL_NONAME_2(name)				SYSCALL_NONAME_0to4(name)
329#define SYSCALL_NONAME_3(name)				SYSCALL_NONAME_0to4(name)
330#define SYSCALL_NONAME_4(name)				SYSCALL_NONAME_0to4(name)
331/* SYSCALL_NONAME_5 declared above */
332#define SYSCALL_NONAME_6(name)				SYSCALL_NONAME_6to8(name, r4-r5, r4-r5)
333#define SYSCALL_NONAME_7(name)				SYSCALL_NONAME_6to8(name, r4-r6 COMMA r8, r4-r6)
334#define SYSCALL_NONAME_8(name)				SYSCALL_NONAME_6to8(name, r4-r6 COMMA r8, r4-r6 COMMA r8)
335
336/* select the appropriate syscall code, based on the number of arguments */
337#define SYSCALL_NONAME(name, nargs)	SYSCALL_NONAME_##nargs(name)
338
339#define	PSEUDO(pseudo, name, nargs)			\
340	.globl	_##pseudo						;\
341	.text									;\
342	.align  2								;\
343_##pseudo:									;\
344	SYSCALL_NONAME(name, nargs)
345
346#define	PSEUDO2(pseudo, name, nargs)			\
347	.globl	pseudo						;\
348	.text									;\
349	.align  2								;\
350pseudo:									;\
351	SYSCALL_NONAME(name, nargs)
352
353#define __SYSCALL(pseudo, name, nargs)		\
354	PSEUDO(pseudo, name, nargs)				;\
355	bx lr
356
357#define __SYSCALL2(pseudo, name, nargs, cerror)		 \
358	PSEUDO2(pseudo, name, nargs)				;\
359	bx lr
360
361#else
362#error Unsupported architecture
363#endif
364
365