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 */
158 /* Are we being ptraced? */
160 LDREG TASK_PTRACE(%r1), %r1
161 bb,<,n %r1,31,.Ltracesys
163 /* Note! We cannot use the syscall table that is mapped
164 nearby since the gateway page is mapped execute-only. */
167 ldil L%sys_call_table, %r1
169 addil L%(sys_call_table64-sys_call_table), %r1
170 ldo R%sys_call_table(%r1), %r19
172 ldo R%sys_call_table64(%r1), %r19
174 ldil L%sys_call_table, %r1
175 ldo R%sys_call_table(%r1), %r19
177 comiclr,>>= __NR_Linux_syscalls, %r20, %r0
181 ldd,s %r20(%r19), %r19
183 ldwx,s %r20(%r19), %r19
185 /* If this is a sys_rt_sigreturn call, and the signal was received
186 * when not in_syscall, then we want to return via syscall_exit_rfi,
187 * not syscall_exit. Signal no. in r20, in_syscall in r25 (see
188 * trampoline code in signal.c).
190 ldi __NR_rt_sigreturn,%r2
191 comb,= %r2,%r20,.Lrt_sigreturn
193 ldil L%syscall_exit,%r2
195 ldo R%syscall_exit(%r2),%r2
197 comib,<> 0,%r25,.Lin_syscall
198 ldil L%syscall_exit_rfi,%r2
200 ldo R%syscall_exit_rfi(%r2),%r2
202 /* Note! Because we are not running where we were linked, any
203 calls to functions external to this file must be indirect. To
204 be safe, we apply the opposite rule to functions within this
205 file, with local labels given to them to ensure correctness. */
209 ldil L%syscall_exit,%r1
210 be R%syscall_exit(%sr7,%r1)
211 ldo -ENOSYS(%r0),%r28 /* set errno */
214 /* Warning! This trace code is a virtual duplicate of the code above so be
215 * sure to maintain both! */
218 /* Need to save more registers so the debugger can see where we
219 * are. This saves only the lower 8 bits of PSW, so that the C
220 * bit is still clear on syscalls, and the D bit is set if this
221 * full register save path has been executed. We check the D
222 * bit on syscall_return_rfi to determine which registers to
223 * restore. An interrupt results in a full PSW saved with the
224 * C bit set, a non-straced syscall entry results in C and D clear
227 ldo -THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1 /* get task ptr */
228 LDREG TI_TASK(%r1), %r1
230 STREG %r2,TASK_PT_PSW(%r1) /* Lower 8 bits only!! */
232 STREG %r2,TASK_PT_SR0(%r1)
234 STREG %r2,TASK_PT_SR1(%r1)
236 STREG %r2,TASK_PT_SR2(%r1)
238 STREG %r2,TASK_PT_SR3(%r1)
239 STREG %r2,TASK_PT_SR4(%r1)
240 STREG %r2,TASK_PT_SR5(%r1)
241 STREG %r2,TASK_PT_SR6(%r1)
242 STREG %r2,TASK_PT_SR7(%r1)
243 STREG %r2,TASK_PT_IASQ0(%r1)
244 STREG %r2,TASK_PT_IASQ1(%r1)
245 LDREG TASK_PT_GR31(%r1),%r2
246 STREG %r2,TASK_PT_IAOQ0(%r1)
248 STREG %r2,TASK_PT_IAOQ1(%r1)
249 ldo TASK_REGS(%r1),%r2
251 STREG %r3,PT_GR3(%r2)
252 STREG %r4,PT_GR4(%r2)
253 STREG %r5,PT_GR5(%r2)
254 STREG %r6,PT_GR6(%r2)
255 STREG %r7,PT_GR7(%r2)
256 STREG %r8,PT_GR8(%r2)
257 STREG %r9,PT_GR9(%r2)
258 STREG %r10,PT_GR10(%r2)
259 STREG %r11,PT_GR11(%r2)
260 STREG %r12,PT_GR12(%r2)
261 STREG %r13,PT_GR13(%r2)
262 STREG %r14,PT_GR14(%r2)
263 STREG %r15,PT_GR15(%r2)
264 STREG %r16,PT_GR16(%r2)
265 STREG %r17,PT_GR17(%r2)
266 STREG %r18,PT_GR18(%r2)
267 /* Finished saving things for the debugger */
269 ldil L%syscall_trace,%r1
270 ldil L%tracesys_next,%r2
271 be R%syscall_trace(%sr7,%r1)
272 ldo R%tracesys_next(%r2),%r2
275 ldil L%sys_call_table,%r1
276 ldo R%sys_call_table(%r1), %r19
278 ldo -THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1 /* get task ptr */
279 LDREG TI_TASK(%r1), %r1
280 LDREG TASK_PT_GR20(%r1), %r20
281 LDREG TASK_PT_GR26(%r1), %r26 /* Restore the users args */
282 LDREG TASK_PT_GR25(%r1), %r25
283 LDREG TASK_PT_GR24(%r1), %r24
284 LDREG TASK_PT_GR23(%r1), %r23
286 LDREG TASK_PT_GR22(%r1), %r22
287 LDREG TASK_PT_GR21(%r1), %r21
288 ldo -16(%r30),%r29 /* Reference param save area */
291 comiclr,>>= __NR_Linux_syscalls, %r20, %r0
295 ldd,s %r20(%r19), %r19
297 ldwx,s %r20(%r19), %r19
299 /* If this is a sys_rt_sigreturn call, and the signal was received
300 * when not in_syscall, then we want to return via syscall_exit_rfi,
301 * not syscall_exit. Signal no. in r20, in_syscall in r25 (see
302 * trampoline code in signal.c).
304 ldi __NR_rt_sigreturn,%r2
305 comb,= %r2,%r20,.Ltrace_rt_sigreturn
307 ldil L%tracesys_exit,%r2
309 ldo R%tracesys_exit(%r2),%r2
311 /* Do *not* call this function on the gateway page, because it
312 makes a direct call to syscall_trace. */
315 ldo -THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1 /* get task ptr */
316 LDREG TI_TASK(%r1), %r1
318 ldo -16(%r30),%r29 /* Reference param save area */
320 bl syscall_trace, %r2
321 STREG %r28,TASK_PT_GR28(%r1) /* save return value now */
322 ldo -THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1 /* get task ptr */
323 LDREG TI_TASK(%r1), %r1
324 LDREG TASK_PT_GR28(%r1), %r28 /* Restore return val. */
326 ldil L%syscall_exit,%r1
327 be,n R%syscall_exit(%sr7,%r1)
329 .Ltrace_rt_sigreturn:
330 comib,<> 0,%r25,.Ltrace_in_syscall
331 ldil L%tracesys_sigexit,%r2
333 ldo R%tracesys_sigexit(%r2),%r2
336 ldo -THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1 /* get task ptr */
339 ldo -16(%r30),%r29 /* Reference param save area */
341 bl syscall_trace, %r2
344 ldil L%syscall_exit_rfi,%r1
345 be,n R%syscall_exit_rfi(%sr7,%r1)
348 .export sys_call_table
351 #include "syscall_table.S"
355 .export sys_call_table64
358 #define SYSCALL_TABLE_64BIT
359 #include "syscall_table.S"
363 /* Make sure nothing else is placed on this page */
366 .export end_linux_gateway_page
367 end_linux_gateway_page: