1/*
2 * Linux/PA-RISC Project (http://www.parisc-linux.org/)
3 *
4 * System call entry code Copyright (c) Matthew Wilcox 1999 <willy@bofh.ai>
5 * Licensed under the GNU GPL.
6 * thanks to Philipp Rumpf, Mike Shaver and various others
7 * sorry about the wall, puffin..
8 */
9
10#include <asm/offset.h>
11#include <asm/unistd.h>
12#include <asm/errno.h>
13#include <asm/psw.h>
14
15#include <asm/assembly.h>
16#include <asm/processor.h>
17#include <linux/version.h>
18
19#ifdef __LP64__
20	.level          2.0w
21#else
22	.level		1.1
23#endif
24	.text
25
26#ifdef __LP64__
27#define FRAME_SIZE	128
28#else
29#define FRAME_SIZE	64
30#endif
31
32	.import syscall_exit,code
33	.import syscall_exit_rfi,code
34	.export linux_gateway_page
35
36	/* Linux gateway page is aliased to virtual page 0 in the kernel
37	 * address space. Since it is a gateway page it cannot be
38	 * dereferenced, so null pointers will still fault. We start
39	 * the actual entry point at 0x100. We put break instructions
40	 * at the beginning of the page to trap null indirect function
41	 * pointers.
42	 */
43
44	.align 4096
45linux_gateway_page:
46
47	.rept 56
48	break   0,0
49	.endr
50
51set_thread_pointer:
52	gate	.+8, %r0		/* increase privilege */
53	depi	3, 31, 2, %r31		/* Ensure we return into user mode. */
54	be	0(%sr7,%r31)		/* return to user space */
55	mtctl	%r26, %cr27		/* move arg0 to the control register */
56
57	.rept 4
58	break   0,0
59	.endr
60
61/* This address must remain fixed, or user binaries go splat. */
62	.align 256
63linux_gateway_entry:
64	gate	.+8, %r0			/* become privileged */
65	mtsp	%r0,%sr4			/* get kernel space into sr4 */
66	mtsp	%r0,%sr5			/* get kernel space into sr5 */
67	mtsp	%r0,%sr6			/* get kernel space into sr6 */
68	mfsp    %sr7,%r1                        /* save user sr7 */
69	mtsp    %r1,%sr3                        /* and store it in sr3 */
70
71#ifdef __LP64__
72	/* for now we can *always* set the W bit on entry to the syscall
73	 * since we don't support wide userland processes.  We could
74	 * also save the current SM other than in r0 and restore it on
75	 * exit from the syscall, and also use that value to know
76	 * whether to do narrow or wide syscalls. -PB
77	 */
78	ssm	PSW_SM_W, %r0
79	/* The top halves of argument registers must be cleared on syscall
80	 * entry.
81	 */
82	depdi	0, 31, 32, %r26
83	depdi	0, 31, 32, %r25
84	depdi	0, 31, 32, %r24
85	depdi	0, 31, 32, %r23
86	depdi	0, 31, 32, %r22
87	depdi	0, 31, 32, %r21
88#endif
89	mfctl   %cr30,%r1
90	xor     %r1,%r30,%r30                   /* ye olde xor trick */
91	xor     %r1,%r30,%r1
92	xor     %r1,%r30,%r30
93	ldo     TASK_SZ_ALGN+FRAME_SIZE(%r30),%r30  /* set up kernel stack */
94
95	/* N.B.: It is critical that we don't set sr7 to 0 until r30
96	 *       contains a valid kernel stack pointer. It is also
97	 *       critical that we don't start using the kernel stack
98	 *       until after sr7 has been set to 0.
99	 */
100
101	mtsp	%r0,%sr7			/* get kernel space into sr7 */
102	STREG   %r1,TASK_PT_GR30-TASK_SZ_ALGN-FRAME_SIZE(%r30) /* save usp */
103	ldo     -TASK_SZ_ALGN-FRAME_SIZE(%r30),%r1   /* get task ptr in %r1 */
104
105	/* Save some registers for sigcontext and potential task
106	   switch (see entry.S for the details of which ones are
107	   saved/restored).  TASK_PT_PSW is zeroed so we can see whether
108	   a process is on a syscall or not.  For an interrupt the real
109	   PSW value is stored.  This is needed for gdb and sys_ptrace. */
110	STREG	%r0,  TASK_PT_PSW(%r1)
111	STREG	%r2,  TASK_PT_GR2(%r1)		/* preserve rp */
112	STREG	%r19, TASK_PT_GR19(%r1)
113	STREG	%r20, TASK_PT_GR20(%r1)
114	STREG	%r21, TASK_PT_GR21(%r1)
115	STREG	%r22, TASK_PT_GR22(%r1)
116	STREG	%r23, TASK_PT_GR23(%r1)		/* 4th argument */
117	STREG	%r24, TASK_PT_GR24(%r1)		/* 3rd argument */
118	STREG	%r25, TASK_PT_GR25(%r1)		/* 2nd argument */
119	STREG	%r26, TASK_PT_GR26(%r1)	 	/* 1st argument */
120	STREG	%r27, TASK_PT_GR27(%r1)		/* user dp */
121	STREG   %r28, TASK_PT_GR28(%r1)         /* return value 0 */
122	STREG   %r28, TASK_PT_ORIG_R28(%r1)     /* return value 0 (saved for signals) */
123	STREG	%r29, TASK_PT_GR29(%r1)		/* return value 1 */
124	STREG	%r31, TASK_PT_GR31(%r1)		/* preserve syscall return ptr */
125
126	ldo	TASK_PT_FR0(%r1), %r27		/* save fpregs from the kernel */
127	save_fp	%r27				/* or potential task switch  */
128
129	mfctl	%cr11, %r27			/* i.e. SAR */
130	STREG	%r27, TASK_PT_SAR(%r1)
131
132	loadgp
133
134#ifdef __LP64__
135	ldo	-16(%r30),%r29			/* Reference param save area */
136#else
137	/* no need to save these on stack in wide mode because the first 8
138	 * args are passed in registers */
139	stw     %r22, -52(%r30)                 /* 5th argument */
140	stw     %r21, -56(%r30)                 /* 6th argument */
141#endif
142
143	/* for some unknown reason, task_struct.ptrace is an unsigned long so use LDREG */
144	LDREG	TASK_PTRACE(%r1), %r19		/* Are we being ptraced? */
145
146	bb,<,n	%r19, 31, .Ltracesys		/* must match PT_PTRACE bit */
147
148	/* Note!  We cannot use the syscall table that is mapped
149	nearby since the gateway page is mapped execute-only. */
150
151	ldil	L%sys_call_table, %r1
152	ldo     R%sys_call_table(%r1), %r19
153
154	comiclr,>>=	__NR_Linux_syscalls, %r20, %r0
155	b,n	.Lsyscall_nosys
156
157#ifdef __LP64__
158	ldd,s   %r20(%r19), %r19
159#else
160	ldwx,s  %r20(%r19), %r19
161#endif
162	/* If this is a sys_rt_sigreturn call, and the signal was received
163	 * when not in_syscall, then we want to return via syscall_exit_rfi,
164	 * not syscall_exit.  Signal no. in r20, in_syscall in r25 (see
165	 * trampoline code in signal.c).
166	 */
167	ldi	__NR_rt_sigreturn,%r2
168	comb,=	%r2,%r20,.Lrt_sigreturn
169.Lin_syscall:
170	ldil	L%syscall_exit,%r2
171	be      0(%sr7,%r19)
172	ldo	R%syscall_exit(%r2),%r2
173.Lrt_sigreturn:
174	comib,<> 0,%r25,.Lin_syscall
175	ldil	L%syscall_exit_rfi,%r2
176	be      0(%sr7,%r19)
177	ldo	R%syscall_exit_rfi(%r2),%r2
178
179	/* Note!  Because we are not running where we were linked, any
180	calls to functions external to this file must be indirect.  To
181	be safe, we apply the opposite rule to functions within this
182	file, with local labels given to them to ensure correctness. */
183
184.Lsyscall_nosys:
185syscall_nosys:
186	ldil	L%syscall_exit,%r1
187	be	R%syscall_exit(%sr7,%r1)
188	ldo	-ENOSYS(%r0),%r28		   /* set errno */
189
190
191/* Warning! This trace code is a virtual duplicate of the code above so be
192 * sure to maintain both! */
193.Ltracesys:
194tracesys:
195	/* Need to save more registers so the debugger can see where we
196	 * are.  This saves only the lower 8 bits of PSW, so that the C
197	 * bit is still clear on syscalls, and the D bit is set if this
198	 * full register save path has been executed.  We check the D
199	 * bit on syscall_return_rfi to determine which registers to
200	 * restore.  An interrupt results in a full PSW saved with the
201	 * C bit set, a non-straced syscall entry results in C and D clear
202	 * in the saved PSW.
203	 */
204	ldo     -TASK_SZ_ALGN-FRAME_SIZE(%r30),%r1      /* get task ptr */
205	ssm	0,%r2
206	STREG	%r2,TASK_PT_PSW(%r1)		/* Lower 8 bits only!! */
207	mfsp	%sr0,%r2
208	STREG	%r2,TASK_PT_SR0(%r1)
209	mfsp	%sr1,%r2
210	STREG	%r2,TASK_PT_SR1(%r1)
211	mfsp	%sr2,%r2
212	STREG	%r2,TASK_PT_SR2(%r1)
213	mfsp	%sr3,%r2
214	STREG	%r2,TASK_PT_SR3(%r1)
215	STREG	%r2,TASK_PT_SR4(%r1)
216	STREG	%r2,TASK_PT_SR5(%r1)
217	STREG	%r2,TASK_PT_SR6(%r1)
218	STREG	%r2,TASK_PT_SR7(%r1)
219	STREG	%r2,TASK_PT_IASQ0(%r1)
220	STREG	%r2,TASK_PT_IASQ1(%r1)
221	LDREG	TASK_PT_GR31(%r1),%r2
222	STREG	%r2,TASK_PT_IAOQ0(%r1)
223	ldo	4(%r2),%r2
224	STREG	%r2,TASK_PT_IAOQ1(%r1)
225	ldo	TASK_REGS(%r1),%r2
226	/* reg_save %r2 */
227	STREG	%r3,PT_GR3(%r2)
228	STREG	%r4,PT_GR4(%r2)
229	STREG	%r5,PT_GR5(%r2)
230	STREG	%r6,PT_GR6(%r2)
231	STREG	%r7,PT_GR7(%r2)
232	STREG	%r8,PT_GR8(%r2)
233	STREG	%r9,PT_GR9(%r2)
234	STREG	%r10,PT_GR10(%r2)
235	STREG	%r11,PT_GR11(%r2)
236	STREG	%r12,PT_GR12(%r2)
237	STREG	%r13,PT_GR13(%r2)
238	STREG	%r14,PT_GR14(%r2)
239	STREG	%r15,PT_GR15(%r2)
240	STREG	%r16,PT_GR16(%r2)
241	STREG	%r17,PT_GR17(%r2)
242	STREG	%r18,PT_GR18(%r2)
243	/* Finished saving things for the debugger */
244
245	ldil	L%syscall_trace,%r1
246	ldil	L%tracesys_next,%r2
247	be	R%syscall_trace(%sr7,%r1)
248	ldo	R%tracesys_next(%r2),%r2
249
250tracesys_next:
251	ldil	L%sys_call_table,%r1
252	ldo     R%sys_call_table(%r1), %r19
253
254	ldo     -TASK_SZ_ALGN-FRAME_SIZE(%r30),%r1      /* get task ptr */
255	LDREG   TASK_PT_GR20(%r1), %r20
256	LDREG   TASK_PT_GR26(%r1), %r26		/* Restore the users args */
257	LDREG   TASK_PT_GR25(%r1), %r25
258	LDREG   TASK_PT_GR24(%r1), %r24
259	LDREG   TASK_PT_GR23(%r1), %r23
260#ifdef __LP64__
261	LDREG   TASK_PT_GR22(%r1), %r22
262	LDREG   TASK_PT_GR21(%r1), %r21
263	ldo	-16(%r30),%r29			/* Reference param save area */
264#endif
265
266	comiclr,>>=	__NR_Linux_syscalls, %r20, %r0
267	b,n	.Lsyscall_nosys
268
269#ifdef __LP64__
270	ldd,s   %r20(%r19), %r19
271#else
272	ldwx,s  %r20(%r19), %r19
273#endif
274	/* If this is a sys_rt_sigreturn call, and the signal was received
275	 * when not in_syscall, then we want to return via syscall_exit_rfi,
276	 * not syscall_exit.  Signal no. in r20, in_syscall in r25 (see
277	 * trampoline code in signal.c).
278	 */
279	ldi	__NR_rt_sigreturn,%r2
280	comb,=	%r2,%r20,.Ltrace_rt_sigreturn
281.Ltrace_in_syscall:
282	ldil	L%tracesys_exit,%r2
283	be      0(%sr7,%r19)
284	ldo	R%tracesys_exit(%r2),%r2
285
286	/* Do *not* call this function on the gateway page, because it
287	makes a direct call to syscall_trace. */
288
289tracesys_exit:
290	ldo     -TASK_SZ_ALGN-FRAME_SIZE(%r30),%r1      /* get task ptr */
291#ifdef __LP64__
292	ldo	-16(%r30),%r29			/* Reference param save area */
293#endif
294	bl	syscall_trace, %r2
295	STREG   %r28,TASK_PT_GR28(%r1)          /* save return value now */
296	ldo     -TASK_SZ_ALGN-FRAME_SIZE(%r30),%r1      /* get task ptr */
297	LDREG   TASK_PT_GR28(%r1), %r28		/* Restore return val. */
298
299	ldil	L%syscall_exit,%r1
300	be,n	R%syscall_exit(%sr7,%r1)
301
302.Ltrace_rt_sigreturn:
303	comib,<> 0,%r25,.Ltrace_in_syscall
304	ldil	L%tracesys_sigexit,%r2
305	be      0(%sr7,%r19)
306	ldo	R%tracesys_sigexit(%r2),%r2
307
308tracesys_sigexit:
309	ldo     -TASK_SZ_ALGN-FRAME_SIZE(%r30),%r1      /* get task ptr */
310#ifdef __LP64__
311	ldo	-16(%r30),%r29			/* Reference param save area */
312#endif
313	bl	syscall_trace, %r2
314	nop
315
316	ldil	L%syscall_exit_rfi,%r1
317	be,n	R%syscall_exit_rfi(%sr7,%r1)
318
319#ifdef __LP64__
320/* Use ENTRY_SAME for 32-bit syscalls which are the same on wide and
321 * narrow palinux.  Use ENTRY_DIFF for those where a 32-bit specific
322 * implementation is required on wide palinux.
323 */
324#define ENTRY_SAME(_name_) .dword sys_/**/_name_
325#define ENTRY_DIFF(_name_) .dword sys32_/**/_name_
326#define ENTRY_UHOH(_name_) .dword sys32_/**/unimplemented
327#else
328#define ENTRY_SAME(_name_) .word sys_/**/_name_
329#define ENTRY_DIFF(_name_) .word sys_/**/_name_
330#define ENTRY_UHOH(_name_) .word sys_/**/_name_
331#endif
332
333	.align 8
334	.export sys_call_table
335.Lsys_call_table:
336sys_call_table:
337	ENTRY_SAME(ni_syscall)	/* 0  -  old "setup()" system call*/
338	ENTRY_SAME(exit)
339	ENTRY_SAME(fork_wrapper)
340	ENTRY_SAME(read)
341	ENTRY_SAME(write)
342	ENTRY_SAME(open)		/* 5 */
343	ENTRY_SAME(close)
344	ENTRY_SAME(waitpid)
345	ENTRY_SAME(creat)
346	ENTRY_SAME(link)
347	ENTRY_SAME(unlink)		/* 10 */
348	ENTRY_DIFF(execve_wrapper)
349	ENTRY_SAME(chdir)
350	/* See comments in kernel/time.c!!! Maybe we don't need this? */
351	ENTRY_DIFF(time)
352	ENTRY_SAME(mknod)
353	ENTRY_SAME(chmod)		/* 15 */
354	ENTRY_SAME(lchown)
355	ENTRY_SAME(socket)
356	/* struct stat is MAYBE identical wide and narrow ?? */
357	ENTRY_DIFF(newstat)
358	ENTRY_DIFF(lseek)
359	ENTRY_SAME(getpid)		/* 20 */
360	/* the 'void * data' parameter may need re-packing in wide */
361	ENTRY_DIFF(mount)
362	/* concerned about struct sockaddr in wide/narrow */
363	/* ---> I think sockaddr is OK unless the compiler packs the struct */
364	/*      differently to align the char array */
365	ENTRY_SAME(bind)
366	ENTRY_SAME(setuid)
367	ENTRY_SAME(getuid)
368	ENTRY_SAME(stime)		/* 25 */
369	ENTRY_SAME(ptrace)
370	ENTRY_SAME(alarm)
371	/* see stat comment */
372	ENTRY_DIFF(newfstat)
373	ENTRY_SAME(pause)
374	/* struct utimbuf uses time_t which might vary */
375	ENTRY_DIFF(utime)		/* 30 */
376	/* struct sockaddr... */
377	ENTRY_SAME(connect)
378	ENTRY_SAME(listen)
379	ENTRY_SAME(access)
380	ENTRY_SAME(nice)
381	/* struct sockaddr... */
382	ENTRY_SAME(accept)		/* 35 */
383	ENTRY_SAME(sync)
384	ENTRY_SAME(kill)
385	ENTRY_SAME(rename)
386	ENTRY_SAME(mkdir)
387	ENTRY_SAME(rmdir)		/* 40 */
388	ENTRY_SAME(dup)
389	ENTRY_SAME(pipe)
390	ENTRY_DIFF(times)
391	/* struct sockaddr... */
392	ENTRY_SAME(getsockname)
393	/* it seems possible brk() could return a >4G pointer... */
394	ENTRY_SAME(brk)		/* 45 */
395	ENTRY_SAME(setgid)
396	ENTRY_SAME(getgid)
397	ENTRY_SAME(signal)
398	ENTRY_SAME(geteuid)
399	ENTRY_SAME(getegid)		/* 50 */
400	ENTRY_SAME(acct)
401	ENTRY_SAME(umount)
402	/* struct sockaddr... */
403	ENTRY_SAME(getpeername)
404	/* This one's a huge ugly mess */
405	ENTRY_DIFF(ioctl)
406	/* struct flock? */
407	ENTRY_DIFF(fcntl)		/* 55 */
408	ENTRY_SAME(socketpair)
409	ENTRY_SAME(setpgid)
410	ENTRY_SAME(send)
411	ENTRY_SAME(newuname)
412	ENTRY_SAME(umask)		/* 60 */
413	ENTRY_SAME(chroot)
414	ENTRY_SAME(ustat)
415	ENTRY_SAME(dup2)
416	ENTRY_SAME(getppid)
417	ENTRY_SAME(getpgrp)		/* 65 */
418	ENTRY_SAME(setsid)
419	ENTRY_SAME(pivot_root)
420	/* I don't like this */
421	ENTRY_UHOH(sgetmask)
422	ENTRY_UHOH(ssetmask)
423	ENTRY_SAME(setreuid)	/* 70 */
424	ENTRY_SAME(setregid)
425	ENTRY_SAME(mincore)
426	ENTRY_DIFF(sigpending)
427	ENTRY_SAME(sethostname)
428	/* Following 3 have linux-common-code structs containing longs -( */
429	ENTRY_DIFF(setrlimit)	/* 75 */
430	ENTRY_DIFF(getrlimit)
431	ENTRY_DIFF(getrusage)
432	/* struct timeval and timezone are maybe?? consistent wide and narrow */
433	ENTRY_DIFF(gettimeofday)
434	ENTRY_DIFF(settimeofday)
435	ENTRY_SAME(getgroups)	/* 80 */
436	ENTRY_SAME(setgroups)
437	/* struct socketaddr... */
438	ENTRY_SAME(sendto)
439	ENTRY_SAME(symlink)
440	/* see stat comment */
441	ENTRY_DIFF(newlstat)
442	ENTRY_SAME(readlink)	/* 85 */
443	/* suspect we'll need some work for narrow shlibs on wide kernel */
444	/* NOTE this doesn't get used when I boot 32-bit userspace */
445	/* containing working shlib apps -- can this be nuked? */
446	ENTRY_UHOH(uselib)
447	ENTRY_SAME(swapon)
448	ENTRY_SAME(reboot)
449	ENTRY_SAME(mmap2)
450	ENTRY_SAME(mmap)		/* 90 */
451	ENTRY_SAME(munmap)
452	ENTRY_SAME(truncate)
453	ENTRY_SAME(ftruncate)
454	ENTRY_SAME(fchmod)
455	ENTRY_SAME(fchown)		/* 95 */
456	ENTRY_SAME(getpriority)
457	ENTRY_SAME(setpriority)
458	ENTRY_SAME(recv)
459	ENTRY_DIFF(statfs)
460	ENTRY_DIFF(fstatfs)		/* 100 */
461	ENTRY_SAME(stat64)
462	/* don't think hppa glibc even provides an entry pt for this
463	 * so disable for now */
464	ENTRY_UHOH(socketcall)
465	ENTRY_SAME(syslog)
466	/* even though manpage says struct timeval contains longs, ours has
467	 * time_t and suseconds_t -- both of which are safe wide/narrow */
468	ENTRY_DIFF(setitimer)
469	ENTRY_DIFF(getitimer)	/* 105 */
470	ENTRY_SAME(capget)
471	ENTRY_SAME(capset)
472	ENTRY_DIFF(pread)
473	ENTRY_DIFF(pwrite)
474	ENTRY_SAME(getcwd)		/* 110 */
475	ENTRY_SAME(vhangup)
476	ENTRY_SAME(fstat64)
477	ENTRY_SAME(vfork_wrapper)
478	/* struct rusage contains longs... */
479	ENTRY_DIFF(wait4)
480	ENTRY_SAME(swapoff)		/* 115 */
481	ENTRY_DIFF(sysinfo)
482	ENTRY_SAME(shutdown)
483	ENTRY_SAME(fsync)
484	ENTRY_SAME(madvise)
485	ENTRY_SAME(clone_wrapper)	/* 120 */
486	ENTRY_SAME(setdomainname)
487	ENTRY_SAME(sendfile)
488	/* struct sockaddr... */
489	ENTRY_SAME(recvfrom)
490	/* struct timex contains longs */
491	ENTRY_DIFF(adjtimex)
492	ENTRY_SAME(mprotect)	/* 125 */
493	/* old_sigset_t forced to 32 bits.  Beware glibc sigset_t */
494	ENTRY_DIFF(sigprocmask)
495	ENTRY_SAME(create_module)
496	/* struct module contains longs, but insmod builds a 64 bit struct
497	 * if running under a 64 bit kernel */
498	ENTRY_SAME(init_module)
499	ENTRY_SAME(delete_module)
500	/* struct kernel_sym contains a long. Linus never heard of size_t? */
501	ENTRY_DIFF(get_kernel_syms)	/* 130 */
502	/* time_t inside struct dqblk */
503	ENTRY_DIFF(quotactl)
504	ENTRY_SAME(getpgid)
505	ENTRY_SAME(fchdir)
506	ENTRY_SAME(bdflush)
507	ENTRY_SAME(sysfs)		/* 135 */
508	ENTRY_SAME(personality)
509	ENTRY_SAME(ni_syscall)	/* for afs_syscall */
510	ENTRY_SAME(setfsuid)
511	ENTRY_SAME(setfsgid)
512	/* I think this might work */
513	ENTRY_SAME(llseek)		/* 140 */
514	/* struct linux_dirent has longs, like 'unsigned long d_ino' which
515	 * almost definitely should be 'ino_t d_ino' but it's too late now */
516	ENTRY_DIFF(getdents)
517	/* it is POSSIBLE that select will be OK because even though fd_set
518	 * contains longs, the macros and sizes are clever. */
519	ENTRY_DIFF(select)
520	ENTRY_SAME(flock)
521	ENTRY_SAME(msync)
522	/* struct iovec contains pointers */
523	ENTRY_DIFF(readv)		/* 145 */
524	ENTRY_DIFF(writev)
525	ENTRY_SAME(getsid)
526	ENTRY_SAME(fdatasync)
527	/* struct __sysctl_args is a mess */
528	ENTRY_DIFF(sysctl)
529	ENTRY_SAME(mlock)		/* 150 */
530	ENTRY_SAME(munlock)
531	ENTRY_SAME(mlockall)
532	ENTRY_SAME(munlockall)
533	/* struct sched_param is ok for now */
534	ENTRY_SAME(sched_setparam)
535	ENTRY_SAME(sched_getparam)	/* 155 */
536	ENTRY_SAME(sched_setscheduler)
537	ENTRY_SAME(sched_getscheduler)
538	ENTRY_SAME(sched_yield)
539	ENTRY_SAME(sched_get_priority_max)
540	ENTRY_SAME(sched_get_priority_min)	/* 160 */
541	/* These 2 would've worked if someone had defined struct timespec
542	 * carefully, like timeval for example (which is about the same).
543	 * Unfortunately it contains a long :-( */
544	ENTRY_DIFF(sched_rr_get_interval)
545	ENTRY_DIFF(nanosleep)
546	ENTRY_SAME(mremap)
547	ENTRY_SAME(setresuid)
548	ENTRY_SAME(getresuid)	/* 165 */
549	ENTRY_DIFF(sigaltstack_wrapper)
550	/* struct passed back to user can contain long symbol values */
551	ENTRY_DIFF(query_module)
552	ENTRY_SAME(poll)
553	/* structs contain pointers and an in_addr... */
554	ENTRY_DIFF(nfsservctl)
555	ENTRY_SAME(setresgid)	/* 170 */
556	ENTRY_SAME(getresgid)
557	ENTRY_SAME(prctl)
558	/* signals need a careful review */
559	ENTRY_SAME(rt_sigreturn_wrapper)
560	ENTRY_DIFF(rt_sigaction)
561	ENTRY_DIFF(rt_sigprocmask)	/* 175 */
562	ENTRY_DIFF(rt_sigpending)
563	ENTRY_UHOH(rt_sigtimedwait)
564	/* even though the struct siginfo_t is different, it appears like
565	 * all the paths use values which should be same wide and narrow.
566	 * Also the struct is padded to 128 bytes which means we don't have
567	 * to worry about faulting trying to copy in a larger 64-bit
568	 * struct from a 32-bit user-space app.
569	 */
570	ENTRY_SAME(rt_sigqueueinfo)
571	ENTRY_SAME(rt_sigsuspend_wrapper) /* not really SAME -- see the code */
572	ENTRY_SAME(chown)		/* 180 */
573	/* setsockopt() used by iptables: SO_SET_REPLACE/SO_SET_ADD_COUNTERS */
574	ENTRY_DIFF(setsockopt)
575	ENTRY_SAME(getsockopt)
576	ENTRY_DIFF(sendmsg)
577	ENTRY_DIFF(recvmsg)
578	ENTRY_SAME(semop)		/* 185 */
579	ENTRY_SAME(semget)
580	ENTRY_DIFF(semctl_broken)
581	ENTRY_DIFF(msgsnd)
582	ENTRY_DIFF(msgrcv)
583	ENTRY_SAME(msgget)		/* 190 */
584	ENTRY_SAME(msgctl_broken)
585	ENTRY_SAME(shmat_wrapper)
586	ENTRY_SAME(shmdt)
587	ENTRY_SAME(shmget)
588	ENTRY_SAME(shmctl_broken)		/* 195 */
589	ENTRY_SAME(ni_syscall)		/* streams1 */
590	ENTRY_SAME(ni_syscall)		/* streams2 */
591	ENTRY_SAME(lstat64)
592	ENTRY_DIFF(truncate64)
593	ENTRY_DIFF(ftruncate64)	/* 200 */
594	ENTRY_SAME(getdents64)
595	ENTRY_DIFF(fcntl64)
596#ifdef CONFIG_XFS_FS
597	ENTRY_SAME(attrctl)
598	ENTRY_SAME(acl_get)
599	ENTRY_SAME(acl_set)            /* 205 */
600#else
601	ENTRY_SAME(ni_syscall)
602	ENTRY_SAME(ni_syscall)
603	ENTRY_SAME(ni_syscall)	       /* 205 */
604#endif
605	ENTRY_SAME(gettid)
606	ENTRY_SAME(readahead)
607	ENTRY_SAME(tkill)
608
609.end
610
611	/* Make sure nothing else is placed on this page */
612
613	.align 4096
614	.export end_linux_gateway_page
615end_linux_gateway_page:
616
617