Home | History | Annotate | Line # | Download | only in alpha
      1 /* $NetBSD: locore.s,v 1.145 2025/09/06 02:53:22 riastradh 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 (at) 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.145 2025/09/06 02:53:22 riastradh 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__
     94 kernel_text:
     95 
     96 /*
     97  * bootstack: a temporary stack, for booting.
     98  *
     99  * Extends from 'start' down.
    100  */
    101 bootstack:
    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  */
    116 IMPORT(prom_mapped, 4)
    117 NESTED_NOPROFILE(locorestart,1,0,ra,0,0)
    118 	br	pv,1f
    119 1:	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__
    232 backtolocore1:
    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 
    245 NESTED_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. */
    250 XNESTED(esigcode,0)
    251 	END(sigcode)
    252 #endif /* COMPAT_16 */
    253 
    254 /**************************************************************************/
    255 
    256 /*
    257  * exception_return: return from trap, exception, or syscall
    258  */
    259 
    260 LEAF(exception_return, 1)			/* XXX should be NESTED */
    261 	br	pv, 1f
    262 1:	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 
    277 2:	/*
    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 */
    302 3:	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. */
    307 4:	ldq	t2, L_MD_FLAGS(s0)
    308 	cmplt	t2, zero, a0
    309 	call_pal PAL_OSF1_wrfen
    310 
    311 	/* restore the registers, and return */
    312 5:	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 */
    323 6:	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 */
    335 7:	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 
    351 LEAF(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 
    379 LEAF(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 
    516 LEAF(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 
    541 LEAF(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 
    598 LEAF(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 
    660 LEAF(savectx, 1)
    661 	br	pv, 1f
    662 1:	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  * Arguments:
    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  */
    689 NESTED_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 
    758 LEAF_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  */
    794 LEAF(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 
    828 1:	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 */
    841 2:
    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 
    858 3:	/*
    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 
    873 4:
    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  */
    895 LEAF_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
    911 LEAF(alpha_copystr_bwx, 4)
    912 	LDGP(pv)
    913 
    914 	mov	a2, t0			/* t0 = i = len */
    915 	beq	a2, 5f			/* if (len == 0), bail */
    916 
    917 1:	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 
    925 2:	beq	a3, 3f			/* if (lenp != NULL) */
    926 	subl	t0, a2, t0		/* *lenp = (i - len) */
    927 	stq	t0, 0(a3)
    928 3:	bne	t1, 4f			/* *from != '\0'; leave in a huff */
    929 
    930 	mov	zero, v0		/* return 0. */
    931 	RET
    932 
    933 4:	ldiq	v0, ENAMETOOLONG
    934 	RET
    935 
    936 5:	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 
    948 LEAF(alpha_copystr, 4)
    949 	LDGP(pv)
    950 
    951 	mov	a2, t0			/* t0 = i = len */
    952 	beq	a2, 5f			/* if (len == 0), bail */
    953 
    954 1:	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 
    968 2:	beq	a3, 3f			/* if (lenp != NULL) */
    969 	subl	t0, a2, t0		/* *lenp = (i - len) */
    970 	stq	t0, 0(a3)
    971 3:	bne	t1, 4f			/* *from != '\0'; leave in a huff */
    972 
    973 	mov	zero, v0		/* return 0. */
    974 	RET
    975 
    976 4:	ldiq	v0, ENAMETOOLONG
    977 	RET
    978 
    979 5:	ldiq	t1, 1			/* fool the test above... */
    980 	br	zero, 2b
    981 	EXPORT(alpha_copystr_end)
    982 	END(alpha_copystr)
    983 
    984 NESTED(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 
   1005 NESTED(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  */
   1041 NESTED(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 
   1067 LEAF(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
   1075 END(kcopyerr)
   1076 
   1077 NESTED(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 
   1103 NESTED(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 
   1129 LEAF(copyerr_efault, 0)
   1130 	ldiq	v0, EFAULT			/* return EFAULT.	     */
   1131 XLEAF(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
   1137 END(copyerr)
   1138 
   1139 /**************************************************************************/
   1140 
   1141 #define	UFETCHSTORE_PROLOGUE						 \
   1142 	br	pv, 1f							;\
   1143 1:	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); */
   1149 LEAF_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); */
   1165 LEAF_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); */
   1181 LEAF_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); */
   1192 LEAF_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); */
   1203 LEAF_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); */
   1218 LEAF_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); */
   1233 LEAF_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); */
   1243 LEAF_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 
   1252 LEAF_NOPROFILE(ufetchstoreerr_efault, 0)
   1253 	ldiq	v0, EFAULT	/* return EFAULT. */
   1254 XLEAF(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  */
   1265 LEAF_NOPROFILE(_ucas_32, 4)
   1266 	UFETCHSTORE_PROLOGUE
   1267 3:
   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? */
   1276 1:
   1277 	stl	t0, 0(a3)			/* *ret = t0 */
   1278 	mov	zero, v0
   1279 	RET
   1280 2:
   1281 	br	3b
   1282 END(_ucas_32)
   1283 
   1284 /*
   1285  * int _ucas_64(volatile uint64_t *uptr, uint64_t old, uint64_t new,
   1286  *		uint64_t *ret);
   1287  */
   1288 LEAF_NOPROFILE(_ucas_64, 4)
   1289 	UFETCHSTORE_PROLOGUE
   1290 3:
   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? */
   1299 1:
   1300 	stq	t0, 0(a3)			/* *ret = t0 */
   1301 	mov	zero, v0
   1302 	RET
   1303 2:
   1304 	br	3b
   1305 END(_ucas_64)
   1306 
   1307 /**************************************************************************/
   1308 
   1309 /*
   1310  * Fault table of user access functions for trap().
   1311  */
   1312 	.section ".rodata"
   1313 	.globl	onfault_table
   1314 onfault_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  */
   1364 LEAF(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
   1399 1:	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 
   1420 LEAF(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
   1438 END(setjmp)
   1439 
   1440 LEAF(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 
   1461 longjmp_botch:
   1462 	lda	a0, longjmp_botchmsg
   1463 	mov	ra, a1
   1464 	CALL(panic)
   1465 	call_pal PAL_bugchk
   1466 
   1467 	.data
   1468 longjmp_botchmsg:
   1469 	.asciz	"longjmp botch from %p"
   1470 	.text
   1471 END(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)
   1486 1:
   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 /*
   1496 LEAF(alpha_sts, 2)
   1497 LEAF(alpha_stt, 2)
   1498 LEAF(alpha_lds, 2)
   1499 LEAF(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 
   1506 LEAF(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
   1515 END(alpha_read_fpcr)
   1516 
   1517 LEAF(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
   1526 END(alpha_write_fpcr)
   1527 
   1528 LEAF(paravirt_membar_sync, 0)
   1529 	/*
   1530 	 * Store-before-load ordering with respect to matching logic
   1531 	 * on the hypervisor side.
   1532 	 *
   1533 	 * This is the same as membar_sync, but without hotpatching
   1534 	 * away the MB instruction on uniprocessor boots -- because
   1535 	 * under virtualization, we still have to coordinate with a
   1536 	 * `device' backed by a hypervisor that is potentially on
   1537 	 * another physical CPU even if we observe only one virtual CPU
   1538 	 * as the guest.
   1539 	 */
   1540 	mb
   1541 	RET
   1542 END(paravirt_membar_sync)
   1543