xref: /netbsd-src/sys/arch/alpha/alpha/locore.s (revision b117086304d1e5c851ebbc0bb3ae2ced17f843a5)
1/* $NetBSD: locore.s,v 1.143 2022/08/07 10:12:19 andvar Exp $ */
2
3/*-
4 * Copyright (c) 1999, 2000, 2019 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
9 * NASA Ames Research Center.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 *    notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 *    notice, this list of conditions and the following disclaimer in the
18 *    documentation and/or other materials provided with the distribution.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 */
32
33/*
34 * Copyright (c) 1994, 1995, 1996 Carnegie-Mellon University.
35 * All rights reserved.
36 *
37 * Author: Chris G. Demetriou
38 *
39 * Permission to use, copy, modify and distribute this software and
40 * its documentation is hereby granted, provided that both the copyright
41 * notice and this permission notice appear in all copies of the
42 * software, derivative works or modified versions, and any portions
43 * thereof, and that both notices appear in supporting documentation.
44 *
45 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
46 * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
47 * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
48 *
49 * Carnegie Mellon requests users of this software to return to
50 *
51 *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
52 *  School of Computer Science
53 *  Carnegie Mellon University
54 *  Pittsburgh PA 15213-3890
55 *
56 * any improvements or extensions that they make and grant Carnegie the
57 * rights to redistribute these changes.
58 */
59
60.stabs	__FILE__,100,0,0,kernel_text
61
62#include "opt_ddb.h"
63#include "opt_kgdb.h"
64#include "opt_multiprocessor.h"
65#include "opt_lockdebug.h"
66#include "opt_compat_netbsd.h"
67
68#include <machine/asm.h>
69
70__KERNEL_RCSID(0, "$NetBSD: locore.s,v 1.143 2022/08/07 10:12:19 andvar Exp $");
71
72#include "assym.h"
73
74.stabs	__FILE__,132,0,0,kernel_text
75
76	/* don't reorder instructions; paranoia. */
77	.set noreorder
78	.text
79
80	.macro	bfalse	reg, dst
81	beq	\reg, \dst
82	.endm
83
84	.macro	btrue	reg, dst
85	bne	\reg, \dst
86	.endm
87
88/*
89 * This is for kvm_mkdb, and should be the address of the beginning
90 * of the kernel text segment (not necessarily the same as kernbase).
91 */
92	EXPORT(kernel_text)
93.loc	1 __LINE__
94kernel_text:
95
96/*
97 * bootstack: a temporary stack, for booting.
98 *
99 * Extends from 'start' down.
100 */
101bootstack:
102
103/*
104 * locorestart: Kernel start. This is no longer the actual entry
105 * point, although jumping to here (the first kernel address) will
106 * in fact work just fine.
107 *
108 * Arguments:
109 *	a0 is the first free page frame number (PFN)
110 *	a1 is the page table base register (PTBR)
111 *	a2 is the bootinfo magic number
112 *	a3 is the pointer to the bootinfo structure
113 *
114 * All arguments are passed to alpha_init().
115 */
116IMPORT(prom_mapped, 4)
117NESTED_NOPROFILE(locorestart,1,0,ra,0,0)
118	br	pv,1f
1191:	LDGP(pv)
120
121	/* Switch to the boot stack. */
122	lda	sp,bootstack
123
124	/* Load KGP with current GP. */
125	mov	a0, s0			/* save pfn */
126	mov	gp, a0
127	call_pal PAL_OSF1_wrkgp		/* clobbers a0, t0, t8-t11 */
128	mov	s0, a0			/* restore pfn */
129
130	/*
131	 * Call alpha_init() to do pre-main initialization.
132	 * alpha_init() gets the arguments we were called with,
133	 * which are already in a0, a1, a2, a3, and a4.
134	 */
135	CALL(alpha_init)
136
137	/* Set up the virtual page table pointer. */
138	ldiq	a0, VPTBASE
139	call_pal PAL_OSF1_wrvptptr	/* clobbers a0, t0, t8-t11 */
140
141	/*
142	 * Switch to lwp0's PCB.
143	 */
144	lda	a0, lwp0
145	ldq	a0, L_MD_PCBPADDR(a0)		/* phys addr of PCB */
146	call_pal PAL_OSF1_swpctx	/* clobbers a0, t0, t8-t11, a0 */
147
148	/* PROM is no longer mapped. */
149	lda	t0, prom_mapped
150	stl	zero, 0(t0)
151
152	/*
153	 * We've switched to a new page table base, so invalidate the TLB
154	 * and I-stream.  This happens automatically everywhere but here.
155	 */
156	ldiq	a0, -2				/* TBIA */
157	call_pal PAL_OSF1_tbi
158	call_pal PAL_imb
159
160	/*
161	 * All ready to go!  Call main()!
162	 *
163	 * We're going to play a little trick there, though.  We are
164	 * going to fake our return address as the kthread backstop.
165	 * Hitting the backstop will trigger a panic, and we want lwp0
166	 * to work like other kthreads in that regard.  We will still
167	 * keep the "main returned" backstop here in case something
168	 * goes horribly wrong.
169	 */
170	lda	ra, alpha_kthread_backstop
171	jsr	s0, main
172	ldgp	gp, 0(s0)
173
174	/* This should never happen. */
175	PANIC("main() returned",Lmain_returned_pmsg)
176	END(locorestart)
177
178/**************************************************************************/
179
180/*
181 * Pull in the PROM interface routines; these are needed for
182 * prom printf (while bootstrapping), and for determining the
183 * boot device, etc.
184 */
185#include <alpha/alpha/prom_disp.s>
186
187/**************************************************************************/
188
189/*
190 * Pull in the PALcode function stubs.
191 */
192#include <alpha/alpha/pal.s>
193
194/**************************************************************************/
195
196/**************************************************************************/
197
198#if defined(MULTIPROCESSOR)
199/*
200 * Pull in the multiprocssor glue.
201 */
202#include <alpha/alpha/multiproc.s>
203#endif /* MULTIPROCESSOR */
204
205/**************************************************************************/
206
207/**************************************************************************/
208
209#if defined(DDB) || defined(KGDB)
210/*
211 * Pull in debugger glue.
212 */
213#include <alpha/alpha/debug.s>
214#endif /* DDB || KGDB */
215
216/**************************************************************************/
217
218/**************************************************************************/
219
220/*
221 * Pull in optimized pmap subroutines.
222 */
223#include <alpha/alpha/pmap_subr.s>
224
225/**************************************************************************/
226
227/**************************************************************************/
228
229	.text
230.stabs	__FILE__,132,0,0,backtolocore1	/* done with includes */
231.loc	1 __LINE__
232backtolocore1:
233/**************************************************************************/
234
235#ifdef COMPAT_16
236/*
237 * Signal "trampoline" code.
238 *
239 * The kernel arranges for the handler to be invoked directly.  This
240 * trampoline is used only to return from the signal.
241 *
242 * The stack pointer points to the saved sigcontext.
243 */
244
245NESTED_NOPROFILE(sigcode,0,0,ra,0,0)
246	mov	sp, a0			/* get pointer to sigcontext */
247	CALLSYS_NOERROR(compat_16___sigreturn14)	/* and call sigreturn() with it. */
248	mov	v0, a0			/* if that failed, get error code */
249	CALLSYS_NOERROR(exit)		/* and call exit() with it. */
250XNESTED(esigcode,0)
251	END(sigcode)
252#endif /* COMPAT_16 */
253
254/**************************************************************************/
255
256/*
257 * exception_return: return from trap, exception, or syscall
258 */
259
260LEAF(exception_return, 1)			/* XXX should be NESTED */
261	br	pv, 1f
2621:	LDGP(pv)
263
264	ldq	s1, (FRAME_PS * 8)(sp)		/* s1 = new PSL */
265	and	s1, ALPHA_PSL_IPL_MASK, s3	/* s3 = new ipl */
266
267	/* --- BEGIN inline spllower() --- */
268
269	cmpult	s3, ALPHA_PSL_IPL_SOFT_HI, t1	/* new IPL < SOFT_HI? */
270	beq	t1, 5f				/* no, can't do AST or SI */
271	/* yes */
272
273	/* GET_CURLWP clobbers v0, t0, t8...t11. */
274	GET_CURLWP
275	mov	v0, s0				/* s0 = curlwp */
276
2772:	/*
278	 * Check to see if a soft interrupt is pending.  We need to only
279	 * check for soft ints eligible to run at the new IPL.  We generate
280	 * the mask of eligible soft ints to run by masking the ssir with:
281	 *
282	 *	(ALPHA_ALL_SOFTINTS << ((ipl) << 1))
283	 *
284	 * See alpha_softint_dispatch().
285	 */
286	ldq	t1, L_CPU(s0)			/* t1 = curlwp->l_cpu */
287	ldiq	t2, ALPHA_ALL_SOFTINTS		/* t2 = ALPHA_ALL_SOFTINTS */
288	ldq	t1, CPU_INFO_SSIR(t1)		/* t1 = t1->ci_ssir */
289	sll	s3, 1, t3			/* t3 = ipl << 1 */
290	sll	t2, t3, t2			/* t2 <<= t3 */
291	and	t1, t2, t1			/* t1 &= t2 */
292	bne	t1, 6f				/* yes */
293	/* no */
294
295	/* --- END inline spllower() --- */
296
297	and	s1, ALPHA_PSL_USERMODE, t0	/* are we returning to user? */
298	beq	t0, 5f				/* no: just return */
299	/* yes */
300
301	/* check for AST */
3023:	ldl	t3, L_MD_ASTPENDING(s0)		/* AST pending? */
303	bne	t3, 7f				/* yes */
304	/* no: headed back to user space */
305
306	/* Enable the FPU based on whether MDLWP_FPACTIVE is set. */
3074:	ldq	t2, L_MD_FLAGS(s0)
308	cmplt	t2, zero, a0
309	call_pal PAL_OSF1_wrfen
310
311	/* restore the registers, and return */
3125:	bsr	ra, exception_restore_regs	/* jmp/CALL trashes pv/t12 */
313	ldq	ra,(FRAME_RA*8)(sp)
314	.set noat
315	ldq	at_reg,(FRAME_AT*8)(sp)
316
317	lda	sp,(FRAME_SW_SIZE*8)(sp)
318	call_pal PAL_OSF1_rti
319	.set at
320	/* NOTREACHED */
321
322	/* We've got a softint */
3236:	ldiq	a0, ALPHA_PSL_IPL_HIGH
324	call_pal PAL_OSF1_swpipl
325	mov	v0, s2				/* remember old IPL */
326	mov	s3, a0				/* pass new ipl */
327	CALL(alpha_softint_dispatch)
328
329	/* SI handled; restore IPL and check again */
330	mov	s2, a0
331	call_pal PAL_OSF1_swpipl
332	br	2b
333
334	/* We've got an AST */
3357:	stl	zero, L_MD_ASTPENDING(s0)	/* no AST pending */
336
337	ldiq	a0, ALPHA_PSL_IPL_0		/* drop IPL to zero */
338	call_pal PAL_OSF1_swpipl
339	mov	v0, s2				/* remember old IPL */
340
341	mov	sp, a0				/* only arg is frame */
342	CALL(ast)
343
344	/* AST handled; restore IPL and check again */
345	mov	s2, a0
346	call_pal PAL_OSF1_swpipl
347	br	3b
348
349	END(exception_return)
350
351LEAF(exception_save_regs, 0)
352	stq	v0,(FRAME_V0*8)(sp)
353	stq	a3,(FRAME_A3*8)(sp)
354	stq	a4,(FRAME_A4*8)(sp)
355	stq	a5,(FRAME_A5*8)(sp)
356	stq	s0,(FRAME_S0*8)(sp)
357	stq	s1,(FRAME_S1*8)(sp)
358	stq	s2,(FRAME_S2*8)(sp)
359	stq	s3,(FRAME_S3*8)(sp)
360	stq	s4,(FRAME_S4*8)(sp)
361	stq	s5,(FRAME_S5*8)(sp)
362	stq	s6,(FRAME_S6*8)(sp)
363	stq	t0,(FRAME_T0*8)(sp)
364	stq	t1,(FRAME_T1*8)(sp)
365	stq	t2,(FRAME_T2*8)(sp)
366	stq	t3,(FRAME_T3*8)(sp)
367	stq	t4,(FRAME_T4*8)(sp)
368	stq	t5,(FRAME_T5*8)(sp)
369	stq	t6,(FRAME_T6*8)(sp)
370	stq	t7,(FRAME_T7*8)(sp)
371	stq	t8,(FRAME_T8*8)(sp)
372	stq	t9,(FRAME_T9*8)(sp)
373	stq	t10,(FRAME_T10*8)(sp)
374	stq	t11,(FRAME_T11*8)(sp)
375	stq	t12,(FRAME_T12*8)(sp)
376	RET
377	END(exception_save_regs)
378
379LEAF(exception_restore_regs, 0)
380	ldq	v0,(FRAME_V0*8)(sp)
381	ldq	a3,(FRAME_A3*8)(sp)
382	ldq	a4,(FRAME_A4*8)(sp)
383	ldq	a5,(FRAME_A5*8)(sp)
384	ldq	s0,(FRAME_S0*8)(sp)
385	ldq	s1,(FRAME_S1*8)(sp)
386	ldq	s2,(FRAME_S2*8)(sp)
387	ldq	s3,(FRAME_S3*8)(sp)
388	ldq	s4,(FRAME_S4*8)(sp)
389	ldq	s5,(FRAME_S5*8)(sp)
390	ldq	s6,(FRAME_S6*8)(sp)
391	ldq	t0,(FRAME_T0*8)(sp)
392	ldq	t1,(FRAME_T1*8)(sp)
393	ldq	t2,(FRAME_T2*8)(sp)
394	ldq	t3,(FRAME_T3*8)(sp)
395	ldq	t4,(FRAME_T4*8)(sp)
396	ldq	t5,(FRAME_T5*8)(sp)
397	ldq	t6,(FRAME_T6*8)(sp)
398	ldq	t7,(FRAME_T7*8)(sp)
399	ldq	t8,(FRAME_T8*8)(sp)
400	ldq	t9,(FRAME_T9*8)(sp)
401	ldq	t10,(FRAME_T10*8)(sp)
402	ldq	t11,(FRAME_T11*8)(sp)
403	ldq	t12,(FRAME_T12*8)(sp)
404	RET
405	END(exception_restore_regs)
406
407/**************************************************************************/
408
409/*
410 * XentArith:
411 * System arithmetic trap entry point.
412 */
413
414	PALVECT(XentArith)		/* setup frame, save registers */
415
416	/* a0, a1, & a2 already set up */
417	ldiq	a3, ALPHA_KENTRY_ARITH
418	mov	sp, a4			; .loc 1 __LINE__
419	CALL(trap)
420
421	jmp	zero, exception_return
422	END(XentArith)
423
424/**************************************************************************/
425
426/*
427 * XentIF:
428 * System instruction fault trap entry point.
429 */
430
431	PALVECT(XentIF)			/* setup frame, save registers */
432
433	/* a0, a1, & a2 already set up */
434	ldiq	a3, ALPHA_KENTRY_IF
435	mov	sp, a4			; .loc 1 __LINE__
436	CALL(trap)
437	jmp	zero, exception_return
438	END(XentIF)
439
440/**************************************************************************/
441
442/*
443 * XentInt:
444 * System interrupt entry point.
445 */
446
447	PALVECT(XentInt)		/* setup frame, save registers */
448
449	/* a0, a1, & a2 already set up */
450	mov	sp, a3			; .loc 1 __LINE__
451	CALL(interrupt)
452	jmp	zero, exception_return
453	END(XentInt)
454
455/**************************************************************************/
456
457/*
458 * XentMM:
459 * System memory management fault entry point.
460 */
461
462	PALVECT(XentMM)			/* setup frame, save registers */
463
464	/* a0, a1, & a2 already set up */
465	ldiq	a3, ALPHA_KENTRY_MM
466	mov	sp, a4			; .loc 1 __LINE__
467	CALL(trap)
468
469	jmp	zero, exception_return
470	END(XentMM)
471
472/**************************************************************************/
473
474/*
475 * XentSys:
476 * System call entry point.
477 */
478
479	ESETUP(XentSys)			; .loc 1 __LINE__
480
481	stq	v0,(FRAME_V0*8)(sp)		/* in case we need to restart */
482	stq	s0,(FRAME_S0*8)(sp)
483	stq	s1,(FRAME_S1*8)(sp)
484	stq	s2,(FRAME_S2*8)(sp)
485	stq	s3,(FRAME_S3*8)(sp)
486	stq	s4,(FRAME_S4*8)(sp)
487	stq	s5,(FRAME_S5*8)(sp)
488	stq	s6,(FRAME_S6*8)(sp)
489	stq	a0,(FRAME_A0*8)(sp)
490	stq	a1,(FRAME_A1*8)(sp)
491	stq	a2,(FRAME_A2*8)(sp)
492	stq	a3,(FRAME_A3*8)(sp)
493	stq	a4,(FRAME_A4*8)(sp)
494	stq	a5,(FRAME_A5*8)(sp)
495	stq	ra,(FRAME_RA*8)(sp)
496
497	/* syscall number, passed in v0, is first arg, frame pointer second */
498	mov	v0,a1
499	GET_CURLWP
500	mov	v0,a0
501	mov	sp,a2			; .loc 1 __LINE__
502	ldq	t11,L_PROC(a0)
503	ldq	t12,P_MD_SYSCALL(t11)
504	CALL((t12))
505
506	jmp	zero, exception_return
507	END(XentSys)
508
509/**************************************************************************/
510
511/*
512 * XentUna:
513 * System unaligned access entry point.
514 */
515
516LEAF(XentUna, 3)				/* XXX should be NESTED */
517	.set noat
518	lda	sp,-(FRAME_SW_SIZE*8)(sp)
519	stq	at_reg,(FRAME_AT*8)(sp)
520	.set at
521	stq	ra,(FRAME_RA*8)(sp)
522	bsr	ra, exception_save_regs		/* jmp/CALL trashes pv/t12 */
523
524	/* a0, a1, & a2 already set up */
525	ldiq	a3, ALPHA_KENTRY_UNA
526	mov	sp, a4			; .loc 1 __LINE__
527	CALL(trap)
528
529	jmp	zero, exception_return
530	END(XentUna)
531
532/**************************************************************************/
533
534/*
535 * savefpstate: Save a process's floating point state.
536 *
537 * Arguments:
538 *	a0	'struct fpstate *' to save into
539 */
540
541LEAF(savefpstate, 1)
542	LDGP(pv)
543	/* save all of the FP registers */
544	lda	t1, FPREG_FPR_REGS(a0)	/* get address of FP reg. save area */
545	stt	$f0,   (0 * 8)(t1)	/* save first register, using hw name */
546	stt	$f1,   (1 * 8)(t1)	/* etc. */
547	stt	$f2,   (2 * 8)(t1)
548	stt	$f3,   (3 * 8)(t1)
549	stt	$f4,   (4 * 8)(t1)
550	stt	$f5,   (5 * 8)(t1)
551	stt	$f6,   (6 * 8)(t1)
552	stt	$f7,   (7 * 8)(t1)
553	stt	$f8,   (8 * 8)(t1)
554	stt	$f9,   (9 * 8)(t1)
555	stt	$f10, (10 * 8)(t1)
556	stt	$f11, (11 * 8)(t1)
557	stt	$f12, (12 * 8)(t1)
558	stt	$f13, (13 * 8)(t1)
559	stt	$f14, (14 * 8)(t1)
560	stt	$f15, (15 * 8)(t1)
561	stt	$f16, (16 * 8)(t1)
562	stt	$f17, (17 * 8)(t1)
563	stt	$f18, (18 * 8)(t1)
564	stt	$f19, (19 * 8)(t1)
565	stt	$f20, (20 * 8)(t1)
566	stt	$f21, (21 * 8)(t1)
567	stt	$f22, (22 * 8)(t1)
568	stt	$f23, (23 * 8)(t1)
569	stt	$f24, (24 * 8)(t1)
570	stt	$f25, (25 * 8)(t1)
571	stt	$f26, (26 * 8)(t1)
572	stt	$f27, (27 * 8)(t1)
573	.set noat
574	stt	$f28, (28 * 8)(t1)
575	.set at
576	stt	$f29, (29 * 8)(t1)
577	stt	$f30, (30 * 8)(t1)
578
579	/*
580	 * Then save the FPCR; note that the necessary 'trapb's are taken
581	 * care of on kernel entry and exit.
582	 */
583	mf_fpcr	ft0
584	stt	ft0, FPREG_FPR_CR(a0)	/* store to FPCR save area */
585
586	RET
587	END(savefpstate)
588
589/**************************************************************************/
590
591/*
592 * restorefpstate: Restore a process's floating point state.
593 *
594 * Arguments:
595 *	a0	'struct fpstate *' to restore from
596 */
597
598LEAF(restorefpstate, 1)
599	LDGP(pv)
600	/*
601	 * Restore the FPCR; note that the necessary 'trapb's are taken care of
602	 * on kernel entry and exit.
603	 */
604	ldt	ft0, FPREG_FPR_CR(a0)	/* load from FPCR save area */
605	mt_fpcr	ft0
606
607	/* Restore all of the FP registers. */
608	lda	t1, FPREG_FPR_REGS(a0)	/* get address of FP reg. save area */
609	ldt	$f0,   (0 * 8)(t1)	/* restore first reg., using hw name */
610	ldt	$f1,   (1 * 8)(t1)	/* etc. */
611	ldt	$f2,   (2 * 8)(t1)
612	ldt	$f3,   (3 * 8)(t1)
613	ldt	$f4,   (4 * 8)(t1)
614	ldt	$f5,   (5 * 8)(t1)
615	ldt	$f6,   (6 * 8)(t1)
616	ldt	$f7,   (7 * 8)(t1)
617	ldt	$f8,   (8 * 8)(t1)
618	ldt	$f9,   (9 * 8)(t1)
619	ldt	$f10, (10 * 8)(t1)
620	ldt	$f11, (11 * 8)(t1)
621	ldt	$f12, (12 * 8)(t1)
622	ldt	$f13, (13 * 8)(t1)
623	ldt	$f14, (14 * 8)(t1)
624	ldt	$f15, (15 * 8)(t1)
625	ldt	$f16, (16 * 8)(t1)
626	ldt	$f17, (17 * 8)(t1)
627	ldt	$f18, (18 * 8)(t1)
628	ldt	$f19, (19 * 8)(t1)
629	ldt	$f20, (20 * 8)(t1)
630	ldt	$f21, (21 * 8)(t1)
631	ldt	$f22, (22 * 8)(t1)
632	ldt	$f23, (23 * 8)(t1)
633	ldt	$f24, (24 * 8)(t1)
634	ldt	$f25, (25 * 8)(t1)
635	ldt	$f26, (26 * 8)(t1)
636	ldt	$f27, (27 * 8)(t1)
637	ldt	$f28, (28 * 8)(t1)
638	ldt	$f29, (29 * 8)(t1)
639	ldt	$f30, (30 * 8)(t1)
640
641	RET
642	END(restorefpstate)
643
644/**************************************************************************/
645
646/*
647 * savectx: save process context, i.e. callee-saved registers
648 *
649 * Note that savectx() only works for processes other than curlwp,
650 * since cpu_switchto will copy over the info saved here.  (It _can_
651 * sanely be used for curlwp iff cpu_switchto won't be called again, e.g.
652 * if called from boot().)
653 *
654 * N.B. this is actually only used by dumpsys().
655 *
656 * Arguments:
657 *	a0	'struct pcb *' of the process that needs its context saved
658 */
659
660LEAF(savectx, 1)
661	br	pv, 1f
6621:	LDGP(pv)
663	stq	sp, PCB_HWPCB_KSP(a0)		/* store sp */
664	stq	s0, PCB_CONTEXT+(0 * 8)(a0)	/* store s0 - s6 */
665	stq	s1, PCB_CONTEXT+(1 * 8)(a0)
666	stq	s2, PCB_CONTEXT+(2 * 8)(a0)
667	stq	s3, PCB_CONTEXT+(3 * 8)(a0)
668	stq	s4, PCB_CONTEXT+(4 * 8)(a0)
669	stq	s5, PCB_CONTEXT+(5 * 8)(a0)
670	stq	s6, PCB_CONTEXT+(6 * 8)(a0)
671	stq	ra, PCB_CONTEXT+(7 * 8)(a0)	/* store ra */
672	RET
673	END(savectx)
674
675/**************************************************************************/
676
677/*
678 * void alpha_softint_switchto(struct lwp *current, int ipl, struct lwp *next)
679 * Switch away from the current LWP to the specified softint LWP, and
680 * dispatch to softint processing.
681 * Aguments:
682 *	a0	'struct lwp *' of the LWP to switch from
683 *	a1	IPL that the softint will run at
684 *	a2	'struct lwp *' of the LWP to switch to
685 *
686 * N.B. We have arranged that a0 and a1 are already set up correctly
687 * for the call to softint_dispatch().
688 */
689NESTED_NOPROFILE(alpha_softint_switchto, 3, 16, ra, IM_RA, 0)
690	LDGP(pv)
691
692	ldq	a3, L_PCB(a0)			/* a3 = from->l_pcb */
693
694	lda	sp, -16(sp)			/* set up stack frame */
695	stq	ra, 0(sp)			/* save ra */
696
697	/*
698	 * Step 1: Save the current LWP's context.  We don't
699	 * save the return address directly; instead, we arrange
700	 * for it to bounce through a trampoline that fixes up
701	 * the state in case the softint LWP blocks.
702	 */
703	stq	sp, PCB_HWPCB_KSP(a3)		/* store sp */
704	stq	s0, PCB_CONTEXT+(0 * 8)(a3)	/* store s0 - s6 */
705	stq	s1, PCB_CONTEXT+(1 * 8)(a3)
706	stq	s2, PCB_CONTEXT+(2 * 8)(a3)
707	stq	s3, PCB_CONTEXT+(3 * 8)(a3)
708	stq	s4, PCB_CONTEXT+(4 * 8)(a3)
709	stq	s5, PCB_CONTEXT+(5 * 8)(a3)
710	stq	s6, PCB_CONTEXT+(6 * 8)(a3)
711
712	/* Set the trampoline address in saved context. */
713	lda	v0, alpha_softint_return
714	stq	v0, PCB_CONTEXT+(7 * 8)(a3)	/* store ra */
715
716	/*
717	 * Step 2: Switch to the softint LWP's stack.
718	 * We always start at the top of the stack (i.e.
719	 * just below the trapframe).
720	 *
721	 * N.B. There is no need to restore any other registers
722	 * from the softint LWP's context; we are starting from
723	 * the root of the call graph.
724	 */
725	ldq	sp, L_MD_TF(a2)
726
727	/*
728	 * Step 3: Update curlwp.
729	 *
730	 * N.B. We save off the from-LWP argument that will be passed
731	 * to softint_dispatch() in s0, which we'll need to restore
732	 * before returning.  If we bounce through the trampoline, the
733	 * context switch will restore it for us.
734	 */
735	mov	a0, s0			/* s0 = from LWP */
736	SET_CURLWP(a2)			/* clobbers a0, v0, t0, t8..t11 */
737
738	/*
739	 * Step 4: Call softint_dispatch().
740	 *
741	 * N.B. a1 already has the IPL argument.
742	 */
743	mov	s0, a0			/* a0 = from LWP */
744	CALL(softint_dispatch)
745
746	/*
747	 * Step 5: Restore everything and return.
748	 */
749	ldq	a3, L_PCB(s0)			/* a3 = from->l_pcb */
750	SET_CURLWP(s0)			/* clobbers a0, v0, t0, t8..t11 */
751	ldq	sp, PCB_HWPCB_KSP(a3)		/* restore sp */
752	ldq	s0, PCB_CONTEXT+(0 * 8)(a3)	/* restore s0 */
753	ldq	ra, 0(sp)			/* restore ra */
754	lda	sp, 16(sp)			/* pop stack frame */
755	RET
756	END(alpha_softint_switchto)
757
758LEAF_NOPROFILE(alpha_softint_return, 0)
759	/*
760	 * Step 1: Go to IPL_HIGH, which is what the alpha_softint_dispatch()
761	 * expects.  We will have arrived here at IPL_SCHED.
762	 */
763	ldiq	a0, ALPHA_PSL_IPL_HIGH
764	call_pal PAL_OSF1_swpipl
765
766	/*
767	 * Step 2: Re-adjust the mutex count after mi_switch().
768	 */
769	GET_CURLWP
770	ldq	v0, L_CPU(v0)
771	ldl	t0, CPU_INFO_MTX_COUNT(v0)
772	addl	t0, 1, t0
773	stl	t0, CPU_INFO_MTX_COUNT(v0)
774
775	/*
776	 * Step 3: Pop alpha_softint_switchto()'s stack frame
777	 * and return.
778	 */
779	ldq	ra, 0(sp)			/* restore ra */
780	lda	sp, 16(sp)			/* pop stack frame */
781	RET
782	END(alpha_softint_return)
783
784/*
785 * struct lwp *cpu_switchto(struct lwp *current, struct lwp *next,
786 *                          bool returning)
787 * Switch to the specified next LWP
788 * Arguments:
789 *	a0	'struct lwp *' of the LWP to switch from
790 *	a1	'struct lwp *' of the LWP to switch to
791 *	a2	non-zero if we're returning to an interrupted LWP
792 *		from a soft interrupt
793 */
794LEAF(cpu_switchto, 0)
795	LDGP(pv)
796
797	/*
798	 * do an inline savectx(), to save old context
799	 */
800	ldq	a3, L_PCB(a0)
801	/* NOTE: ksp is stored by the swpctx */
802	stq	s0, PCB_CONTEXT+(0 * 8)(a3)	/* store s0 - s6 */
803	stq	s1, PCB_CONTEXT+(1 * 8)(a3)
804	stq	s2, PCB_CONTEXT+(2 * 8)(a3)
805	stq	s3, PCB_CONTEXT+(3 * 8)(a3)
806	stq	s4, PCB_CONTEXT+(4 * 8)(a3)
807	stq	s5, PCB_CONTEXT+(5 * 8)(a3)
808	stq	s6, PCB_CONTEXT+(6 * 8)(a3)
809	stq	ra, PCB_CONTEXT+(7 * 8)(a3)	/* store ra */
810
811	mov	a0, s4				/* save old curlwp */
812	mov	a1, s2				/* save new lwp */
813
814	/*
815	 * Check to see if we're doing a light-weight switch back to
816	 * an interrupted LWP (referred to as the "pinned" LWP) from
817	 * a softint LWP.  In this case we have been running on the
818	 * pinned LWP's context -- swpctx was not used to get here --
819	 * so we won't be using swpctx to go back, either.
820	 */
821	bne	a2, 3f			/* yes, go handle it */
822	/* no, normal context switch */
823
824	/* Switch to the new PCB. */
825	ldq	a0, L_MD_PCBPADDR(s2)
826	call_pal PAL_OSF1_swpctx	/* clobbers a0, t0, t8-t11, v0 */
827
8281:	SET_CURLWP(s2)			/* curlwp = l */
829
830	/*
831	 * Now running on the new PCB.
832	 */
833	ldq	s0, L_PCB(s2)
834
835	/*
836	 * Check for restartable atomic sequences (RAS).
837	 */
838	ldq	a0, L_PROC(s2)			/* first ras_lookup() arg */
839	ldq	t0, P_RASLIST(a0)		/* any RAS entries? */
840	bne	t0, 4f				/* yes, go deal with it */
8412:
842	mov	s4, v0				/* return the old lwp */
843	/*
844	 * Restore registers and return.
845	 * NOTE: ksp is restored by the swpctx.
846	 */
847	ldq	s1, PCB_CONTEXT+(1 * 8)(s0)		/* restore s1-s6 */
848	ldq	s2, PCB_CONTEXT+(2 * 8)(s0)
849	ldq	s3, PCB_CONTEXT+(3 * 8)(s0)
850	ldq	s4, PCB_CONTEXT+(4 * 8)(s0)
851	ldq	s5, PCB_CONTEXT+(5 * 8)(s0)
852	ldq	s6, PCB_CONTEXT+(6 * 8)(s0)
853	ldq	ra, PCB_CONTEXT+(7 * 8)(s0)		/* restore ra */
854	ldq	s0, PCB_CONTEXT+(0 * 8)(s0)		/* restore s0 */
855
856	RET
857
8583:	/*
859	 * Registers right now:
860	 *
861	 *	a0	old LWP
862	 *	a1	new LWP
863	 *	a3	old PCB
864	 *
865	 * What we need to do here is swap the stack, since we won't
866	 * be getting that from swpctx.
867	 */
868	ldq	a2, L_PCB(a1)			/* a2 = new PCB */
869	stq	sp, PCB_HWPCB_KSP(a3)		/* save old SP */
870	ldq	sp, PCB_HWPCB_KSP(a2)		/* restore new SP */
871	br	1b				/* finish up */
872
8734:
874	ldq	s1, L_MD_TF(s2)			/* s1 = l->l_md.md_tf */
875	ldq	a1, (FRAME_PC*8)(s1)		/* second ras_lookup() arg */
876	CALL(ras_lookup)			/* ras_lookup(p, PC) */
877	addq	v0, 1, t0			/* -1 means "not in ras" */
878	beq	t0, 2b				/* not in ras? return */
879	stq	v0, (FRAME_PC*8)(s1)		/* in ras? fix up PC */
880	br	2b				/* finish up */
881
882	END(cpu_switchto)
883
884/*
885 * lwp_trampoline()
886 *
887 * Arrange for a function to be invoked neatly, after a cpu_lwp_fork(),
888 * which has set up our pcb_context for us.  But we actually *get here*
889 * via cpu_switchto(), which returns the LWP we switched away from in v0.
890 *
891 * Invokes the function specified by the s0 register with the return
892 * address specified by the s1 register and with one argument specified
893 * by the s2 register.
894 */
895LEAF_NOPROFILE(lwp_trampoline, 0)
896	mov	v0, a0		/* a0 = prev_lwp (from cpu_switchto()) */
897	mov	s3, a1		/* a1 = new_lwp (that's us!) */
898	CALL(lwp_startup)	/* lwp_startup(prev_lwp, new_lwp); */
899	mov	s0, pv		/* pv = func */
900	mov	s1, ra		/* ra = (probably exception_return()) */
901	mov	s2, a0		/* a0 = arg */
902	jmp	zero, (pv)	/* func(arg) */
903	END(lwp_trampoline)
904
905/**************************************************************************/
906
907/*
908 * alpha_copystr(const void *from, void *to, size_t len, size_t *donep)
909 */
910	.arch	ev56
911LEAF(alpha_copystr_bwx, 4)
912	LDGP(pv)
913
914	mov	a2, t0			/* t0 = i = len */
915	beq	a2, 5f			/* if (len == 0), bail */
916
9171:	ldbu	t1, 0(a0)		/* t1 = *from */
918	subl	a2, 1, a2		/* len-- */
919	addq	a0, 1, a0		/* from++ */
920	stb	t1, 0(a1)		/* *to = t1 */
921	beq	t1, 2f			/* if (t1 == '\0'), bail out */
922	addq	a1, 1, a1		/* to++ */
923	bne	a2, 1b			/* if (len != 0), copy more */
924
9252:	beq	a3, 3f			/* if (lenp != NULL) */
926	subl	t0, a2, t0		/* *lenp = (i - len) */
927	stq	t0, 0(a3)
9283:	bne	t1, 4f			/* *from != '\0'; leave in a huff */
929
930	mov	zero, v0		/* return 0. */
931	RET
932
9334:	ldiq	v0, ENAMETOOLONG
934	RET
935
9365:	ldiq	t1, 1			/* fool the test above... */
937	br	zero, 2b
938
939	nop				/* pad to same length as... */
940	nop				/* non-BWX version. */
941	nop
942	nop
943	nop
944	EXPORT(alpha_copystr_bwx_end)
945	END(alpha_copystr_bwx)
946	.arch	ev4
947
948LEAF(alpha_copystr, 4)
949	LDGP(pv)
950
951	mov	a2, t0			/* t0 = i = len */
952	beq	a2, 5f			/* if (len == 0), bail */
953
9541:	ldq_u	t1, 0(a0)		/* t1 = *from */
955	extbl	t1, a0, t1
956	ldq_u	t3, 0(a1)		/* set up t2 with quad around *to */
957	insbl	t1, a1, t2
958	mskbl	t3, a1, t3
959	or	t3, t2, t3		/* add *from to quad around *to */
960	stq_u	t3, 0(a1)		/* write out that quad */
961
962	subl	a2, 1, a2		/* len-- */
963	beq	t1, 2f			/* if (*from == 0), bail out */
964	addq	a1, 1, a1		/* to++ */
965	addq	a0, 1, a0		/* from++ */
966	bne	a2, 1b			/* if (len != 0) copy more */
967
9682:	beq	a3, 3f			/* if (lenp != NULL) */
969	subl	t0, a2, t0		/* *lenp = (i - len) */
970	stq	t0, 0(a3)
9713:	bne	t1, 4f			/* *from != '\0'; leave in a huff */
972
973	mov	zero, v0		/* return 0. */
974	RET
975
9764:	ldiq	v0, ENAMETOOLONG
977	RET
978
9795:	ldiq	t1, 1			/* fool the test above... */
980	br	zero, 2b
981	EXPORT(alpha_copystr_end)
982	END(alpha_copystr)
983
984NESTED(copyinstr, 4, 16, ra, IM_RA|IM_S0, 0)
985	LDGP(pv)
986	lda	sp, -16(sp)			/* set up stack frame	     */
987	stq	ra, (16-8)(sp)			/* save ra		     */
988	stq	s0, (16-16)(sp)			/* save s0		     */
989	ldiq	t0, VM_MAX_ADDRESS		/* make sure that src addr   */
990	cmpult	a0, t0, t1			/* is in user space.	     */
991	beq	t1, copyerr_efault		/* if it's not, error out.   */
992	/* Note: GET_CURLWP clobbers v0, t0, t8...t11. */
993	GET_CURLWP
994	ldq	s0, L_PCB(v0)			/* s0 = pcb                  */
995	lda	v0, copyerr			/* set up fault handler.     */
996	stq	v0, PCB_ONFAULT(s0)
997	CALL(alpha_copystr)			/* do the copy.		     */
998	stq	zero, PCB_ONFAULT(s0)		/* kill the fault handler.   */
999	ldq	ra, (16-8)(sp)			/* restore ra.		     */
1000	ldq	s0, (16-16)(sp)			/* restore s0.		     */
1001	lda	sp, 16(sp)			/* kill stack frame.	     */
1002	RET					/* v0 left over from copystr */
1003	END(copyinstr)
1004
1005NESTED(copyoutstr, 4, 16, ra, IM_RA|IM_S0, 0)
1006	LDGP(pv)
1007	lda	sp, -16(sp)			/* set up stack frame	     */
1008	stq	ra, (16-8)(sp)			/* save ra		     */
1009	stq	s0, (16-16)(sp)			/* save s0		     */
1010	ldiq	t0, VM_MAX_ADDRESS		/* make sure that dest addr  */
1011	cmpult	a1, t0, t1			/* is in user space.	     */
1012	beq	t1, copyerr_efault		/* if it's not, error out.   */
1013	/* Note: GET_CURLWP clobbers v0, t0, t8...t11. */
1014	GET_CURLWP
1015	ldq	s0, L_PCB(v0)			/* s0 = pcb                  */
1016	lda	v0, copyerr			/* set up fault handler.     */
1017	stq	v0, PCB_ONFAULT(s0)
1018	CALL(alpha_copystr)			/* do the copy.		     */
1019	stq	zero, PCB_ONFAULT(s0)		/* kill the fault handler.   */
1020	ldq	ra, (16-8)(sp)			/* restore ra.		     */
1021	ldq	s0, (16-16)(sp)			/* restore s0.		     */
1022	lda	sp, 16(sp)			/* kill stack frame.	     */
1023	RET					/* v0 left over from copystr */
1024	END(copyoutstr)
1025
1026/*
1027 * kcopy(const void *src, void *dst, size_t len);
1028 *
1029 * Copy len bytes from src to dst, aborting if we encounter a fatal
1030 * page fault.
1031 *
1032 * kcopy() _must_ save and restore the old fault handler since it is
1033 * called by uiomove(), which may be in the path of servicing a non-fatal
1034 * page fault.
1035 *
1036 * N.B. This implementation is a wrapper around memcpy(), which is
1037 * implemented in src/common/lib/libc/arch/alpha/string/bcopy.S.
1038 * This is safe ONLY because we know that, as implemented, it is
1039 * a LEAF function (and thus does not use any callee-saved registers).
1040 */
1041NESTED(kcopy, 3, 32, ra, IM_RA|IM_S0|IM_S1, 0)
1042	LDGP(pv)
1043	lda	sp, -32(sp)			/* set up stack frame	     */
1044	stq	ra, (32-8)(sp)			/* save ra		     */
1045	stq	s0, (32-16)(sp)			/* save s0		     */
1046	stq	s1, (32-24)(sp)			/* save s1		     */
1047	/* Swap a0, a1, for call to memcpy(). */
1048	mov	a1, v0
1049	mov	a0, a1
1050	mov	v0, a0
1051	/* Note: GET_CURLWP clobbers v0, t0, t8...t11. */
1052	GET_CURLWP
1053	ldq	s1, L_PCB(v0)			/* s1 = pcb                  */
1054	lda	v0, kcopyerr			/* set up fault handler.     */
1055	ldq	s0, PCB_ONFAULT(s1)		/* save old handler.	     */
1056	stq	v0, PCB_ONFAULT(s1)
1057	CALL(memcpy)				/* do the copy.		     */
1058	stq	s0, PCB_ONFAULT(s1)		/* restore the old handler.  */
1059	ldq	ra, (32-8)(sp)			/* restore ra.		     */
1060	ldq	s0, (32-16)(sp)			/* restore s0.		     */
1061	ldq	s1, (32-24)(sp)			/* restore s1.		     */
1062	lda	sp, 32(sp)			/* kill stack frame.	     */
1063	mov	zero, v0			/* return 0. */
1064	RET
1065	END(kcopy)
1066
1067LEAF(kcopyerr, 0)
1068	LDGP(pv)
1069	stq	s0, PCB_ONFAULT(s1)		/* s1 == pcb (from above)    */
1070	ldq	ra, (32-8)(sp)			/* restore ra.		     */
1071	ldq	s0, (32-16)(sp)			/* restore s0.		     */
1072	ldq	s1, (32-24)(sp)			/* restore s1.		     */
1073	lda	sp, 32(sp)			/* kill stack frame.	     */
1074	RET
1075END(kcopyerr)
1076
1077NESTED(copyin, 3, 16, ra, IM_RA|IM_S0, 0)
1078	LDGP(pv)
1079	lda	sp, -16(sp)			/* set up stack frame	     */
1080	stq	ra, (16-8)(sp)			/* save ra		     */
1081	stq	s0, (16-16)(sp)			/* save s0		     */
1082	ldiq	t0, VM_MAX_ADDRESS		/* make sure that src addr   */
1083	cmpult	a0, t0, t1			/* is in user space.	     */
1084	beq	t1, copyerr_efault		/* if it's not, error out.   */
1085	/* Swap a0, a1, for call to memcpy(). */
1086	mov	a1, v0
1087	mov	a0, a1
1088	mov	v0, a0
1089	/* Note: GET_CURLWP clobbers v0, t0, t8...t11. */
1090	GET_CURLWP
1091	ldq	s0, L_PCB(v0)			/* s = pcb                   */
1092	lda	v0, copyerr			/* set up fault handler.     */
1093	stq	v0, PCB_ONFAULT(s0)
1094	CALL(memcpy)				/* do the copy.		     */
1095	stq	zero, PCB_ONFAULT(s0)		/* kill the fault handler.   */
1096	ldq	ra, (16-8)(sp)			/* restore ra.		     */
1097	ldq	s0, (16-16)(sp)			/* restore s0.		     */
1098	lda	sp, 16(sp)			/* kill stack frame.	     */
1099	mov	zero, v0			/* return 0. */
1100	RET
1101	END(copyin)
1102
1103NESTED(copyout, 3, 16, ra, IM_RA|IM_S0, 0)
1104	LDGP(pv)
1105	lda	sp, -16(sp)			/* set up stack frame	     */
1106	stq	ra, (16-8)(sp)			/* save ra		     */
1107	stq	s0, (16-16)(sp)			/* save s0		     */
1108	ldiq	t0, VM_MAX_ADDRESS		/* make sure that dest addr  */
1109	cmpult	a1, t0, t1			/* is in user space.	     */
1110	beq	t1, copyerr_efault		/* if it's not, error out.   */
1111	/* Swap a0, a1, for call to memcpy(). */
1112	mov	a1, v0
1113	mov	a0, a1
1114	mov	v0, a0
1115	/* Note: GET_CURLWP clobbers v0, t0, t8...t11. */
1116	GET_CURLWP
1117	ldq	s0, L_PCB(v0)			/* s0 = pcb                  */
1118	lda	v0, copyerr			/* set up fault handler.     */
1119	stq	v0, PCB_ONFAULT(s0)
1120	CALL(memcpy)				/* do the copy.		     */
1121	stq	zero, PCB_ONFAULT(s0)		/* kill the fault handler.   */
1122	ldq	ra, (16-8)(sp)			/* restore ra.		     */
1123	ldq	s0, (16-16)(sp)			/* restore s0.		     */
1124	lda	sp, 16(sp)			/* kill stack frame.	     */
1125	mov	zero, v0			/* return 0. */
1126	RET
1127	END(copyout)
1128
1129LEAF(copyerr_efault, 0)
1130	ldiq	v0, EFAULT			/* return EFAULT.	     */
1131XLEAF(copyerr, 0)
1132	LDGP(pv)
1133	ldq	ra, (16-8)(sp)			/* restore ra.		     */
1134	ldq	s0, (16-16)(sp)			/* restore s0.		     */
1135	lda	sp, 16(sp)			/* kill stack frame.	     */
1136	RET
1137END(copyerr)
1138
1139/**************************************************************************/
1140
1141#define	UFETCHSTORE_PROLOGUE						 \
1142	br	pv, 1f							;\
11431:	LDGP(pv)							;\
1144	ldiq	t0, VM_MAX_ADDRESS	/* make sure that addr */	;\
1145	cmpult	a0, t0, t1		/* is in user space. */		;\
1146	beq	t1, ufetchstoreerr_efault /* if it's not, error out. */
1147
1148/* LINTSTUB: int _ufetch_8(const uint8_t *uaddr, uint8_t *valp); */
1149LEAF_NOPROFILE(_ufetch_8, 2)
1150	UFETCHSTORE_PROLOGUE
1151.L_ufetch_8_start:
1152	ldq_u	t0, 0(a0)	/* load quad containing byte */
1153.L_ufetch_8_end:
1154	extbl	t0, a0, a0	/* a0 = extracted byte */
1155	ldq_u	t0, 0(a1)	/* load dest quad */
1156	insbl	a0, a1, a0	/* a0 = byte in target position */
1157	mskbl	t0, a1, t0	/* clear target byte in destination */
1158	or	a0, t0, a0	/* or in byte to destination */
1159	stq_u	a0, 0(a1)	/* *a1 = fetched byte! */
1160	mov	zero, v0
1161	RET
1162	END(_ufetch_8)
1163
1164/* LINTSTUB: int _ufetch_16(const uint16_t *uaddr, uint16_t *valp); */
1165LEAF_NOPROFILE(_ufetch_16, 2)
1166	UFETCHSTORE_PROLOGUE
1167.L_ufetch_16_start:
1168	ldq_u	t0, 0(a0)	/* load quad containing short */
1169.L_ufetch_16_end:
1170	extwl	t0, a0, a0	/* a0 = extracted short */
1171	ldq_u	t0, 0(a1)	/* load dest quad */
1172	inswl	a0, a1, a0	/* a0 = short in target position */
1173	mskwl	t0, a1, t0	/* clear target short in destination */
1174	or	a0, t0, a0	/* or in short to destination */
1175	stq_u	a0, 0(a1)	/* *a1 = fetched short! */
1176	mov	zero, v0
1177	RET
1178	END(_ufetch_16)
1179
1180/* LINTSTUB: int _ufetch_32(const uint32_t *uaddr, uint32_t *valp); */
1181LEAF_NOPROFILE(_ufetch_32, 2)
1182	UFETCHSTORE_PROLOGUE
1183.L_ufetch_32_start:
1184	ldl	v0, 0(a0)
1185.L_ufetch_32_end:
1186	stl	v0, 0(a1)
1187	mov	zero, v0
1188	RET
1189	END(_ufetch_32)
1190
1191/* LINTSTUB: int _ufetch_64(const uint64_t *uaddr, uint64_t *valp); */
1192LEAF_NOPROFILE(_ufetch_64, 2)
1193	UFETCHSTORE_PROLOGUE
1194.L_ufetch_64_start:
1195	ldq	v0, 0(a0)
1196.L_ufetch_64_end:
1197	stq	v0, 0(a1)
1198	mov	zero, v0
1199	RET
1200	END(_ufetch_64)
1201
1202/* LINTSTUB: int _ustore_8(uint8_t *uaddr, uint8_t val); */
1203LEAF_NOPROFILE(_ustore_8, 2)
1204	UFETCHSTORE_PROLOGUE
1205	zap	a1, 0xfe, a1	/* kill arg's high bytes */
1206	insbl	a1, a0, a1	/* move it to the right spot */
1207.L_ustore_8_start:
1208	ldq_u	t0, 0(a0)	/* load quad around byte */
1209	mskbl	t0, a0, t0	/* kill the target byte */
1210	or	t0, a1, a1	/* put the result together */
1211	stq_u	a1, 0(a0)	/* and store it. */
1212.L_ustore_8_end:
1213	mov	zero, v0
1214	RET
1215	END(_ustore_8)
1216
1217/* LINTSTUB: int _ustore_16(uint16_t *uaddr, uint16_t val); */
1218LEAF_NOPROFILE(_ustore_16, 2)
1219	UFETCHSTORE_PROLOGUE
1220	zap	a1, 0xfc, a1	/* kill arg's high bytes */
1221	inswl	a1, a0, a1	/* move it to the right spot */
1222.L_ustore_16_start:
1223	ldq_u	t0, 0(a0)	/* load quad around short */
1224	mskwl	t0, a0, t0	/* kill the target short */
1225	or	t0, a1, a1	/* put the result together */
1226	stq_u	a1, 0(a0)	/* and store it. */
1227.L_ustore_16_end:
1228	mov	zero, v0
1229	RET
1230	END(_ustore_16)
1231
1232/* LINTSTUB: int _ustore_32(uint32_t *uaddr, uint32_t val); */
1233LEAF_NOPROFILE(_ustore_32, 2)
1234	UFETCHSTORE_PROLOGUE
1235.L_ustore_32_start:
1236	stl	a1, 0(a0)
1237.L_ustore_32_end:
1238	mov	zero, v0
1239	RET
1240	END(_ustore_32)
1241
1242/* LINTSTUB: int _ustore_64(uint64_t *uaddr, uint64_t val); */
1243LEAF_NOPROFILE(_ustore_64, 2)
1244	UFETCHSTORE_PROLOGUE
1245.L_ustore_64_start:
1246	stq	a1, 0(a0)
1247.L_ustore_64_end:
1248	mov	zero, v0
1249	RET
1250	END(_ustore_64)
1251
1252LEAF_NOPROFILE(ufetchstoreerr_efault, 0)
1253	ldiq	v0, EFAULT	/* return EFAULT. */
1254XLEAF(ufetchstoreerr, 0)
1255	LDGP(pv)
1256	RET
1257	END(ufetchstoreerr_efault)
1258
1259/**************************************************************************/
1260
1261/*
1262 * int _ucas_32(volatile uint32_t *uptr, uint32_t old, uint32_t new,
1263 *		uint32_t *ret);
1264 */
1265LEAF_NOPROFILE(_ucas_32, 4)
1266	UFETCHSTORE_PROLOGUE
12673:
1268.Lucas_32_start:
1269	mov	a2, t2
1270	ldl_l	t0, 0(a0)			/* t0 = *uptr */
1271	cmpeq	t0, a1, t1			/* does t0 = old? */
1272	beq	t1, 1f				/* if not, skip */
1273	stl_c	t2, 0(a0)			/* *uptr ~= new */
1274.Lucas_32_end:
1275	beq	t1, 2f				/* did it work? */
12761:
1277	stl	t0, 0(a3)			/* *ret = t0 */
1278	mov	zero, v0
1279	RET
12802:
1281	br	3b
1282END(_ucas_32)
1283
1284/*
1285 * int _ucas_64(volatile uint64_t *uptr, uint64_t old, uint64_t new,
1286 *		uint64_t *ret);
1287 */
1288LEAF_NOPROFILE(_ucas_64, 4)
1289	UFETCHSTORE_PROLOGUE
12903:
1291.Lucas_64_start:
1292	mov	a2, t2
1293	ldq_l	t0, 0(a0)			/* t0 = *uptr */
1294	cmpeq	t0, a1, t1			/* does t0 = old? */
1295	beq	t1, 1f				/* if not, skip */
1296	stq_c	t2, 0(a0)			/* *uptr ~= new */
1297.Lucas_64_end:
1298	beq	t1, 2f				/* did it work? */
12991:
1300	stq	t0, 0(a3)			/* *ret = t0 */
1301	mov	zero, v0
1302	RET
13032:
1304	br	3b
1305END(_ucas_64)
1306
1307/**************************************************************************/
1308
1309/*
1310 * Fault table of user access functions for trap().
1311 */
1312	.section ".rodata"
1313	.globl	onfault_table
1314onfault_table:
1315	.quad	.L_ufetch_8_start
1316	.quad	.L_ufetch_8_end
1317	.quad	ufetchstoreerr
1318
1319	.quad	.L_ufetch_16_start
1320	.quad	.L_ufetch_16_end
1321	.quad	ufetchstoreerr
1322
1323	.quad	.L_ufetch_32_start
1324	.quad	.L_ufetch_32_end
1325	.quad	ufetchstoreerr
1326
1327	.quad	.L_ufetch_64_start
1328	.quad	.L_ufetch_64_end
1329	.quad	ufetchstoreerr
1330
1331	.quad	.L_ustore_8_start
1332	.quad	.L_ustore_8_end
1333	.quad	ufetchstoreerr
1334
1335	.quad	.L_ustore_16_start
1336	.quad	.L_ustore_16_end
1337	.quad	ufetchstoreerr
1338
1339	.quad	.L_ustore_32_start
1340	.quad	.L_ustore_32_end
1341	.quad	ufetchstoreerr
1342
1343	.quad	.L_ustore_64_start
1344	.quad	.L_ustore_64_end
1345	.quad	ufetchstoreerr
1346
1347	.quad	.Lucas_32_start
1348	.quad	.Lucas_32_end
1349	.quad	ufetchstoreerr
1350
1351	.quad	.Lucas_64_start
1352	.quad	.Lucas_64_end
1353	.quad	ufetchstoreerr
1354
1355	.quad	0
1356
1357	.text
1358
1359/**************************************************************************/
1360
1361/*
1362 * console 'restart' routine to be placed in HWRPB.
1363 */
1364LEAF(XentRestart, 1)			/* XXX should be NESTED */
1365	.set noat
1366	lda	sp,-(FRAME_SIZE*8)(sp)
1367	stq	at_reg,(FRAME_AT*8)(sp)
1368	.set at
1369	stq	v0,(FRAME_V0*8)(sp)
1370	stq	a0,(FRAME_A0*8)(sp)
1371	stq	a1,(FRAME_A1*8)(sp)
1372	stq	a2,(FRAME_A2*8)(sp)
1373	stq	a3,(FRAME_A3*8)(sp)
1374	stq	a4,(FRAME_A4*8)(sp)
1375	stq	a5,(FRAME_A5*8)(sp)
1376	stq	s0,(FRAME_S0*8)(sp)
1377	stq	s1,(FRAME_S1*8)(sp)
1378	stq	s2,(FRAME_S2*8)(sp)
1379	stq	s3,(FRAME_S3*8)(sp)
1380	stq	s4,(FRAME_S4*8)(sp)
1381	stq	s5,(FRAME_S5*8)(sp)
1382	stq	s6,(FRAME_S6*8)(sp)
1383	stq	t0,(FRAME_T0*8)(sp)
1384	stq	t1,(FRAME_T1*8)(sp)
1385	stq	t2,(FRAME_T2*8)(sp)
1386	stq	t3,(FRAME_T3*8)(sp)
1387	stq	t4,(FRAME_T4*8)(sp)
1388	stq	t5,(FRAME_T5*8)(sp)
1389	stq	t6,(FRAME_T6*8)(sp)
1390	stq	t7,(FRAME_T7*8)(sp)
1391	stq	t8,(FRAME_T8*8)(sp)
1392	stq	t9,(FRAME_T9*8)(sp)
1393	stq	t10,(FRAME_T10*8)(sp)
1394	stq	t11,(FRAME_T11*8)(sp)
1395	stq	t12,(FRAME_T12*8)(sp)
1396	stq	ra,(FRAME_RA*8)(sp)
1397
1398	br	pv,1f
13991:	LDGP(pv)
1400
1401	mov	sp,a0
1402	CALL(console_restart)
1403
1404	call_pal PAL_halt
1405	END(XentRestart)
1406
1407/**************************************************************************/
1408
1409/*
1410 * Kernel setjmp and longjmp.  Rather minimalist.
1411 *
1412 *	longjmp(label_t *a)
1413 * will generate a "return (1)" from the last call to
1414 *	setjmp(label_t *a)
1415 * by restoring registers from the stack,
1416 */
1417
1418	.set	noreorder
1419
1420LEAF(setjmp, 1)
1421	LDGP(pv)
1422
1423	stq	ra, (0 * 8)(a0)			/* return address */
1424	stq	s0, (1 * 8)(a0)			/* callee-saved registers */
1425	stq	s1, (2 * 8)(a0)
1426	stq	s2, (3 * 8)(a0)
1427	stq	s3, (4 * 8)(a0)
1428	stq	s4, (5 * 8)(a0)
1429	stq	s5, (6 * 8)(a0)
1430	stq	s6, (7 * 8)(a0)
1431	stq	sp, (8 * 8)(a0)
1432
1433	ldiq	t0, 0xbeeffedadeadbabe		/* set magic number */
1434	stq	t0, (9 * 8)(a0)
1435
1436	mov	zero, v0			/* return zero */
1437	RET
1438END(setjmp)
1439
1440LEAF(longjmp, 1)
1441	LDGP(pv)
1442
1443	ldiq	t0, 0xbeeffedadeadbabe		/* check magic number */
1444	ldq	t1, (9 * 8)(a0)
1445	cmpeq	t0, t1, t0
1446	beq	t0, longjmp_botch		/* if bad, punt */
1447
1448	ldq	ra, (0 * 8)(a0)			/* return address */
1449	ldq	s0, (1 * 8)(a0)			/* callee-saved registers */
1450	ldq	s1, (2 * 8)(a0)
1451	ldq	s2, (3 * 8)(a0)
1452	ldq	s3, (4 * 8)(a0)
1453	ldq	s4, (5 * 8)(a0)
1454	ldq	s5, (6 * 8)(a0)
1455	ldq	s6, (7 * 8)(a0)
1456	ldq	sp, (8 * 8)(a0)
1457
1458	ldiq	v0, 1
1459	RET
1460
1461longjmp_botch:
1462	lda	a0, longjmp_botchmsg
1463	mov	ra, a1
1464	CALL(panic)
1465	call_pal PAL_bugchk
1466
1467	.data
1468longjmp_botchmsg:
1469	.asciz	"longjmp botch from %p"
1470	.text
1471END(longjmp)
1472
1473/*
1474 * void sts(int rn, u_int32_t *rval);
1475 * void stt(int rn, u_int64_t *rval);
1476 * void lds(int rn, u_int32_t *rval);
1477 * void ldt(int rn, u_int64_t *rval);
1478 */
1479
1480.macro	make_freg_util name, op
1481	LEAF(alpha_\name, 2)
1482	and	a0, 0x1f, a0
1483	s8addq	a0, pv, pv
1484	addq	pv, 1f - alpha_\name, pv
1485	jmp	(pv)
14861:
1487	rn = 0
1488	.rept	32
1489	\op	$f0 + rn, 0(a1)
1490	RET
1491	rn = rn + 1
1492	.endr
1493	END(alpha_\name)
1494.endm
1495/*
1496LEAF(alpha_sts, 2)
1497LEAF(alpha_stt, 2)
1498LEAF(alpha_lds, 2)
1499LEAF(alpha_ldt, 2)
1500 */
1501	make_freg_util sts, sts
1502	make_freg_util stt, stt
1503	make_freg_util lds, lds
1504	make_freg_util ldt, ldt
1505
1506LEAF(alpha_read_fpcr, 0); f30save = 0; rettmp = 8; framesz = 16
1507	lda	sp, -framesz(sp)
1508	stt	$f30, f30save(sp)
1509	mf_fpcr	$f30
1510	stt	$f30, rettmp(sp)
1511	ldt	$f30, f30save(sp)
1512	ldq	v0, rettmp(sp)
1513	lda	sp, framesz(sp)
1514	RET
1515END(alpha_read_fpcr)
1516
1517LEAF(alpha_write_fpcr, 1); f30save = 0; fpcrtmp = 8; framesz = 16
1518	lda	sp, -framesz(sp)
1519	stq	a0, fpcrtmp(sp)
1520	stt	$f30, f30save(sp)
1521	ldt	$f30, fpcrtmp(sp)
1522	mt_fpcr	$f30
1523	ldt	$f30, f30save(sp)
1524	lda	sp, framesz(sp)
1525	RET
1526END(alpha_write_fpcr)
1527