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
45 linux_gateway_page:
46 
47         .rept 56
48         break   0,0
49         .endr
50 
51 set_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
63 linux_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:
185 syscall_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:
194 tracesys:
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         
250 tracesys_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         
289 tracesys_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 
308 tracesys_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:
336 sys_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         ENTRY_SAME(ni_syscall)          /* attrctl */
597         ENTRY_SAME(ni_syscall)          /* acl_get */
598         ENTRY_SAME(ni_syscall)          /* acl_set */
599         ENTRY_SAME(gettid)
600         ENTRY_SAME(readahead)          
601 
602 .end
603 
604         /* Make sure nothing else is placed on this page */
605 
606         .align 4096
607         .export end_linux_gateway_page
608 end_linux_gateway_page:
609