xref: /linux/arch/alpha/kernel/entry.S (revision f4cdf7ca9a1fdcca413157df19753f388a5a224e)
1/* SPDX-License-Identifier: GPL-2.0 */
2/*
3 * arch/alpha/kernel/entry.S
4 *
5 * Kernel entry-points.
6 */
7
8#include <asm/asm-offsets.h>
9#include <asm/thread_info.h>
10#include <asm/pal.h>
11#include <asm/errno.h>
12#include <asm/unistd.h>
13#include <linux/errno.h>
14
15	.text
16	.set noat
17	.cfi_sections	.debug_frame
18
19.macro	CFI_START_OSF_FRAME	func
20	.align	4
21	.globl	\func
22	.type	\func,@function
23\func:
24	.cfi_startproc simple
25	.cfi_return_column 64
26	.cfi_def_cfa	$sp, 48
27	.cfi_rel_offset	64, 8
28	.cfi_rel_offset	$gp, 16
29	.cfi_rel_offset	$16, 24
30	.cfi_rel_offset	$17, 32
31	.cfi_rel_offset	$18, 40
32.endm
33
34.macro	CFI_END_OSF_FRAME	func
35	.cfi_endproc
36	.size	\func, . - \func
37.endm
38
39/*
40 * SYSCALL_SKIP_RETURN_RESTART_GATE
41 *
42 * Used when syscall dispatch is skipped (seccomp/ptrace injected nr=-1).
43 *  - Ensure we never return r0==-1 with a3==0 (success); convert to ENOSYS.
44 *  - Gate whether syscall restart is allowed by preserving restart context
45 *    only for ERESTART* returns. Result:
46 *        $26 = 0  => restart allowed
47 *        $26 = 1  => restart NOT allowed
48 *        $18 = preserved syscall nr (regs->r2) if restart allowed, else 0
49 */
50.macro  SYSCALL_SKIP_RETURN_RESTART_GATE
51	/* Fix up invalid "-1 success" return state. */
52	ldq	$19, 72($sp)		/* a3 */
53	bne	$19, 1f			/* already error => skip fixup */
54
55	ldq	$20, 0($sp)		/* r0 */
56	lda	$21, -1($31)
57	cmpeq	$20, $21, $22
58	beq	$22, 1f			/* r0 != -1 => skip fixup */
59
60
61	lda	$20, ENOSYS($31)
62	stq	$20, 0($sp)		/* r0 = ENOSYS */
63	lda	$19, 1($31)
64	stq	$19, 72($sp)		/* a3 = 1 */
651:
66	/* Restart gating: success is never restartable here. */
67	ldq	$19, 72($sp)		/* a3 */
68	beq	$19, 3f			/* success => not restartable */
69
70	ldq	$20, 0($sp)		/* r0 (positive errno if a3==1) */
71	lda	$21, ERESTARTSYS($31)
72	cmpeq	$20, $21, $22
73	bne	$22, 2f
74	lda	$21, ERESTARTNOINTR($31)
75	cmpeq	$20, $21, $22
76	bne	$22, 2f
77	lda	$21, ERESTARTNOHAND($31)
78	cmpeq	$20, $21, $22
79	bne	$22, 2f
80	lda	$21, ERESTART_RESTARTBLOCK($31)
81	cmpeq	$20, $21, $22
82	bne	$22, 2f
83
843:	/* Not a restart code (or success) => restart NOT allowed. */
85	addq	$31, 1, $26		/* $26=1 => restart NOT allowed */
86	mov	0, $18
87	br	4f
88
892:	/* Restart allowed. */
90	ldq	$18, 16($sp)		/* preserved syscall nr (regs->r2) */
91	mov	$31, $26		/* $26=0 => restart allowed */
92	br	4f
934:
94.endm
95
96.macro LOCKDEP_HARDIRQS_ON_RESTORE
97#ifdef CONFIG_PROVE_LOCKING
98	/* a0 = saved PS */
99	ldq	$16, SP_OFF($sp)
100
101	/* a1 = callsite IP for lockdep */
102	lda	$17, 1f
103
104	jsr	$26, lockdep_on_restore
105	ldgp	$gp, 0($26)
1061:
107#endif
108.endm
109
110/*
111 * This defines the normal kernel pt-regs layout.
112 *
113 * regs 9-15 preserved by C code
114 * regs 16-18 saved by PAL-code
115 * regs 29-30 saved and set up by PAL-code
116 * JRP - Save regs 16-18 in a special area of the stack, so that
117 * the palcode-provided values are available to the signal handler.
118 */
119
120.macro	SAVE_ALL
121	subq	$sp, SP_OFF, $sp
122	.cfi_adjust_cfa_offset	SP_OFF
123	stq	$0, 0($sp)
124	stq	$1, 8($sp)
125	stq	$2, 16($sp)
126	stq	$3, 24($sp)
127	stq	$4, 32($sp)
128	stq	$28, 144($sp)
129	.cfi_rel_offset	$0, 0
130	.cfi_rel_offset $1, 8
131	.cfi_rel_offset	$2, 16
132	.cfi_rel_offset	$3, 24
133	.cfi_rel_offset	$4, 32
134	.cfi_rel_offset	$28, 144
135	lda	$2, alpha_mv
136	stq	$5, 40($sp)
137	stq	$6, 48($sp)
138	stq	$7, 56($sp)
139	stq	$8, 64($sp)
140	stq	$19, 72($sp)
141	stq	$20, 80($sp)
142	stq	$21, 88($sp)
143	ldq	$2, HAE_CACHE($2)
144	stq	$22, 96($sp)
145	stq	$23, 104($sp)
146	stq	$24, 112($sp)
147	stq	$25, 120($sp)
148	stq	$26, 128($sp)
149	stq	$27, 136($sp)
150	stq	$2, 152($sp)
151	stq	$16, 160($sp)
152	stq	$17, 168($sp)
153	stq	$18, 176($sp)
154	.cfi_rel_offset	$5, 40
155	.cfi_rel_offset	$6, 48
156	.cfi_rel_offset	$7, 56
157	.cfi_rel_offset	$8, 64
158	.cfi_rel_offset $19, 72
159	.cfi_rel_offset	$20, 80
160	.cfi_rel_offset	$21, 88
161	.cfi_rel_offset $22, 96
162	.cfi_rel_offset	$23, 104
163	.cfi_rel_offset	$24, 112
164	.cfi_rel_offset	$25, 120
165	.cfi_rel_offset	$26, 128
166	.cfi_rel_offset	$27, 136
167.endm
168
169.macro	RESTORE_ALL
170	lda	$19, alpha_mv
171	ldq	$0, 0($sp)
172	ldq	$1, 8($sp)
173	ldq	$2, 16($sp)
174	ldq	$3, 24($sp)
175	ldq	$21, 152($sp)
176	ldq	$20, HAE_CACHE($19)
177	ldq	$4, 32($sp)
178	ldq	$5, 40($sp)
179	ldq	$6, 48($sp)
180	ldq	$7, 56($sp)
181	subq	$20, $21, $20
182	ldq	$8, 64($sp)
183	beq	$20, 99f
184	ldq	$20, HAE_REG($19)
185	stq	$21, HAE_CACHE($19)
186	stq	$21, 0($20)
18799:	ldq	$19, 72($sp)
188	ldq	$20, 80($sp)
189	ldq	$21, 88($sp)
190	ldq	$22, 96($sp)
191	ldq	$23, 104($sp)
192	ldq	$24, 112($sp)
193	ldq	$25, 120($sp)
194	ldq	$26, 128($sp)
195	ldq	$27, 136($sp)
196	ldq	$28, 144($sp)
197	addq	$sp, SP_OFF, $sp
198	.cfi_restore	$0
199	.cfi_restore	$1
200	.cfi_restore	$2
201	.cfi_restore	$3
202	.cfi_restore	$4
203	.cfi_restore	$5
204	.cfi_restore	$6
205	.cfi_restore	$7
206	.cfi_restore	$8
207	.cfi_restore	$19
208	.cfi_restore	$20
209	.cfi_restore	$21
210	.cfi_restore	$22
211	.cfi_restore	$23
212	.cfi_restore	$24
213	.cfi_restore	$25
214	.cfi_restore	$26
215	.cfi_restore	$27
216	.cfi_restore	$28
217	.cfi_adjust_cfa_offset	-SP_OFF
218.endm
219
220.macro	DO_SWITCH_STACK
221	bsr	$1, do_switch_stack
222	.cfi_adjust_cfa_offset	SWITCH_STACK_SIZE
223	.cfi_rel_offset	$9, 0
224	.cfi_rel_offset	$10, 8
225	.cfi_rel_offset	$11, 16
226	.cfi_rel_offset	$12, 24
227	.cfi_rel_offset	$13, 32
228	.cfi_rel_offset	$14, 40
229	.cfi_rel_offset	$15, 48
230.endm
231
232.macro	UNDO_SWITCH_STACK
233	bsr	$1, undo_switch_stack
234	.cfi_restore	$9
235	.cfi_restore	$10
236	.cfi_restore	$11
237	.cfi_restore	$12
238	.cfi_restore	$13
239	.cfi_restore	$14
240	.cfi_restore	$15
241	.cfi_adjust_cfa_offset	-SWITCH_STACK_SIZE
242.endm
243
244/*
245 * Non-syscall kernel entry points.
246 */
247
248CFI_START_OSF_FRAME entInt
249	SAVE_ALL
250	lda	$8, 0x3fff
251	lda	$26, ret_from_sys_call
252	bic	$sp, $8, $8
253	mov	$sp, $19
254	jsr	$31, do_entInt
255CFI_END_OSF_FRAME entInt
256
257CFI_START_OSF_FRAME entArith
258	SAVE_ALL
259	lda	$8, 0x3fff
260	lda	$26, ret_from_sys_call
261	bic	$sp, $8, $8
262	mov	$sp, $18
263	jsr	$31, do_entArith
264CFI_END_OSF_FRAME entArith
265
266CFI_START_OSF_FRAME entMM
267	SAVE_ALL
268/* save $9 - $15 so the inline exception code can manipulate them.  */
269	subq	$sp, 64, $sp
270	.cfi_adjust_cfa_offset	64
271	stq	$9, 0($sp)
272	stq	$10, 8($sp)
273	stq	$11, 16($sp)
274	stq	$12, 24($sp)
275	stq	$13, 32($sp)
276	stq	$14, 40($sp)
277	stq	$15, 48($sp)
278	.cfi_rel_offset	$9, 0
279	.cfi_rel_offset	$10, 8
280	.cfi_rel_offset	$11, 16
281	.cfi_rel_offset	$12, 24
282	.cfi_rel_offset	$13, 32
283	.cfi_rel_offset	$14, 40
284	.cfi_rel_offset	$15, 48
285	addq	$sp, 64, $19
286/* handle the fault */
287	lda	$8, 0x3fff
288	bic	$sp, $8, $8
289	jsr	$26, do_page_fault
290/* reload the registers after the exception code played.  */
291	ldq	$9, 0($sp)
292	ldq	$10, 8($sp)
293	ldq	$11, 16($sp)
294	ldq	$12, 24($sp)
295	ldq	$13, 32($sp)
296	ldq	$14, 40($sp)
297	ldq	$15, 48($sp)
298	addq	$sp, 64, $sp
299	.cfi_restore	$9
300	.cfi_restore	$10
301	.cfi_restore	$11
302	.cfi_restore	$12
303	.cfi_restore	$13
304	.cfi_restore	$14
305	.cfi_restore	$15
306	.cfi_adjust_cfa_offset	-64
307/* finish up the syscall as normal.  */
308	br	ret_from_sys_call
309CFI_END_OSF_FRAME entMM
310
311CFI_START_OSF_FRAME entIF
312	SAVE_ALL
313	lda	$8, 0x3fff
314	lda	$26, ret_from_sys_call
315	bic	$sp, $8, $8
316	mov	$sp, $17
317	jsr	$31, do_entIF
318CFI_END_OSF_FRAME entIF
319
320CFI_START_OSF_FRAME entUna
321	lda	$sp, -256($sp)
322	.cfi_adjust_cfa_offset	256
323	stq	$0, 0($sp)
324	.cfi_rel_offset	$0, 0
325	.cfi_remember_state
326	ldq	$0, 256($sp)	/* get PS */
327	stq	$1, 8($sp)
328	stq	$2, 16($sp)
329	stq	$3, 24($sp)
330	and	$0, 8, $0		/* user mode? */
331	stq	$4, 32($sp)
332	bne	$0, entUnaUser	/* yup -> do user-level unaligned fault */
333	stq	$5, 40($sp)
334	stq	$6, 48($sp)
335	stq	$7, 56($sp)
336	stq	$8, 64($sp)
337	stq	$9, 72($sp)
338	stq	$10, 80($sp)
339	stq	$11, 88($sp)
340	stq	$12, 96($sp)
341	stq	$13, 104($sp)
342	stq	$14, 112($sp)
343	stq	$15, 120($sp)
344	/* 16-18 PAL-saved */
345	stq	$19, 152($sp)
346	stq	$20, 160($sp)
347	stq	$21, 168($sp)
348	stq	$22, 176($sp)
349	stq	$23, 184($sp)
350	stq	$24, 192($sp)
351	stq	$25, 200($sp)
352	stq	$26, 208($sp)
353	stq	$27, 216($sp)
354	stq	$28, 224($sp)
355	mov	$sp, $19
356	stq	$gp, 232($sp)
357	.cfi_rel_offset	$1, 1*8
358	.cfi_rel_offset	$2, 2*8
359	.cfi_rel_offset	$3, 3*8
360	.cfi_rel_offset	$4, 4*8
361	.cfi_rel_offset	$5, 5*8
362	.cfi_rel_offset	$6, 6*8
363	.cfi_rel_offset	$7, 7*8
364	.cfi_rel_offset	$8, 8*8
365	.cfi_rel_offset	$9, 9*8
366	.cfi_rel_offset	$10, 10*8
367	.cfi_rel_offset	$11, 11*8
368	.cfi_rel_offset	$12, 12*8
369	.cfi_rel_offset	$13, 13*8
370	.cfi_rel_offset	$14, 14*8
371	.cfi_rel_offset	$15, 15*8
372	.cfi_rel_offset	$19, 19*8
373	.cfi_rel_offset	$20, 20*8
374	.cfi_rel_offset	$21, 21*8
375	.cfi_rel_offset	$22, 22*8
376	.cfi_rel_offset	$23, 23*8
377	.cfi_rel_offset	$24, 24*8
378	.cfi_rel_offset	$25, 25*8
379	.cfi_rel_offset	$26, 26*8
380	.cfi_rel_offset	$27, 27*8
381	.cfi_rel_offset	$28, 28*8
382	.cfi_rel_offset	$29, 29*8
383	lda	$8, 0x3fff
384	stq	$31, 248($sp)
385	bic	$sp, $8, $8
386	jsr	$26, do_entUna
387	ldq	$0, 0($sp)
388	ldq	$1, 8($sp)
389	ldq	$2, 16($sp)
390	ldq	$3, 24($sp)
391	ldq	$4, 32($sp)
392	ldq	$5, 40($sp)
393	ldq	$6, 48($sp)
394	ldq	$7, 56($sp)
395	ldq	$8, 64($sp)
396	ldq	$9, 72($sp)
397	ldq	$10, 80($sp)
398	ldq	$11, 88($sp)
399	ldq	$12, 96($sp)
400	ldq	$13, 104($sp)
401	ldq	$14, 112($sp)
402	ldq	$15, 120($sp)
403	/* 16-18 PAL-saved */
404	ldq	$19, 152($sp)
405	ldq	$20, 160($sp)
406	ldq	$21, 168($sp)
407	ldq	$22, 176($sp)
408	ldq	$23, 184($sp)
409	ldq	$24, 192($sp)
410	ldq	$25, 200($sp)
411	ldq	$26, 208($sp)
412	ldq	$27, 216($sp)
413	ldq	$28, 224($sp)
414	ldq	$gp, 232($sp)
415	lda	$sp, 256($sp)
416	.cfi_restore	$1
417	.cfi_restore	$2
418	.cfi_restore	$3
419	.cfi_restore	$4
420	.cfi_restore	$5
421	.cfi_restore	$6
422	.cfi_restore	$7
423	.cfi_restore	$8
424	.cfi_restore	$9
425	.cfi_restore	$10
426	.cfi_restore	$11
427	.cfi_restore	$12
428	.cfi_restore	$13
429	.cfi_restore	$14
430	.cfi_restore	$15
431	.cfi_restore	$19
432	.cfi_restore	$20
433	.cfi_restore	$21
434	.cfi_restore	$22
435	.cfi_restore	$23
436	.cfi_restore	$24
437	.cfi_restore	$25
438	.cfi_restore	$26
439	.cfi_restore	$27
440	.cfi_restore	$28
441	.cfi_restore	$29
442	.cfi_adjust_cfa_offset	-256
443	LOCKDEP_HARDIRQS_ON_RESTORE
444	call_pal PAL_rti
445
446	.align	4
447entUnaUser:
448	.cfi_restore_state
449	ldq	$0, 0($sp)	/* restore original $0 */
450	lda	$sp, 256($sp)	/* pop entUna's stack frame */
451	.cfi_restore	$0
452	.cfi_adjust_cfa_offset	-256
453	SAVE_ALL		/* setup normal kernel stack */
454	lda	$sp, -64($sp)
455	.cfi_adjust_cfa_offset	64
456	stq	$9, 0($sp)
457	stq	$10, 8($sp)
458	stq	$11, 16($sp)
459	stq	$12, 24($sp)
460	stq	$13, 32($sp)
461	stq	$14, 40($sp)
462	stq	$15, 48($sp)
463	.cfi_rel_offset	$9, 0
464	.cfi_rel_offset	$10, 8
465	.cfi_rel_offset	$11, 16
466	.cfi_rel_offset	$12, 24
467	.cfi_rel_offset	$13, 32
468	.cfi_rel_offset	$14, 40
469	.cfi_rel_offset	$15, 48
470	lda	$8, 0x3fff
471	addq	$sp, 64, $19
472	bic	$sp, $8, $8
473	jsr	$26, do_entUnaUser
474	ldq	$9, 0($sp)
475	ldq	$10, 8($sp)
476	ldq	$11, 16($sp)
477	ldq	$12, 24($sp)
478	ldq	$13, 32($sp)
479	ldq	$14, 40($sp)
480	ldq	$15, 48($sp)
481	lda	$sp, 64($sp)
482	.cfi_restore	$9
483	.cfi_restore	$10
484	.cfi_restore	$11
485	.cfi_restore	$12
486	.cfi_restore	$13
487	.cfi_restore	$14
488	.cfi_restore	$15
489	.cfi_adjust_cfa_offset	-64
490	br	ret_from_sys_call
491CFI_END_OSF_FRAME entUna
492
493CFI_START_OSF_FRAME entDbg
494	SAVE_ALL
495	lda	$8, 0x3fff
496	lda	$26, ret_from_sys_call
497	bic	$sp, $8, $8
498	mov	$sp, $16
499	jsr	$31, do_entDbg
500CFI_END_OSF_FRAME entDbg
501
502/*
503 * The system call entry point is special.  Most importantly, it looks
504 * like a function call to userspace as far as clobbered registers.  We
505 * do preserve the argument registers (for syscall restarts) and $26
506 * (for leaf syscall functions).
507 *
508 * So much for theory.  We don't take advantage of this yet.
509 *
510 * Note that a0-a2 are not saved by PALcode as with the other entry points.
511 *
512 * Alpha syscall ABI uses:
513 *   - r0 for return value
514 *   - r19 ("a3") as error indicator (0=success, 1=error; r0 holds errno)
515 *
516 * For seccomp/ptrace/generic syscall helpers we track the syscall
517 * number separately:
518 *   - regs->r1: current (mutable) syscall number (may be changed or set to -1)
519 *   - regs->r2: original syscall number for restart/rollback
520 *
521 * On entry PAL provides the syscall number in r0; copy it into r1/r2.
522 */
523
524	.align	4
525	.globl	entSys
526	.type	entSys, @function
527	.cfi_startproc simple
528	.cfi_return_column 64
529	.cfi_def_cfa	$sp, 48
530	.cfi_rel_offset	64, 8
531	.cfi_rel_offset	$gp, 16
532entSys:
533	SAVE_ALL
534        ldq     $1, 0($sp)          /* syscall nr from saved r0 */
535        stq     $1, 8($sp)          /* regs->r1 = shadow syscall nr */
536        stq     $1, 16($sp)         /* regs->r2 = restart syscall nr */
537	/* Syscalls always enter from user mode: snapshot USP into pt_regs->usp */
538	mov	$0, $8
539	call_pal PAL_rdusp
540	stq      $0, PT_REGS_USP($sp)
541	mov	$8, $0
542
543
544	lda	$8, 0x3fff
545	bic	$sp, $8, $8
546	lda	$4, NR_syscalls($31)
547	stq	$16, SP_OFF+24($sp)
548	lda	$5, sys_call_table
549	lda	$27, sys_ni_syscall
550	cmpult	$0, $4, $4
551	ldl	$3, TI_FLAGS($8)
552	stq	$17, SP_OFF+32($sp)
553	s8addq	$0, $5, $5
554	stq	$18, SP_OFF+40($sp)
555	.cfi_rel_offset	$16, SP_OFF+24
556	.cfi_rel_offset	$17, SP_OFF+32
557	.cfi_rel_offset	$18, SP_OFF+40
558	lda     $6, _TIF_SYSCALL_WORK
559	and     $3, $6, $3
560	bne     $3, strace
561
562	beq	$4, 1f
563	ldq	$27, 0($5)
5641:	ldq	$0, 8($sp)		/* syscall nr shadow (regs->r1) */
565
566	jsr	$26, ($27), sys_ni_syscall
567	ldgp	$gp, 0($26)
568	blt	$0, $syscall_error	/* the call failed */
569$ret_success:
570	stq	$0, 0($sp)
571	stq	$31, 72($sp)		/* a3=0 => no error */
572
573	.align	4
574	.globl	ret_from_sys_call
575ret_from_sys_call:
576	cmovne	$26, 0, $18		/* $18 = 0 => non-restartable */
577	ldq	$0, SP_OFF($sp)
578	and	$0, 8, $0
579	beq	$0, ret_to_kernel
580ret_to_user:
581	/* Make sure need_resched and sigpending don't change between
582		sampling and the rti.  */
583	lda	$16, 7
584	call_pal PAL_swpipl
585	ldl	$17, TI_FLAGS($8)
586	and	$17, _TIF_WORK_MASK, $2
587	bne	$2, work_pending
588restore_all:
589	ldl	$2, TI_STATUS($8)
590	and	$2, TS_SAVED_FP | TS_RESTORE_FP, $3
591	bne	$3, restore_fpu
592restore_other:
593	.cfi_remember_state
594	LOCKDEP_HARDIRQS_ON_RESTORE
595	RESTORE_ALL
596	call_pal PAL_rti
597
598ret_to_kernel:
599	.cfi_restore_state
600	lda	$16, 7
601	call_pal PAL_swpipl
602	br restore_other
603
604	.align 3
605$syscall_error:
606        /* Restart syscall nr comes from saved r2 (preserved even if r0 overwritten). */
607	ldq	$18, 16($sp)	/* old syscall nr for restart */
608
609	ldq	$19, 72($sp)	/* .. and this a3 */
610	subq	$31, $0, $0	/* with error in v0 */
611	addq	$31, 1, $1	/* set a3 for errno return */
612	stq	$0, 0($sp)
613	mov	$31, $26	/* tell "ret_from_sys_call" we can restart */
614	stq	$1, 72($sp)	/* a3 for return */
615	br	ret_from_sys_call
616
617/*
618 * Do all cleanup when returning from all interrupts and system calls.
619 *
620 * Arguments:
621 *       $8: current.
622 *      $17: TI_FLAGS.
623 *      $18: The old syscall number, or zero if this is not a return
624 *           from a syscall that errored and is possibly restartable.
625 *      $19: The old a3 value
626 */
627
628	.align	4
629	.type	work_pending, @function
630work_pending:
631	and	$17, _TIF_NOTIFY_RESUME | _TIF_SIGPENDING | _TIF_NOTIFY_SIGNAL, $2
632	bne	$2, $work_notifysig
633
634$work_resched:
635	/*
636	 * We can get here only if we returned from syscall without SIGPENDING
637	 * or got through work_notifysig already.  Either case means no syscall
638	 * restarts for us, so let $18 and $19 burn.
639	 */
640	jsr	$26, alpha_schedule_user_work
641	mov	0, $18
642	br	ret_to_user
643
644$work_notifysig:
645	mov	$sp, $16
646	DO_SWITCH_STACK
647	jsr	$26, do_work_pending
648	UNDO_SWITCH_STACK
649	br	restore_all
650
651/*
652 * PTRACE syscall handler
653 */
654
655	.align	4
656	.type	strace, @function
657strace:
658	/* set up signal stack, call syscall_trace */
659	// NB: if anyone adds preemption, this block will need to be protected
660	ldl	$1, TI_STATUS($8)
661	and	$1, TS_SAVED_FP, $3
662	or	$1, TS_SAVED_FP, $2
663	bne	$3, 1f
664	stl	$2, TI_STATUS($8)
665	bsr	$26, __save_fpu
6661:
667	DO_SWITCH_STACK
668	jsr	$26, syscall_trace_enter /* returns the syscall number */
669	UNDO_SWITCH_STACK
670
671	stq     $0, 8($sp)		/* regs->r1 = shadow syscall nr */
672
673	/* get the arguments back.. */
674	ldq	$16, SP_OFF+24($sp)
675	ldq	$17, SP_OFF+32($sp)
676	ldq	$18, SP_OFF+40($sp)
677	ldq	$19, 72($sp)
678	ldq	$20, 80($sp)
679	ldq	$21, 88($sp)
680
681	/* nr == -1: internal skip-dispatch or userspace syscall(-1)? */
682        lda     $6, -1($31)
683        cmpeq   $0, $6, $6
684	bne	$6, $strace_skip_call	/* nr == -1 => dispatch */
685
686	/* get the system call pointer.. */
687	lda	$1, NR_syscalls($31)
688	lda	$2, sys_call_table
689	lda	$27, sys_ni_syscall
690	cmpult	$0, $1, $1
691	s8addq	$0, $2, $2
692	beq	$1, 1f
693	ldq	$27, 0($2)
6941:	jsr	$26, ($27), sys_gettimeofday
695ret_from_straced:
696	ldgp	$gp, 0($26)
697
698	/* check return.. */
699	blt	$0, $strace_error	/* the call failed */
700$strace_success:
701	stq	$31, 72($sp)		/* a3=0 => no error */
702	stq	$0, 0($sp)		/* save return value */
703
704$strace_skip_call:
705	SYSCALL_SKIP_RETURN_RESTART_GATE
706	DO_SWITCH_STACK
707	jsr	$26, syscall_trace_leave
708	UNDO_SWITCH_STACK
709	br	$31, ret_from_sys_call
710
711	.align	3
712$strace_error:
713	ldq	$18, 16($sp)	/* restart syscall nr */
714	ldq	$19, 72($sp)	/* .. and this a3 */
715
716	subq	$31, $0, $0	/* with error in v0 */
717	addq	$31, 1, $1	/* set a3 for errno return */
718	stq	$0, 0($sp)
719	stq	$1, 72($sp)	/* a3 for return */
720
721	DO_SWITCH_STACK
722	mov	$18, $9		/* save old syscall number */
723	mov	$19, $10	/* save old a3 */
724	jsr	$26, syscall_trace_leave
725	mov	$9, $18
726	mov	$10, $19
727	UNDO_SWITCH_STACK
728
729	mov	$31, $26	/* tell "ret_from_sys_call" we can restart */
730	br	ret_from_sys_call
731CFI_END_OSF_FRAME entSys
732
733/*
734 * Save and restore the switch stack -- aka the balance of the user context.
735 */
736
737	.align	4
738	.type	do_switch_stack, @function
739	.cfi_startproc simple
740	.cfi_return_column 64
741	.cfi_def_cfa $sp, 0
742	.cfi_register 64, $1
743do_switch_stack:
744	lda	$sp, -SWITCH_STACK_SIZE($sp)
745	.cfi_adjust_cfa_offset	SWITCH_STACK_SIZE
746	stq	$9, 0($sp)
747	stq	$10, 8($sp)
748	stq	$11, 16($sp)
749	stq	$12, 24($sp)
750	stq	$13, 32($sp)
751	stq	$14, 40($sp)
752	stq	$15, 48($sp)
753	stq	$26, 56($sp)
754	ret	$31, ($1), 1
755	.cfi_endproc
756	.size	do_switch_stack, .-do_switch_stack
757
758	.align	4
759	.type	undo_switch_stack, @function
760	.cfi_startproc simple
761	.cfi_def_cfa $sp, 0
762	.cfi_register 64, $1
763undo_switch_stack:
764	ldq	$9, 0($sp)
765	ldq	$10, 8($sp)
766	ldq	$11, 16($sp)
767	ldq	$12, 24($sp)
768	ldq	$13, 32($sp)
769	ldq	$14, 40($sp)
770	ldq	$15, 48($sp)
771	ldq	$26, 56($sp)
772	lda	$sp, SWITCH_STACK_SIZE($sp)
773	ret	$31, ($1), 1
774	.cfi_endproc
775	.size	undo_switch_stack, .-undo_switch_stack
776
777#define FR(n) n * 8 + TI_FP($8)
778	.align	4
779	.globl	__save_fpu
780	.type	__save_fpu, @function
781__save_fpu:
782#define V(n) stt	$f##n, FR(n)
783	V( 0); V( 1); V( 2); V( 3)
784	V( 4); V( 5); V( 6); V( 7)
785	V( 8); V( 9); V(10); V(11)
786	V(12); V(13); V(14); V(15)
787	V(16); V(17); V(18); V(19)
788	V(20); V(21); V(22); V(23)
789	V(24); V(25); V(26); V(27)
790	mf_fpcr	$f0		# get fpcr
791	V(28); V(29); V(30)
792	stt	$f0, FR(31)	# save fpcr in slot of $f31
793	ldt	$f0, FR(0)	# don't let "__save_fpu" change fp state.
794	ret
795#undef V
796	.size	__save_fpu, .-__save_fpu
797
798	.align	4
799restore_fpu:
800	and	$3, TS_RESTORE_FP, $3
801	bic	$2, TS_SAVED_FP | TS_RESTORE_FP, $2
802	beq	$3, 1f
803#define V(n) ldt	$f##n, FR(n)
804	ldt	$f30, FR(31)	# get saved fpcr
805	V( 0); V( 1); V( 2); V( 3)
806	mt_fpcr	$f30		# install saved fpcr
807	V( 4); V( 5); V( 6); V( 7)
808	V( 8); V( 9); V(10); V(11)
809	V(12); V(13); V(14); V(15)
810	V(16); V(17); V(18); V(19)
811	V(20); V(21); V(22); V(23)
812	V(24); V(25); V(26); V(27)
813	V(28); V(29); V(30)
8141:	stl $2, TI_STATUS($8)
815	br restore_other
816#undef V
817
818
819/*
820 * The meat of the context switch code.
821 */
822	.align	4
823	.globl	alpha_switch_to
824	.type	alpha_switch_to, @function
825	.cfi_startproc
826alpha_switch_to:
827	DO_SWITCH_STACK
828	ldl	$1, TI_STATUS($8)
829	and	$1, TS_RESTORE_FP, $3
830	bne	$3, 1f
831	or	$1, TS_RESTORE_FP | TS_SAVED_FP, $2
832	and	$1, TS_SAVED_FP, $3
833	stl	$2, TI_STATUS($8)
834	bne	$3, 1f
835	bsr	$26, __save_fpu
8361:
837	call_pal PAL_swpctx
838	lda	$8, 0x3fff
839	UNDO_SWITCH_STACK
840	bic	$sp, $8, $8
841	mov	$17, $0
842	ret
843	.cfi_endproc
844	.size	alpha_switch_to, .-alpha_switch_to
845
846/*
847 * New processes begin life here.
848 */
849
850	.globl	ret_from_fork
851	.align	4
852	.ent	ret_from_fork
853ret_from_fork:
854	lda	$26, ret_to_user
855	mov	$17, $16
856	jmp	$31, schedule_tail
857.end ret_from_fork
858
859/*
860 * ... and new kernel threads - here
861 */
862	.align 4
863	.globl	ret_from_kernel_thread
864	.ent	ret_from_kernel_thread
865ret_from_kernel_thread:
866	mov	$17, $16
867	jsr	$26, schedule_tail
868	mov	$9, $27
869	mov	$10, $16
870	jsr	$26, ($9)
871	br	$31, ret_to_user
872.end ret_from_kernel_thread
873
874
875/*
876 * Special system calls.  Most of these are special in that they either
877 * have to play switch_stack games.
878 */
879
880.macro	fork_like name
881	.align	4
882	.globl	alpha_\name
883	.ent	alpha_\name
884alpha_\name:
885	.prologue 0
886	bsr	$1, do_switch_stack
887	// NB: if anyone adds preemption, this block will need to be protected
888	ldl	$1, TI_STATUS($8)
889	and	$1, TS_SAVED_FP, $3
890	or	$1, TS_SAVED_FP, $2
891	bne	$3, 1f
892	stl	$2, TI_STATUS($8)
893	bsr	$26, __save_fpu
8941:
895	jsr	$26, sys_\name
896	ldq	$26, 56($sp)
897	lda	$sp, SWITCH_STACK_SIZE($sp)
898	ret
899.end	alpha_\name
900.endm
901
902fork_like fork
903fork_like vfork
904fork_like clone
905fork_like clone3
906
907.macro	sigreturn_like name
908	.align	4
909	.globl	sys_\name
910	.ent	sys_\name
911sys_\name:
912	.prologue 0
913	lda	$9, ret_from_straced
914	cmpult	$26, $9, $9
915	lda	$sp, -SWITCH_STACK_SIZE($sp)
916	jsr	$26, do_\name
917	bne	$9, 1f
918	jsr	$26, syscall_trace_leave
9191:	br	$1, undo_switch_stack
920	br	ret_from_sys_call
921.end sys_\name
922.endm
923
924sigreturn_like sigreturn
925sigreturn_like rt_sigreturn
926
927	.align	4
928	.globl	alpha_syscall_zero
929	.ent	alpha_syscall_zero
930alpha_syscall_zero:
931	.prologue 0
932	/* Special because it needs to do something opposite to
933	   force_successful_syscall_return().  We use the saved
934	   syscall number for that, zero meaning "not an error".
935	   That works nicely, but for real syscall 0 we need to
936	   make sure that this logics doesn't get confused.
937	   Store a non-zero there - -ENOSYS we need in register
938	   for our return value will do just fine.
939	  */
940	lda	$0, -ENOSYS
941	unop
942	stq	$0, 0($sp)
943	ret
944.end alpha_syscall_zero
945