2 * Linux/PA-RISC Project (http://www.parisc-linux.org/)
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..
10 #include <asm/offsets.h>
11 #include <asm/unistd.h>
12 #include <asm/errno.h>
14 #include <asm/thread_info.h>
16 #include <asm/assembly.h>
17 #include <asm/processor.h>
26 .import syscall_exit,code
27 .import syscall_exit_rfi,code
28 .export linux_gateway_page
30 /* Linux gateway page is aliased to virtual page 0 in the kernel
31 * address space. Since it is a gateway page it cannot be
32 * dereferenced, so null pointers will still fault. We start
33 * the actual entry point at 0x100. We put break instructions
34 * at the beginning of the page to trap null indirect function
46 gate .+8, %r0 /* increase privilege */
47 depi 3, 31, 2, %r31 /* Ensure we return into user mode. */
48 be 0(%sr7,%r31) /* return to user space */
49 mtctl %r26, %cr27 /* move arg0 to the control register */
55 /* This address must remain fixed, or user binaries go splat. */
58 gate .+8, %r0 /* become privileged */
59 mtsp %r0,%sr4 /* get kernel space into sr4 */
60 mtsp %r0,%sr5 /* get kernel space into sr5 */
61 mtsp %r0,%sr6 /* get kernel space into sr6 */
62 mfsp %sr7,%r1 /* save user sr7 */
63 mtsp %r1,%sr3 /* and store it in sr3 */
66 /* for now we can *always* set the W bit on entry to the syscall
67 * since we don't support wide userland processes. We could
68 * also save the current SM other than in r0 and restore it on
69 * exit from the syscall, and also use that value to know
70 * whether to do narrow or wide syscalls. -PB
73 extrd,u %r1,PSW_W_BIT,1,%r1
74 /* sp must be aligned on 4, so deposit the W bit setting into
75 * the bottom of sp temporarily */
78 /* The top halves of argument registers must be cleared on syscall
79 * entry from narrow executable.
90 xor %r1,%r30,%r30 /* ye olde xor trick */
94 ldo THREAD_SZ_ALGN+FRAME_SIZE(%r30),%r30 /* set up kernel stack */
96 /* N.B.: It is critical that we don't set sr7 to 0 until r30
97 * contains a valid kernel stack pointer. It is also
98 * critical that we don't start using the kernel stack
99 * until after sr7 has been set to 0.
102 mtsp %r0,%sr7 /* get kernel space into sr7 */
103 STREGM %r1,FRAME_SIZE(%r30) /* save r1 (usp) here for now */
104 mfctl %cr30,%r1 /* get task ptr in %r1 */
105 LDREG TI_TASK(%r1),%r1
107 /* Save some registers for sigcontext and potential task
108 switch (see entry.S for the details of which ones are
109 saved/restored). TASK_PT_PSW is zeroed so we can see whether
110 a process is on a syscall or not. For an interrupt the real
111 PSW value is stored. This is needed for gdb and sys_ptrace. */
112 STREG %r0, TASK_PT_PSW(%r1)
113 STREG %r2, TASK_PT_GR2(%r1) /* preserve rp */
114 STREG %r19, TASK_PT_GR19(%r1)
116 LDREGM -FRAME_SIZE(%r30), %r2 /* get users sp back */
118 extrd,u %r2,63,1,%r19 /* W hidden in bottom bit */
120 xor %r19,%r2,%r2 /* clear bottom bit */
122 std %r19,TASK_PT_PSW(%r1)
125 STREG %r2, TASK_PT_GR30(%r1) /* ... and save it */
127 STREG %r20, TASK_PT_GR20(%r1)
128 STREG %r21, TASK_PT_GR21(%r1)
129 STREG %r22, TASK_PT_GR22(%r1)
130 STREG %r23, TASK_PT_GR23(%r1) /* 4th argument */
131 STREG %r24, TASK_PT_GR24(%r1) /* 3rd argument */
132 STREG %r25, TASK_PT_GR25(%r1) /* 2nd argument */
133 STREG %r26, TASK_PT_GR26(%r1) /* 1st argument */
134 STREG %r27, TASK_PT_GR27(%r1) /* user dp */
135 STREG %r28, TASK_PT_GR28(%r1) /* return value 0 */
136 STREG %r28, TASK_PT_ORIG_R28(%r1) /* return value 0 (saved for signals) */
137 STREG %r29, TASK_PT_GR29(%r1) /* return value 1 */
138 STREG %r31, TASK_PT_GR31(%r1) /* preserve syscall return ptr */
140 ldo TASK_PT_FR0(%r1), %r27 /* save fpregs from the kernel */
141 save_fp %r27 /* or potential task switch */
143 mfctl %cr11, %r27 /* i.e. SAR */
144 STREG %r27, TASK_PT_SAR(%r1)
149 ldo -16(%r30),%r29 /* Reference param save area */
150 copy %r19,%r2 /* W bit back to r2 */
152 /* no need to save these on stack in wide mode because the first 8
153 * args are passed in registers */
154 stw %r22, -52(%r30) /* 5th argument */
155 stw %r21, -56(%r30) /* 6th argument */
159 LDREG TI_FLAGS(%r1), %r19
160 bb,<,n %r19,31-TIF_SYSCALL_TRACE,.Ltracesys
162 /* Note! We cannot use the syscall table that is mapped
163 nearby since the gateway page is mapped execute-only. */
166 ldil L%sys_call_table, %r1
168 addil L%(sys_call_table64-sys_call_table), %r1
169 ldo R%sys_call_table(%r1), %r19
171 ldo R%sys_call_table64(%r1), %r19
173 ldil L%sys_call_table, %r1
174 ldo R%sys_call_table(%r1), %r19
176 comiclr,>>= __NR_Linux_syscalls, %r20, %r0
180 ldd,s %r20(%r19), %r19
182 ldwx,s %r20(%r19), %r19
184 /* If this is a sys_rt_sigreturn call, and the signal was received
185 * when not in_syscall, then we want to return via syscall_exit_rfi,
186 * not syscall_exit. Signal no. in r20, in_syscall in r25 (see
187 * trampoline code in signal.c).
189 ldi __NR_rt_sigreturn,%r2
190 comb,= %r2,%r20,.Lrt_sigreturn
192 ldil L%syscall_exit,%r2
194 ldo R%syscall_exit(%r2),%r2
196 comib,<> 0,%r25,.Lin_syscall
197 ldil L%syscall_exit_rfi,%r2
199 ldo R%syscall_exit_rfi(%r2),%r2
201 /* Note! Because we are not running where we were linked, any
202 calls to functions external to this file must be indirect. To
203 be safe, we apply the opposite rule to functions within this
204 file, with local labels given to them to ensure correctness. */
208 ldil L%syscall_exit,%r1
209 be R%syscall_exit(%sr7,%r1)
210 ldo -ENOSYS(%r0),%r28 /* set errno */
213 /* Warning! This trace code is a virtual duplicate of the code above so be
214 * sure to maintain both! */
217 /* Need to save more registers so the debugger can see where we
218 * are. This saves only the lower 8 bits of PSW, so that the C
219 * bit is still clear on syscalls, and the D bit is set if this
220 * full register save path has been executed. We check the D
221 * bit on syscall_return_rfi to determine which registers to
222 * restore. An interrupt results in a full PSW saved with the
223 * C bit set, a non-straced syscall entry results in C and D clear
226 ldo -THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1 /* get task ptr */
227 LDREG TI_TASK(%r1), %r1
229 STREG %r2,TASK_PT_PSW(%r1) /* Lower 8 bits only!! */
231 STREG %r2,TASK_PT_SR0(%r1)
233 STREG %r2,TASK_PT_SR1(%r1)
235 STREG %r2,TASK_PT_SR2(%r1)
237 STREG %r2,TASK_PT_SR3(%r1)
238 STREG %r2,TASK_PT_SR4(%r1)
239 STREG %r2,TASK_PT_SR5(%r1)
240 STREG %r2,TASK_PT_SR6(%r1)
241 STREG %r2,TASK_PT_SR7(%r1)
242 STREG %r2,TASK_PT_IASQ0(%r1)
243 STREG %r2,TASK_PT_IASQ1(%r1)
244 LDREG TASK_PT_GR31(%r1),%r2
245 STREG %r2,TASK_PT_IAOQ0(%r1)
247 STREG %r2,TASK_PT_IAOQ1(%r1)
248 ldo TASK_REGS(%r1),%r2
250 STREG %r3,PT_GR3(%r2)
251 STREG %r4,PT_GR4(%r2)
252 STREG %r5,PT_GR5(%r2)
253 STREG %r6,PT_GR6(%r2)
254 STREG %r7,PT_GR7(%r2)
255 STREG %r8,PT_GR8(%r2)
256 STREG %r9,PT_GR9(%r2)
257 STREG %r10,PT_GR10(%r2)
258 STREG %r11,PT_GR11(%r2)
259 STREG %r12,PT_GR12(%r2)
260 STREG %r13,PT_GR13(%r2)
261 STREG %r14,PT_GR14(%r2)
262 STREG %r15,PT_GR15(%r2)
263 STREG %r16,PT_GR16(%r2)
264 STREG %r17,PT_GR17(%r2)
265 STREG %r18,PT_GR18(%r2)
266 /* Finished saving things for the debugger */
268 ldil L%syscall_trace,%r1
269 ldil L%tracesys_next,%r2
270 be R%syscall_trace(%sr7,%r1)
271 ldo R%tracesys_next(%r2),%r2
274 ldil L%sys_call_table,%r1
275 ldo R%sys_call_table(%r1), %r19
277 ldo -THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1 /* get task ptr */
278 LDREG TI_TASK(%r1), %r1
279 LDREG TASK_PT_GR20(%r1), %r20
280 LDREG TASK_PT_GR26(%r1), %r26 /* Restore the users args */
281 LDREG TASK_PT_GR25(%r1), %r25
282 LDREG TASK_PT_GR24(%r1), %r24
283 LDREG TASK_PT_GR23(%r1), %r23
285 LDREG TASK_PT_GR22(%r1), %r22
286 LDREG TASK_PT_GR21(%r1), %r21
287 ldo -16(%r30),%r29 /* Reference param save area */
290 comiclr,>>= __NR_Linux_syscalls, %r20, %r0
294 ldd,s %r20(%r19), %r19
296 ldwx,s %r20(%r19), %r19
298 /* If this is a sys_rt_sigreturn call, and the signal was received
299 * when not in_syscall, then we want to return via syscall_exit_rfi,
300 * not syscall_exit. Signal no. in r20, in_syscall in r25 (see
301 * trampoline code in signal.c).
303 ldi __NR_rt_sigreturn,%r2
304 comb,= %r2,%r20,.Ltrace_rt_sigreturn
306 ldil L%tracesys_exit,%r2
308 ldo R%tracesys_exit(%r2),%r2
310 /* Do *not* call this function on the gateway page, because it
311 makes a direct call to syscall_trace. */
314 ldo -THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1 /* get task ptr */
315 LDREG TI_TASK(%r1), %r1
317 ldo -16(%r30),%r29 /* Reference param save area */
319 bl syscall_trace, %r2
320 STREG %r28,TASK_PT_GR28(%r1) /* save return value now */
321 ldo -THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1 /* get task ptr */
322 LDREG TI_TASK(%r1), %r1
323 LDREG TASK_PT_GR28(%r1), %r28 /* Restore return val. */
325 ldil L%syscall_exit,%r1
326 be,n R%syscall_exit(%sr7,%r1)
328 .Ltrace_rt_sigreturn:
329 comib,<> 0,%r25,.Ltrace_in_syscall
330 ldil L%tracesys_sigexit,%r2
332 ldo R%tracesys_sigexit(%r2),%r2
335 ldo -THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1 /* get task ptr */
338 ldo -16(%r30),%r29 /* Reference param save area */
340 bl syscall_trace, %r2
343 ldil L%syscall_exit_rfi,%r1
344 be,n R%syscall_exit_rfi(%sr7,%r1)
347 .export sys_call_table
350 #include "syscall_table.S"
354 .export sys_call_table64
357 #define SYSCALL_TABLE_64BIT
358 #include "syscall_table.S"
362 /* Make sure nothing else is placed on this page */
365 .export end_linux_gateway_page
366 end_linux_gateway_page: