1/*        $NetBSD: locore.s,v 1.286 2025/04/29 09:55:14 martin Exp $  */
2
3/*
4 * Copyright (c) 1996 Paul Kranenburg
5 * Copyright (c) 1996
6 *        The President and Fellows of Harvard College. All rights reserved.
7 * Copyright (c) 1992, 1993
8 *        The Regents of the University of California.  All rights reserved.
9 *
10 * This software was developed by the Computer Systems Engineering group
11 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
12 * contributed to Berkeley.
13 *
14 * All advertising materials mentioning features or use of this software
15 * must display the following acknowledgement:
16 *        This product includes software developed by the University of
17 *        California, Lawrence Berkeley Laboratory.
18 *        This product includes software developed by Harvard University.
19 *
20 * Redistribution and use in source and binary forms, with or without
21 * modification, are permitted provided that the following conditions
22 * are met:
23 * 1. Redistributions of source code must retain the above copyright
24 *    notice, this list of conditions and the following disclaimer.
25 * 2. Redistributions in binary form must reproduce the above copyright
26 *    notice, this list of conditions and the following disclaimer in the
27 *    documentation and/or other materials provided with the distribution.
28 * 3. All advertising materials mentioning features or use of this software
29 *    must display the following acknowledgement:
30 *        This product includes software developed by the University of
31 *        California, Berkeley and its contributors.
32 *        This product includes software developed by Harvard University.
33 *        This product includes software developed by Paul Kranenburg.
34 * 4. Neither the name of the University nor the names of its contributors
35 *    may be used to endorse or promote products derived from this software
36 *    without specific prior written permission.
37 *
38 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
39 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
40 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
41 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
42 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
43 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
44 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
45 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
46 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
47 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
48 * SUCH DAMAGE.
49 *
50 *        @(#)locore.s        8.4 (Berkeley) 12/10/93
51 */
52
53#include "opt_ddb.h"
54#include "opt_kgdb.h"
55#include "opt_compat_netbsd.h"
56#include "opt_compat_sunos.h"
57#include "opt_multiprocessor.h"
58#include "opt_lockdebug.h"
59
60#include "assym.h"
61#include <machine/param.h>
62#include <machine/asm.h>
63#include <sparc/sparc/intreg.h>
64#include <sparc/sparc/timerreg.h>
65#include <sparc/sparc/vaddrs.h>
66#ifdef notyet
67#include <sparc/dev/zsreg.h>
68#endif
69#include <machine/ctlreg.h>
70#include <machine/intr.h>
71#include <machine/psl.h>
72#include <machine/signal.h>
73#include <machine/trap.h>
74
75#include <sys/syscall.h>
76
77/* use as needed to align things on longword boundaries */
78#define   _ALIGN    .align 4
79
80/*
81 * CCFSZ (C Compiler Frame SiZe) is the size of a stack frame required if
82 * a function is to call C code.  It should be just 64, but Sun defined
83 * their frame with space to hold arguments 0 through 5 (plus some junk),
84 * and varargs routines (such as printf) demand this, and gcc uses this
85 * area at times anyway.
86 */
87#define   CCFSZ     96
88
89/* We rely on the fact that %lo(CPUINFO_VA) is zero */
90.if CPUINFO_VA & 0x1fff
91BARF
92.endif
93
94#if EV_COUNT != 0
95# error "this code does not work with EV_COUNT != 0"
96#endif
97#if EV_STRUCTSIZE != 32
98# error "this code does not work with EV_STRUCTSIZE != 32"
99#else
100# define EV_STRUCTSHIFT       5
101#endif
102
103/*
104 * Another handy macro: load one register window, given `base' address.
105 * This can be either a simple register (e.g., %sp) or include an initial
106 * offset (e.g., %g6 + PCB_RW).
107 */
108#define   LOADWIN(addr) \
109          ldd       [addr], %l0; \
110          ldd       [addr + 8], %l2; \
111          ldd       [addr + 16], %l4; \
112          ldd       [addr + 24], %l6; \
113          ldd       [addr + 32], %i0; \
114          ldd       [addr + 40], %i2; \
115          ldd       [addr + 48], %i4; \
116          ldd       [addr + 56], %i6
117
118/*
119 * To return from trap we need the two-instruction sequence
120 * `jmp %l1; rett %l2', which is defined here for convenience.
121 */
122#define   RETT      jmp %l1; rett %l2
123
124          .data
125/*
126 * The interrupt stack.
127 *
128 * This is the very first thing in the data segment, and therefore has
129 * the lowest kernel stack address.  We count on this in the interrupt
130 * trap-frame setup code, since we may need to switch from the kernel
131 * stack to the interrupt stack (iff we are not already on the interrupt
132 * stack).  One sethi+cmp is all we need since this is so carefully
133 * arranged.
134 *
135 * In SMP kernels, each CPU has its own interrupt stack and the computation
136 * to determine whether we're already on the interrupt stack is slightly
137 * more time consuming (see INTR_SETUP() below).
138 */
139          .globl    _C_LABEL(intstack)
140          .globl    _C_LABEL(eintstack)
141_C_LABEL(intstack):
142          .skip     INT_STACK_SIZE                ! 16k = 128 128-byte stack frames
143_C_LABEL(eintstack):
144
145_EINTSTACKP = CPUINFO_VA + CPUINFO_EINTSTACK
146
147/*
148 * CPUINFO_VA is a CPU-local virtual address; cpi->ci_self is a global
149 * virtual address for the same structure.  It must be stored in p->p_cpu
150 * upon context switch.
151 */
152_CISELFP  = CPUINFO_VA + CPUINFO_SELF
153_CIFLAGS  = CPUINFO_VA + CPUINFO_FLAGS
154
155/* Per-CPU AST requests */
156_WANT_AST = CPUINFO_VA + CPUINFO_WANT_AST
157
158/*
159 * Process 0's u.
160 *
161 * This must be aligned on an 8 byte boundary.
162 */
163          .globl    _C_LABEL(u0)
164_C_LABEL(u0):       .skip     USPACE
165estack0:
166
167#ifdef KGDB
168/*
169 * Another item that must be aligned, easiest to put it here.
170 */
171KGDB_STACK_SIZE = 2048
172          .globl    _C_LABEL(kgdb_stack)
173_C_LABEL(kgdb_stack):
174          .skip     KGDB_STACK_SIZE               ! hope this is enough
175#endif
176
177/*
178 * cpcb points to the current pcb (and hence u. area).
179 * Initially this is the special one.
180 */
181cpcb = CPUINFO_VA + CPUINFO_CURPCB
182
183/* curlwp points to the current LWP that has the CPU */
184curlwp = CPUINFO_VA + CPUINFO_CURLWP
185
186/*
187 * cputyp is the current CPU type, used to distinguish between
188 * the many variations of different sun4* machines. It contains
189 * the value CPU_SUN4, CPU_SUN4C, or CPU_SUN4M.
190 */
191          .globl    _C_LABEL(cputyp)
192_C_LABEL(cputyp):
193          .word     1
194
195#if defined(SUN4C) || defined(SUN4M)
196cputypval:
197          .asciz    "sun4c"
198          .ascii    "     "
199cputypvar:
200          .asciz    "compatible"
201          _ALIGN
202#endif
203
204/*
205 * There variables are pointed to by the cpp symbols PGSHIFT, NBPG,
206 * and PGOFSET.
207 */
208          .globl    _C_LABEL(pgshift), _C_LABEL(nbpg), _C_LABEL(pgofset)
209_C_LABEL(pgshift):
210          .word     0
211_C_LABEL(nbpg):
212          .word     0
213_C_LABEL(pgofset):
214          .word     0
215
216          .globl    _C_LABEL(trapbase)
217_C_LABEL(trapbase):
218          .word     0
219
220#if 0
221#if defined(SUN4M)
222_mapme:
223          .asciz "0 0 f8000000 15c6a0 map-pages"
224#endif
225#endif
226
227#if !defined(SUN4D)
228sun4d_notsup:
229          .asciz    "cr .( NetBSD/sparc: this kernel does not support the sun4d) cr"
230#endif
231#if !defined(SUN4M)
232sun4m_notsup:
233          .asciz    "cr .( NetBSD/sparc: this kernel does not support the sun4m) cr"
234#endif
235#if !defined(SUN4C)
236sun4c_notsup:
237          .asciz    "cr .( NetBSD/sparc: this kernel does not support the sun4c) cr"
238#endif
239#if !defined(SUN4)
240sun4_notsup:
241          ! the extra characters at the end are to ensure the zs fifo drains
242          ! before we halt. Sick, eh?
243          .asciz    "NetBSD/sparc: this kernel does not support the sun4\n\r \b"
244#endif
245          _ALIGN
246
247          .text
248
249/*
250 * The first thing in the real text segment is the trap vector table,
251 * which must be aligned on a 4096 byte boundary.  The text segment
252 * starts beyond page 0 of KERNBASE so that there is a red zone
253 * between user and kernel space.  Since the boot ROM loads us at
254 * PROM_LOADADDR, it is far easier to start at KERNBASE+PROM_LOADADDR than to
255 * buck the trend.  This is two or four pages in (depending on if
256 * pagesize is 8192 or 4096).    We place two items in this area:
257 * the message buffer (phys addr 0) and the cpu_softc structure for
258 * the first processor in the system (phys addr 0x2000).
259 * Because the message buffer is in our "red zone" between user and
260 * kernel space we remap it in configure() to another location and
261 * invalidate the mapping at KERNBASE.
262 */
263
264/*
265 * Each trap has room for four instructions, of which one perforce must
266 * be a branch.  On entry the hardware has copied pc and npc to %l1 and
267 * %l2 respectively.  We use two more to read the psr into %l0, and to
268 * put the trap type value into %l3 (with a few exceptions below).
269 * We could read the trap type field of %tbr later in the code instead,
270 * but there is no need, and that would require more instructions
271 * (read+mask, vs 1 `mov' here).
272 *
273 * I used to generate these numbers by address arithmetic, but gas's
274 * expression evaluator has about as much sense as your average slug
275 * (oddly enough, the code looks about as slimy too).  Thus, all the
276 * trap numbers are given as arguments to the trap macros.  This means
277 * there is one line per trap.  Sigh.
278 *
279 * Note that only the local registers may be used, since the trap
280 * window is potentially the last window.  Its `in' registers are
281 * the previous window's outs (as usual), but more important, its
282 * `out' registers may be in use as the `topmost' window's `in' registers.
283 * The global registers are of course verboten (well, until we save
284 * them away).
285 *
286 * Hardware interrupt vectors can be `linked'---the linkage is to regular
287 * C code---or rewired to fast in-window handlers.  The latter are good
288 * for unbuffered hardware like the Zilog serial chip and the AMD audio
289 * chip, where many interrupts can be handled trivially with pseudo-DMA or
290 * similar.  Only one `fast' interrupt can be used per level, however, and
291 * direct and `fast' interrupts are incompatible.  Routines in intr.c
292 * handle setting these, with optional paranoia.
293 */
294
295          /* regular vectored traps */
296#define   VTRAP(type, label) \
297          mov (type), %l3; b label; mov %psr, %l0; nop
298
299          /* hardware interrupts (can be linked or made `fast') */
300#define   HARDINT44C(lev) \
301          mov (lev), %l3; b _C_LABEL(sparc_interrupt44c); mov %psr, %l0; nop
302
303          /* hardware interrupts (can be linked or made `fast') */
304#define   HARDINT4M(lev) \
305          mov (lev), %l3; b _C_LABEL(sparc_interrupt4m); mov %psr, %l0; nop
306
307          /* software interrupts (may not be made direct, sorry---but you
308             should not be using them trivially anyway) */
309#define   SOFTINT44C(lev, bit) \
310          mov (lev), %l3; mov (bit), %l4; b softintr_sun44c; mov %psr, %l0
311
312          /* There's no SOFTINT4M(): both hard and soft vector the same way */
313
314          /* traps that just call trap() */
315#define   TRAP(type)          VTRAP(type, slowtrap)
316
317          /* architecturally undefined traps (cause panic) */
318#define   UTRAP(type)         VTRAP(type, slowtrap)
319
320          /* software undefined traps (may be replaced) */
321#define   STRAP(type)         VTRAP(type, slowtrap)
322
323/* breakpoint acts differently under kgdb */
324#ifdef KGDB
325#define   BPT                 VTRAP(T_BREAKPOINT, bpt)
326#define   BPT_KGDB_EXEC       VTRAP(T_KGDB_EXEC, bpt)
327#else
328#define   BPT                 TRAP(T_BREAKPOINT)
329#define   BPT_KGDB_EXEC       TRAP(T_KGDB_EXEC)
330#endif
331
332/* special high-speed 1-instruction-shaved-off traps (get nothing in %l3) */
333#define   SYSCALL             b _C_LABEL(_syscall); mov %psr, %l0; nop; nop
334#define   WINDOW_OF b window_of; mov %psr, %l0; nop; nop
335#define   WINDOW_UF b window_uf; mov %psr, %l0; nop; nop
336#ifdef notyet
337#define   ZS_INTERRUPT        b zshard; mov %psr, %l0; nop; nop
338#else
339#define   ZS_INTERRUPT44C     HARDINT44C(12)
340#define   ZS_INTERRUPT4M      HARDINT4M(12)
341#endif
342
343#ifdef DEBUG
344#define TRAP_TRACE(tt, tmp)                                           \
345          sethi     %hi(CPUINFO_VA + CPUINFO_TT), tmp;                \
346          st        tt, [tmp + %lo(CPUINFO_VA + CPUINFO_TT)];
347#define TRAP_TRACE2(tt, tmp1, tmp2)                                   \
348          mov       tt, tmp1;                                         \
349          TRAP_TRACE(tmp1, tmp2)
350#else /* DEBUG */
351#define TRAP_TRACE(tt,tmp)              /**/
352#define TRAP_TRACE2(tt,tmp1,tmp2)       /**/
353#endif /* DEBUG */
354
355          .globl    _ASM_LABEL(start), _C_LABEL(kernel_text)
356          _C_LABEL(kernel_text) = start           ! for kvm_mkdb(8)
357_ASM_LABEL(start):
358/*
359 * Put sun4 traptable first, since it needs the most stringent alignment (8192)
360 */
361#if defined(SUN4)
362trapbase_sun4:
363          /* trap 0 is special since we cannot receive it */
364          b dostart; nop; nop; nop      ! 00 = reset (fake)
365          VTRAP(T_TEXTFAULT, memfault_sun4)       ! 01 = instr. fetch fault
366          TRAP(T_ILLINST)                         ! 02 = illegal instruction
367          TRAP(T_PRIVINST)              ! 03 = privileged instruction
368          TRAP(T_FPDISABLED)            ! 04 = fp instr, but EF bit off in psr
369          WINDOW_OF                     ! 05 = window overflow
370          WINDOW_UF                     ! 06 = window underflow
371          TRAP(T_ALIGN)                           ! 07 = address alignment error
372          VTRAP(T_FPE, fp_exception)    ! 08 = fp exception
373          VTRAP(T_DATAFAULT, memfault_sun4)       ! 09 = data fetch fault
374          TRAP(T_TAGOF)                           ! 0a = tag overflow
375          UTRAP(0x0b)
376          UTRAP(0x0c)
377          UTRAP(0x0d)
378          UTRAP(0x0e)
379          UTRAP(0x0f)
380          UTRAP(0x10)
381          SOFTINT44C(1, IE_L1)                    ! 11 = level 1 interrupt
382          HARDINT44C(2)                           ! 12 = level 2 interrupt
383          HARDINT44C(3)                           ! 13 = level 3 interrupt
384          SOFTINT44C(4, IE_L4)                    ! 14 = level 4 interrupt
385          HARDINT44C(5)                           ! 15 = level 5 interrupt
386          SOFTINT44C(6, IE_L6)                    ! 16 = level 6 interrupt
387          HARDINT44C(7)                           ! 17 = level 7 interrupt
388          HARDINT44C(8)                           ! 18 = level 8 interrupt
389          HARDINT44C(9)                           ! 19 = level 9 interrupt
390          HARDINT44C(10)                          ! 1a = level 10 interrupt
391          HARDINT44C(11)                          ! 1b = level 11 interrupt
392          ZS_INTERRUPT44C                         ! 1c = level 12 (zs) interrupt
393          HARDINT44C(13)                          ! 1d = level 13 interrupt
394          HARDINT44C(14)                          ! 1e = level 14 interrupt
395          VTRAP(15, nmi_sun4)           ! 1f = nonmaskable interrupt
396          UTRAP(0x20)
397          UTRAP(0x21)
398          UTRAP(0x22)
399          UTRAP(0x23)
400          TRAP(T_CPDISABLED)  ! 24 = coprocessor instr, EC bit off in psr
401          UTRAP(0x25)
402          UTRAP(0x26)
403          UTRAP(0x27)
404          TRAP(T_CPEXCEPTION) ! 28 = coprocessor exception
405          UTRAP(0x29)
406          UTRAP(0x2a)
407          UTRAP(0x2b)
408          UTRAP(0x2c)
409          UTRAP(0x2d)
410          UTRAP(0x2e)
411          UTRAP(0x2f)
412          UTRAP(0x30)
413          UTRAP(0x31)
414          UTRAP(0x32)
415          UTRAP(0x33)
416          UTRAP(0x34)
417          UTRAP(0x35)
418          UTRAP(0x36)
419          UTRAP(0x37)
420          UTRAP(0x38)
421          UTRAP(0x39)
422          UTRAP(0x3a)
423          UTRAP(0x3b)
424          UTRAP(0x3c)
425          UTRAP(0x3d)
426          UTRAP(0x3e)
427          UTRAP(0x3f)
428          UTRAP(0x40)
429          UTRAP(0x41)
430          UTRAP(0x42)
431          UTRAP(0x43)
432          UTRAP(0x44)
433          UTRAP(0x45)
434          UTRAP(0x46)
435          UTRAP(0x47)
436          UTRAP(0x48)
437          UTRAP(0x49)
438          UTRAP(0x4a)
439          UTRAP(0x4b)
440          UTRAP(0x4c)
441          UTRAP(0x4d)
442          UTRAP(0x4e)
443          UTRAP(0x4f)
444          UTRAP(0x50)
445          UTRAP(0x51)
446          UTRAP(0x52)
447          UTRAP(0x53)
448          UTRAP(0x54)
449          UTRAP(0x55)
450          UTRAP(0x56)
451          UTRAP(0x57)
452          UTRAP(0x58)
453          UTRAP(0x59)
454          UTRAP(0x5a)
455          UTRAP(0x5b)
456          UTRAP(0x5c)
457          UTRAP(0x5d)
458          UTRAP(0x5e)
459          UTRAP(0x5f)
460          UTRAP(0x60)
461          UTRAP(0x61)
462          UTRAP(0x62)
463          UTRAP(0x63)
464          UTRAP(0x64)
465          UTRAP(0x65)
466          UTRAP(0x66)
467          UTRAP(0x67)
468          UTRAP(0x68)
469          UTRAP(0x69)
470          UTRAP(0x6a)
471          UTRAP(0x6b)
472          UTRAP(0x6c)
473          UTRAP(0x6d)
474          UTRAP(0x6e)
475          UTRAP(0x6f)
476          UTRAP(0x70)
477          UTRAP(0x71)
478          UTRAP(0x72)
479          UTRAP(0x73)
480          UTRAP(0x74)
481          UTRAP(0x75)
482          UTRAP(0x76)
483          UTRAP(0x77)
484          UTRAP(0x78)
485          UTRAP(0x79)
486          UTRAP(0x7a)
487          UTRAP(0x7b)
488          UTRAP(0x7c)
489          UTRAP(0x7d)
490          UTRAP(0x7e)
491          UTRAP(0x7f)
492          SYSCALL                       ! 80 = sun syscall
493          BPT                           ! 81 = pseudo breakpoint instruction
494          TRAP(T_DIV0)                  ! 82 = divide by zero
495          TRAP(T_FLUSHWIN)    ! 83 = flush windows
496          TRAP(T_CLEANWIN)    ! 84 = provide clean windows
497          TRAP(T_RANGECHECK)  ! 85 = ???
498          TRAP(T_FIXALIGN)    ! 86 = fix up unaligned accesses
499          TRAP(T_INTOF)                 ! 87 = integer overflow
500          SYSCALL                       ! 88 = svr4 syscall
501          SYSCALL                       ! 89 = bsd syscall
502          BPT_KGDB_EXEC                 ! 8a = enter kernel gdb on kernel startup
503          STRAP(0x8b)
504          STRAP(0x8c)
505          STRAP(0x8d)
506          STRAP(0x8e)
507          STRAP(0x8f)
508          STRAP(0x90)
509          STRAP(0x91)
510          STRAP(0x92)
511          STRAP(0x93)
512          STRAP(0x94)
513          STRAP(0x95)
514          STRAP(0x96)
515          STRAP(0x97)
516          STRAP(0x98)
517          STRAP(0x99)
518          STRAP(0x9a)
519          STRAP(0x9b)
520          STRAP(0x9c)
521          STRAP(0x9d)
522          STRAP(0x9e)
523          STRAP(0x9f)
524          STRAP(0xa0)
525          STRAP(0xa1)
526          STRAP(0xa2)
527          STRAP(0xa3)
528          STRAP(0xa4)
529          STRAP(0xa5)
530          STRAP(0xa6)
531          STRAP(0xa7)
532          STRAP(0xa8)
533          STRAP(0xa9)
534          STRAP(0xaa)
535          STRAP(0xab)
536          STRAP(0xac)
537          STRAP(0xad)
538          STRAP(0xae)
539          STRAP(0xaf)
540          STRAP(0xb0)
541          STRAP(0xb1)
542          STRAP(0xb2)
543          STRAP(0xb3)
544          STRAP(0xb4)
545          STRAP(0xb5)
546          STRAP(0xb6)
547          STRAP(0xb7)
548          STRAP(0xb8)
549          STRAP(0xb9)
550          STRAP(0xba)
551          STRAP(0xbb)
552          STRAP(0xbc)
553          STRAP(0xbd)
554          STRAP(0xbe)
555          STRAP(0xbf)
556          STRAP(0xc0)
557          STRAP(0xc1)
558          STRAP(0xc2)
559          STRAP(0xc3)
560          STRAP(0xc4)
561          STRAP(0xc5)
562          STRAP(0xc6)
563          STRAP(0xc7)
564          STRAP(0xc8)
565          STRAP(0xc9)
566          STRAP(0xca)
567          STRAP(0xcb)
568          STRAP(0xcc)
569          STRAP(0xcd)
570          STRAP(0xce)
571          STRAP(0xcf)
572          STRAP(0xd0)
573          STRAP(0xd1)
574          STRAP(0xd2)
575          STRAP(0xd3)
576          STRAP(0xd4)
577          STRAP(0xd5)
578          STRAP(0xd6)
579          STRAP(0xd7)
580          STRAP(0xd8)
581          STRAP(0xd9)
582          STRAP(0xda)
583          STRAP(0xdb)
584          STRAP(0xdc)
585          STRAP(0xdd)
586          STRAP(0xde)
587          STRAP(0xdf)
588          STRAP(0xe0)
589          STRAP(0xe1)
590          STRAP(0xe2)
591          STRAP(0xe3)
592          STRAP(0xe4)
593          STRAP(0xe5)
594          STRAP(0xe6)
595          STRAP(0xe7)
596          STRAP(0xe8)
597          STRAP(0xe9)
598          STRAP(0xea)
599          STRAP(0xeb)
600          STRAP(0xec)
601          STRAP(0xed)
602          STRAP(0xee)
603          STRAP(0xef)
604          STRAP(0xf0)
605          STRAP(0xf1)
606          STRAP(0xf2)
607          STRAP(0xf3)
608          STRAP(0xf4)
609          STRAP(0xf5)
610          STRAP(0xf6)
611          STRAP(0xf7)
612          STRAP(0xf8)
613          STRAP(0xf9)
614          STRAP(0xfa)
615          STRAP(0xfb)
616          STRAP(0xfc)
617          STRAP(0xfd)
618          STRAP(0xfe)
619          STRAP(0xff)
620#endif
621
622#if defined(SUN4C)
623trapbase_sun4c:
624/* trap 0 is special since we cannot receive it */
625          b dostart; nop; nop; nop      ! 00 = reset (fake)
626          VTRAP(T_TEXTFAULT, memfault_sun4c)      ! 01 = instr. fetch fault
627          TRAP(T_ILLINST)                         ! 02 = illegal instruction
628          TRAP(T_PRIVINST)              ! 03 = privileged instruction
629          TRAP(T_FPDISABLED)            ! 04 = fp instr, but EF bit off in psr
630          WINDOW_OF                     ! 05 = window overflow
631          WINDOW_UF                     ! 06 = window underflow
632          TRAP(T_ALIGN)                           ! 07 = address alignment error
633          VTRAP(T_FPE, fp_exception)    ! 08 = fp exception
634          VTRAP(T_DATAFAULT, memfault_sun4c)      ! 09 = data fetch fault
635          TRAP(T_TAGOF)                           ! 0a = tag overflow
636          UTRAP(0x0b)
637          UTRAP(0x0c)
638          UTRAP(0x0d)
639          UTRAP(0x0e)
640          UTRAP(0x0f)
641          UTRAP(0x10)
642          SOFTINT44C(1, IE_L1)                    ! 11 = level 1 interrupt
643          HARDINT44C(2)                           ! 12 = level 2 interrupt
644          HARDINT44C(3)                           ! 13 = level 3 interrupt
645          SOFTINT44C(4, IE_L4)                    ! 14 = level 4 interrupt
646          HARDINT44C(5)                           ! 15 = level 5 interrupt
647          SOFTINT44C(6, IE_L6)                    ! 16 = level 6 interrupt
648          HARDINT44C(7)                           ! 17 = level 7 interrupt
649          HARDINT44C(8)                           ! 18 = level 8 interrupt
650          HARDINT44C(9)                           ! 19 = level 9 interrupt
651          HARDINT44C(10)                          ! 1a = level 10 interrupt
652          HARDINT44C(11)                          ! 1b = level 11 interrupt
653          ZS_INTERRUPT44C                         ! 1c = level 12 (zs) interrupt
654          HARDINT44C(13)                          ! 1d = level 13 interrupt
655          HARDINT44C(14)                          ! 1e = level 14 interrupt
656          VTRAP(15, nmi_sun4c)                    ! 1f = nonmaskable interrupt
657          UTRAP(0x20)
658          UTRAP(0x21)
659          UTRAP(0x22)
660          UTRAP(0x23)
661          TRAP(T_CPDISABLED)  ! 24 = coprocessor instr, EC bit off in psr
662          UTRAP(0x25)
663          UTRAP(0x26)
664          UTRAP(0x27)
665          TRAP(T_CPEXCEPTION) ! 28 = coprocessor exception
666          UTRAP(0x29)
667          UTRAP(0x2a)
668          UTRAP(0x2b)
669          UTRAP(0x2c)
670          UTRAP(0x2d)
671          UTRAP(0x2e)
672          UTRAP(0x2f)
673          UTRAP(0x30)
674          UTRAP(0x31)
675          UTRAP(0x32)
676          UTRAP(0x33)
677          UTRAP(0x34)
678          UTRAP(0x35)
679          UTRAP(0x36)
680          UTRAP(0x37)
681          UTRAP(0x38)
682          UTRAP(0x39)
683          UTRAP(0x3a)
684          UTRAP(0x3b)
685          UTRAP(0x3c)
686          UTRAP(0x3d)
687          UTRAP(0x3e)
688          UTRAP(0x3f)
689          UTRAP(0x40)
690          UTRAP(0x41)
691          UTRAP(0x42)
692          UTRAP(0x43)
693          UTRAP(0x44)
694          UTRAP(0x45)
695          UTRAP(0x46)
696          UTRAP(0x47)
697          UTRAP(0x48)
698          UTRAP(0x49)
699          UTRAP(0x4a)
700          UTRAP(0x4b)
701          UTRAP(0x4c)
702          UTRAP(0x4d)
703          UTRAP(0x4e)
704          UTRAP(0x4f)
705          UTRAP(0x50)
706          UTRAP(0x51)
707          UTRAP(0x52)
708          UTRAP(0x53)
709          UTRAP(0x54)
710          UTRAP(0x55)
711          UTRAP(0x56)
712          UTRAP(0x57)
713          UTRAP(0x58)
714          UTRAP(0x59)
715          UTRAP(0x5a)
716          UTRAP(0x5b)
717          UTRAP(0x5c)
718          UTRAP(0x5d)
719          UTRAP(0x5e)
720          UTRAP(0x5f)
721          UTRAP(0x60)
722          UTRAP(0x61)
723          UTRAP(0x62)
724          UTRAP(0x63)
725          UTRAP(0x64)
726          UTRAP(0x65)
727          UTRAP(0x66)
728          UTRAP(0x67)
729          UTRAP(0x68)
730          UTRAP(0x69)
731          UTRAP(0x6a)
732          UTRAP(0x6b)
733          UTRAP(0x6c)
734          UTRAP(0x6d)
735          UTRAP(0x6e)
736          UTRAP(0x6f)
737          UTRAP(0x70)
738          UTRAP(0x71)
739          UTRAP(0x72)
740          UTRAP(0x73)
741          UTRAP(0x74)
742          UTRAP(0x75)
743          UTRAP(0x76)
744          UTRAP(0x77)
745          UTRAP(0x78)
746          UTRAP(0x79)
747          UTRAP(0x7a)
748          UTRAP(0x7b)
749          UTRAP(0x7c)
750          UTRAP(0x7d)
751          UTRAP(0x7e)
752          UTRAP(0x7f)
753          SYSCALL                       ! 80 = sun syscall
754          BPT                           ! 81 = pseudo breakpoint instruction
755          TRAP(T_DIV0)                  ! 82 = divide by zero
756          TRAP(T_FLUSHWIN)    ! 83 = flush windows
757          TRAP(T_CLEANWIN)    ! 84 = provide clean windows
758          TRAP(T_RANGECHECK)  ! 85 = ???
759          TRAP(T_FIXALIGN)    ! 86 = fix up unaligned accesses
760          TRAP(T_INTOF)                 ! 87 = integer overflow
761          SYSCALL                       ! 88 = svr4 syscall
762          SYSCALL                       ! 89 = bsd syscall
763          BPT_KGDB_EXEC                 ! 8a = enter kernel gdb on kernel startup
764          STRAP(0x8b)
765          STRAP(0x8c)
766          STRAP(0x8d)
767          STRAP(0x8e)
768          STRAP(0x8f)
769          STRAP(0x90)
770          STRAP(0x91)
771          STRAP(0x92)
772          STRAP(0x93)
773          STRAP(0x94)
774          STRAP(0x95)
775          STRAP(0x96)
776          STRAP(0x97)
777          STRAP(0x98)
778          STRAP(0x99)
779          STRAP(0x9a)
780          STRAP(0x9b)
781          STRAP(0x9c)
782          STRAP(0x9d)
783          STRAP(0x9e)
784          STRAP(0x9f)
785          STRAP(0xa0)
786          STRAP(0xa1)
787          STRAP(0xa2)
788          STRAP(0xa3)
789          STRAP(0xa4)
790          STRAP(0xa5)
791          STRAP(0xa6)
792          STRAP(0xa7)
793          STRAP(0xa8)
794          STRAP(0xa9)
795          STRAP(0xaa)
796          STRAP(0xab)
797          STRAP(0xac)
798          STRAP(0xad)
799          STRAP(0xae)
800          STRAP(0xaf)
801          STRAP(0xb0)
802          STRAP(0xb1)
803          STRAP(0xb2)
804          STRAP(0xb3)
805          STRAP(0xb4)
806          STRAP(0xb5)
807          STRAP(0xb6)
808          STRAP(0xb7)
809          STRAP(0xb8)
810          STRAP(0xb9)
811          STRAP(0xba)
812          STRAP(0xbb)
813          STRAP(0xbc)
814          STRAP(0xbd)
815          STRAP(0xbe)
816          STRAP(0xbf)
817          STRAP(0xc0)
818          STRAP(0xc1)
819          STRAP(0xc2)
820          STRAP(0xc3)
821          STRAP(0xc4)
822          STRAP(0xc5)
823          STRAP(0xc6)
824          STRAP(0xc7)
825          STRAP(0xc8)
826          STRAP(0xc9)
827          STRAP(0xca)
828          STRAP(0xcb)
829          STRAP(0xcc)
830          STRAP(0xcd)
831          STRAP(0xce)
832          STRAP(0xcf)
833          STRAP(0xd0)
834          STRAP(0xd1)
835          STRAP(0xd2)
836          STRAP(0xd3)
837          STRAP(0xd4)
838          STRAP(0xd5)
839          STRAP(0xd6)
840          STRAP(0xd7)
841          STRAP(0xd8)
842          STRAP(0xd9)
843          STRAP(0xda)
844          STRAP(0xdb)
845          STRAP(0xdc)
846          STRAP(0xdd)
847          STRAP(0xde)
848          STRAP(0xdf)
849          STRAP(0xe0)
850          STRAP(0xe1)
851          STRAP(0xe2)
852          STRAP(0xe3)
853          STRAP(0xe4)
854          STRAP(0xe5)
855          STRAP(0xe6)
856          STRAP(0xe7)
857          STRAP(0xe8)
858          STRAP(0xe9)
859          STRAP(0xea)
860          STRAP(0xeb)
861          STRAP(0xec)
862          STRAP(0xed)
863          STRAP(0xee)
864          STRAP(0xef)
865          STRAP(0xf0)
866          STRAP(0xf1)
867          STRAP(0xf2)
868          STRAP(0xf3)
869          STRAP(0xf4)
870          STRAP(0xf5)
871          STRAP(0xf6)
872          STRAP(0xf7)
873          STRAP(0xf8)
874          STRAP(0xf9)
875          STRAP(0xfa)
876          STRAP(0xfb)
877          STRAP(0xfc)
878          STRAP(0xfd)
879          STRAP(0xfe)
880          STRAP(0xff)
881#endif
882
883#if defined(SUN4M)
884trapbase_sun4m:
885/* trap 0 is special since we cannot receive it */
886          b dostart; nop; nop; nop      ! 00 = reset (fake)
887          VTRAP(T_TEXTFAULT, memfault_sun4m)      ! 01 = instr. fetch fault
888          VTRAP(T_ILLINST, illinst4m)   ! 02 = illegal instruction
889          TRAP(T_PRIVINST)              ! 03 = privileged instruction
890          TRAP(T_FPDISABLED)            ! 04 = fp instr, but EF bit off in psr
891          WINDOW_OF                     ! 05 = window overflow
892          WINDOW_UF                     ! 06 = window underflow
893          TRAP(T_ALIGN)                           ! 07 = address alignment error
894          VTRAP(T_FPE, fp_exception)    ! 08 = fp exception
895          VTRAP(T_DATAFAULT, memfault_sun4m)      ! 09 = data fetch fault
896          TRAP(T_TAGOF)                           ! 0a = tag overflow
897          UTRAP(0x0b)
898          UTRAP(0x0c)
899          UTRAP(0x0d)
900          UTRAP(0x0e)
901          UTRAP(0x0f)
902          UTRAP(0x10)
903          HARDINT4M(1)                            ! 11 = level 1 interrupt
904          HARDINT4M(2)                            ! 12 = level 2 interrupt
905          HARDINT4M(3)                            ! 13 = level 3 interrupt
906          HARDINT4M(4)                            ! 14 = level 4 interrupt
907          HARDINT4M(5)                            ! 15 = level 5 interrupt
908          HARDINT4M(6)                            ! 16 = level 6 interrupt
909          HARDINT4M(7)                            ! 17 = level 7 interrupt
910          HARDINT4M(8)                            ! 18 = level 8 interrupt
911          HARDINT4M(9)                            ! 19 = level 9 interrupt
912          HARDINT4M(10)                           ! 1a = level 10 interrupt
913          HARDINT4M(11)                           ! 1b = level 11 interrupt
914          ZS_INTERRUPT4M                          ! 1c = level 12 (zs) interrupt
915          HARDINT4M(13)                           ! 1d = level 13 interrupt
916          HARDINT4M(14)                           ! 1e = level 14 interrupt
917          VTRAP(15, nmi_sun4m)                    ! 1f = nonmaskable interrupt
918          UTRAP(0x20)
919          VTRAP(T_TEXTERROR, memfault_sun4m)      ! 21 = instr. fetch error
920          UTRAP(0x22)
921          UTRAP(0x23)
922          TRAP(T_CPDISABLED)  ! 24 = coprocessor instr, EC bit off in psr
923          UTRAP(0x25)
924          UTRAP(0x26)
925          UTRAP(0x27)
926          TRAP(T_CPEXCEPTION) ! 28 = coprocessor exception
927          VTRAP(T_DATAERROR, memfault_sun4m)      ! 29 = data fetch error
928          UTRAP(0x2a)
929          VTRAP(T_STOREBUFFAULT, memfault_sun4m) ! 2b = SuperSPARC store buffer fault
930          UTRAP(0x2c)
931          UTRAP(0x2d)
932          UTRAP(0x2e)
933          UTRAP(0x2f)
934          UTRAP(0x30)
935          UTRAP(0x31)
936          UTRAP(0x32)
937          UTRAP(0x33)
938          UTRAP(0x34)
939          UTRAP(0x35)
940          UTRAP(0x36)
941          UTRAP(0x37)
942          UTRAP(0x38)
943          UTRAP(0x39)
944          UTRAP(0x3a)
945          UTRAP(0x3b)
946          UTRAP(0x3c)
947          UTRAP(0x3d)
948          UTRAP(0x3e)
949          UTRAP(0x3f)
950          UTRAP(0x40)
951          UTRAP(0x41)
952          UTRAP(0x42)
953          UTRAP(0x43)
954          UTRAP(0x44)
955          UTRAP(0x45)
956          UTRAP(0x46)
957          UTRAP(0x47)
958          UTRAP(0x48)
959          UTRAP(0x49)
960          UTRAP(0x4a)
961          UTRAP(0x4b)
962          UTRAP(0x4c)
963          UTRAP(0x4d)
964          UTRAP(0x4e)
965          UTRAP(0x4f)
966          UTRAP(0x50)
967          UTRAP(0x51)
968          UTRAP(0x52)
969          UTRAP(0x53)
970          UTRAP(0x54)
971          UTRAP(0x55)
972          UTRAP(0x56)
973          UTRAP(0x57)
974          UTRAP(0x58)
975          UTRAP(0x59)
976          UTRAP(0x5a)
977          UTRAP(0x5b)
978          UTRAP(0x5c)
979          UTRAP(0x5d)
980          UTRAP(0x5e)
981          UTRAP(0x5f)
982          UTRAP(0x60)
983          UTRAP(0x61)
984          UTRAP(0x62)
985          UTRAP(0x63)
986          UTRAP(0x64)
987          UTRAP(0x65)
988          UTRAP(0x66)
989          UTRAP(0x67)
990          UTRAP(0x68)
991          UTRAP(0x69)
992          UTRAP(0x6a)
993          UTRAP(0x6b)
994          UTRAP(0x6c)
995          UTRAP(0x6d)
996          UTRAP(0x6e)
997          UTRAP(0x6f)
998          UTRAP(0x70)
999          UTRAP(0x71)
1000          UTRAP(0x72)
1001          UTRAP(0x73)
1002          UTRAP(0x74)
1003          UTRAP(0x75)
1004          UTRAP(0x76)
1005          UTRAP(0x77)
1006          UTRAP(0x78)
1007          UTRAP(0x79)
1008          UTRAP(0x7a)
1009          UTRAP(0x7b)
1010          UTRAP(0x7c)
1011          UTRAP(0x7d)
1012          UTRAP(0x7e)
1013          UTRAP(0x7f)
1014          SYSCALL                       ! 80 = sun syscall
1015          BPT                           ! 81 = pseudo breakpoint instruction
1016          TRAP(T_DIV0)                  ! 82 = divide by zero
1017          TRAP(T_FLUSHWIN)    ! 83 = flush windows
1018          TRAP(T_CLEANWIN)    ! 84 = provide clean windows
1019          TRAP(T_RANGECHECK)  ! 85 = ???
1020          TRAP(T_FIXALIGN)    ! 86 = fix up unaligned accesses
1021          TRAP(T_INTOF)                 ! 87 = integer overflow
1022          SYSCALL                       ! 88 = svr4 syscall
1023          SYSCALL                       ! 89 = bsd syscall
1024          BPT_KGDB_EXEC                 ! 8a = enter kernel gdb on kernel startup
1025          TRAP(T_DBPAUSE)               ! 8b = hold CPU for kernel debugger
1026          STRAP(0x8c)
1027          STRAP(0x8d)
1028          STRAP(0x8e)
1029          STRAP(0x8f)
1030          STRAP(0x90)
1031          STRAP(0x91)
1032          STRAP(0x92)
1033          STRAP(0x93)
1034          STRAP(0x94)
1035          STRAP(0x95)
1036          STRAP(0x96)
1037          STRAP(0x97)
1038          STRAP(0x98)
1039          STRAP(0x99)
1040          STRAP(0x9a)
1041          STRAP(0x9b)
1042          STRAP(0x9c)
1043          STRAP(0x9d)
1044          STRAP(0x9e)
1045          STRAP(0x9f)
1046          STRAP(0xa0)
1047          STRAP(0xa1)
1048          STRAP(0xa2)
1049          STRAP(0xa3)
1050          STRAP(0xa4)
1051          STRAP(0xa5)
1052          STRAP(0xa6)
1053          STRAP(0xa7)
1054          STRAP(0xa8)
1055          STRAP(0xa9)
1056          STRAP(0xaa)
1057          STRAP(0xab)
1058          STRAP(0xac)
1059          STRAP(0xad)
1060          STRAP(0xae)
1061          STRAP(0xaf)
1062          STRAP(0xb0)
1063          STRAP(0xb1)
1064          STRAP(0xb2)
1065          STRAP(0xb3)
1066          STRAP(0xb4)
1067          STRAP(0xb5)
1068          STRAP(0xb6)
1069          STRAP(0xb7)
1070          STRAP(0xb8)
1071          STRAP(0xb9)
1072          STRAP(0xba)
1073          STRAP(0xbb)
1074          STRAP(0xbc)
1075          STRAP(0xbd)
1076          STRAP(0xbe)
1077          STRAP(0xbf)
1078          STRAP(0xc0)
1079          STRAP(0xc1)
1080          STRAP(0xc2)
1081          STRAP(0xc3)
1082          STRAP(0xc4)
1083          STRAP(0xc5)
1084          STRAP(0xc6)
1085          STRAP(0xc7)
1086          STRAP(0xc8)
1087          STRAP(0xc9)
1088          STRAP(0xca)
1089          STRAP(0xcb)
1090          STRAP(0xcc)
1091          STRAP(0xcd)
1092          STRAP(0xce)
1093          STRAP(0xcf)
1094          STRAP(0xd0)
1095          STRAP(0xd1)
1096          STRAP(0xd2)
1097          STRAP(0xd3)
1098          STRAP(0xd4)
1099          STRAP(0xd5)
1100          STRAP(0xd6)
1101          STRAP(0xd7)
1102          STRAP(0xd8)
1103          STRAP(0xd9)
1104          STRAP(0xda)
1105          STRAP(0xdb)
1106          STRAP(0xdc)
1107          STRAP(0xdd)
1108          STRAP(0xde)
1109          STRAP(0xdf)
1110          STRAP(0xe0)
1111          STRAP(0xe1)
1112          STRAP(0xe2)
1113          STRAP(0xe3)
1114          STRAP(0xe4)
1115          STRAP(0xe5)
1116          STRAP(0xe6)
1117          STRAP(0xe7)
1118          STRAP(0xe8)
1119          STRAP(0xe9)
1120          STRAP(0xea)
1121          STRAP(0xeb)
1122          STRAP(0xec)
1123          STRAP(0xed)
1124          STRAP(0xee)
1125          STRAP(0xef)
1126          STRAP(0xf0)
1127          STRAP(0xf1)
1128          STRAP(0xf2)
1129          STRAP(0xf3)
1130          STRAP(0xf4)
1131          STRAP(0xf5)
1132          STRAP(0xf6)
1133          STRAP(0xf7)
1134          STRAP(0xf8)
1135          STRAP(0xf9)
1136          STRAP(0xfa)
1137          STRAP(0xfb)
1138          STRAP(0xfc)
1139          STRAP(0xfd)
1140          STRAP(0xfe)
1141          STRAP(0xff)
1142#endif
1143
1144/*
1145 * Pad the trap table to max page size.
1146 * Trap table size is 0x100 * 4instr * 4byte/instr = 4096 bytes;
1147 * need to .skip 4096 to pad to page size iff. the number of trap tables
1148 * defined above is odd.
1149 */
1150#if (defined(SUN4) + defined(SUN4C) + defined(SUN4M)) % 2 == 1
1151          .skip     4096
1152#endif
1153
1154/* redzones don't work currently in multi-processor mode */
1155#if defined(DEBUG) && !defined(MULTIPROCESSOR)
1156/*
1157 * A hardware red zone is impossible.  We simulate one in software by
1158 * keeping a `red zone' pointer; if %sp becomes less than this, we panic.
1159 * This is expensive and is only enabled when debugging.
1160 */
1161
1162/* `redzone' is located in the per-CPU information structure */
1163_redzone = CPUINFO_VA + CPUINFO_REDZONE
1164          .data
1165#define   REDSTACK 2048                 /* size of `panic: stack overflow' region */
1166_redstack:
1167          .skip     REDSTACK
1168          .text
1169Lpanic_red:
1170          .asciz    "stack overflow"
1171          _ALIGN
1172
1173          /* set stack pointer redzone to base+minstack; alters base */
1174#define   SET_SP_REDZONE(base, tmp) \
1175          add       base, REDSIZE, base; \
1176          sethi     %hi(_redzone), tmp; \
1177          st        base, [tmp + %lo(_redzone)]
1178
1179          /* variant with a constant */
1180#define   SET_SP_REDZONE_CONST(const, tmp1, tmp2) \
1181          set       (const) + REDSIZE, tmp1; \
1182          sethi     %hi(_redzone), tmp2; \
1183          st        tmp1, [tmp2 + %lo(_redzone)]
1184
1185          /* variant with a variable & offset */
1186#define   SET_SP_REDZONE_VAR(var, offset, tmp1, tmp2) \
1187          sethi     %hi(var), tmp1; \
1188          ld        [tmp1 + %lo(var)], tmp1; \
1189          sethi     %hi(offset), tmp2; \
1190          add       tmp1, tmp2, tmp1; \
1191          SET_SP_REDZONE(tmp1, tmp2)
1192
1193          /* check stack pointer against redzone (uses two temps) */
1194#define   CHECK_SP_REDZONE(t1, t2) \
1195          sethi     %hi(_redzone), t1; \
1196          ld        [t1 + %lo(_redzone)], t2; \
1197          cmp       %sp, t2;  /* if sp >= t2, not in red zone */ \
1198          bgeu      7f; nop;  /* and can continue normally */ \
1199          /* move to panic stack */ \
1200          st        %g0, [t1 + %lo(_redzone)]; \
1201          set       _redstack + REDSTACK - 96, %sp; \
1202          /* prevent panic() from lowering ipl */ \
1203          sethi     %hi(_C_LABEL(panicstr)), t1; \
1204          set       Lpanic_red, t2; \
1205          st        t2, [t1 + %lo(_C_LABEL(panicstr))]; \
1206          rd        %psr, t1;           /* t1 = splhigh() */ \
1207          or        t1, PSR_PIL, t2; \
1208          wr        t2, 0, %psr; \
1209          wr        t2, PSR_ET, %psr;   /* turn on traps */ \
1210          nop; nop; nop; \
1211          save      %sp, -CCFSZ, %sp;   /* preserve current window */ \
1212          sethi     %hi(Lpanic_red), %o0; \
1213          call      _C_LABEL(panic); or %o0, %lo(Lpanic_red), %o0; \
12147:
1215
1216#else
1217
1218#define   SET_SP_REDZONE(base, tmp)
1219#define   SET_SP_REDZONE_CONST(const, t1, t2)
1220#define   SET_SP_REDZONE_VAR(var, offset, t1, t2)
1221#define   CHECK_SP_REDZONE(t1, t2)
1222#endif /* DEBUG */
1223
1224/*
1225 * The window code must verify user stack addresses before using them.
1226 * A user stack pointer is invalid if:
1227 *        - it is not on an 8 byte boundary;
1228 *        - its pages (a register window, being 64 bytes, can occupy
1229 *          two pages) are not readable or writable.
1230 * We define three separate macros here for testing user stack addresses.
1231 *
1232 * PTE_OF_ADDR locates a PTE, branching to a `bad address'
1233 *        handler if the stack pointer points into the hole in the
1234 *        address space (i.e., top 3 bits are not either all 1 or all 0);
1235 * CMP_PTE_USER_READ compares the located PTE against `user read' mode;
1236 * CMP_PTE_USER_WRITE compares the located PTE against `user write' mode.
1237 * The compares give `equal' if read or write is OK.
1238 *
1239 * Note that the user stack pointer usually points into high addresses
1240 * (top 3 bits all 1), so that is what we check first.
1241 *
1242 * The code below also assumes that PTE_OF_ADDR is safe in a delay
1243 * slot; it is, at it merely sets its `pte' register to a temporary value.
1244 */
1245#if defined(SUN4) || defined(SUN4C)
1246          /* input: addr, output: pte; aux: bad address label */
1247#define   PTE_OF_ADDR4_4C(addr, pte, bad, page_offset) \
1248          sra       addr, PG_VSHIFT, pte; \
1249          cmp       pte, -1; \
1250          be,a      1f; andn addr, page_offset, pte; \
1251          tst       pte; \
1252          bne       bad; .empty; \
1253          andn      addr, page_offset, pte; \
12541:
1255
1256          /* input: pte; output: condition codes */
1257#define   CMP_PTE_USER_READ4_4C(pte) \
1258          lda       [pte] ASI_PTE, pte; \
1259          srl       pte, PG_PROTSHIFT, pte; \
1260          andn      pte, (PG_W >> PG_PROTSHIFT), pte; \
1261          cmp       pte, PG_PROTUREAD
1262
1263          /* input: pte; output: condition codes */
1264#define   CMP_PTE_USER_WRITE4_4C(pte) \
1265          lda       [pte] ASI_PTE, pte; \
1266          srl       pte, PG_PROTSHIFT, pte; \
1267          cmp       pte, PG_PROTUWRITE
1268#endif
1269
1270/*
1271 * The Sun4M does not have the memory hole that the 4C does. Thus all
1272 * we need to do here is clear the page offset from addr.
1273 */
1274#if defined(SUN4M)
1275#define   PTE_OF_ADDR4M(addr, pte, bad, page_offset) \
1276          andn      addr, page_offset, pte
1277
1278/*
1279 * After obtaining the PTE through ASI_SRMMUFP, we read the Sync Fault
1280 * Status register. This is necessary on Hypersparcs which stores and
1281 * locks the fault address and status registers if the translation
1282 * fails (thanks to Chris Torek for finding this quirk).
1283 */
1284#define CMP_PTE_USER_READ4M(pte, tmp) \
1285          /*or      pte, ASI_SRMMUFP_L3, pte; -- ASI_SRMMUFP_L3 == 0 */ \
1286          lda       [pte] ASI_SRMMUFP, pte; \
1287          set       SRMMU_SFSR, tmp; \
1288          lda       [tmp] ASI_SRMMU, %g0; \
1289          and       pte, SRMMU_TETYPE, tmp; \
1290          /* Check for valid pte */ \
1291          cmp       tmp, SRMMU_TEPTE; \
1292          bnz       8f; \
1293          and       pte, SRMMU_PROT_MASK, pte; \
1294          /* check for one of: R_R, RW_RW, RX_RX and RWX_RWX */ \
1295          cmp       pte, PPROT_X_X; \
1296          bcs,a     8f; \
1297           /* Now we have carry set if OK; turn it into Z bit */ \
1298           subxcc   %g0, -1, %g0; \
1299          /* One more case to check: R_RW */ \
1300          cmp       pte, PPROT_R_RW; \
13018:
1302
1303
1304/* note: PTE bit 4 set implies no user writes */
1305#define CMP_PTE_USER_WRITE4M(pte, tmp) \
1306          or        pte, ASI_SRMMUFP_L3, pte; \
1307          lda       [pte] ASI_SRMMUFP, pte; \
1308          set       SRMMU_SFSR, tmp; \
1309          lda       [tmp] ASI_SRMMU, %g0; \
1310          and       pte, (SRMMU_TETYPE | 0x14), pte; \
1311          cmp       pte, (SRMMU_TEPTE | PPROT_WRITE)
1312#endif /* 4m */
1313
1314#if defined(SUN4M) && !(defined(SUN4C) || defined(SUN4))
1315
1316#define PTE_OF_ADDR(addr, pte, bad, page_offset, label) \
1317          PTE_OF_ADDR4M(addr, pte, bad, page_offset)
1318#define CMP_PTE_USER_WRITE(pte, tmp, label)       CMP_PTE_USER_WRITE4M(pte,tmp)
1319#define CMP_PTE_USER_READ(pte, tmp, label)        CMP_PTE_USER_READ4M(pte,tmp)
1320
1321#elif (defined(SUN4C) || defined(SUN4)) && !defined(SUN4M)
1322
1323#define PTE_OF_ADDR(addr, pte, bad, page_offset,label) \
1324          PTE_OF_ADDR4_4C(addr, pte, bad, page_offset)
1325#define CMP_PTE_USER_WRITE(pte, tmp, label)       CMP_PTE_USER_WRITE4_4C(pte)
1326#define CMP_PTE_USER_READ(pte, tmp, label)        CMP_PTE_USER_READ4_4C(pte)
1327
1328#else /* both defined, ugh */
1329
1330#define   PTE_OF_ADDR(addr, pte, bad, page_offset, label) \
1331label:    b,a       2f; \
1332          PTE_OF_ADDR4M(addr, pte, bad, page_offset); \
1333          b,a       3f; \
13342: \
1335          PTE_OF_ADDR4_4C(addr, pte, bad, page_offset); \
13363:
1337
1338#define CMP_PTE_USER_READ(pte, tmp, label) \
1339label:    b,a       1f; \
1340          CMP_PTE_USER_READ4M(pte,tmp); \
1341          b,a       2f; \
13421: \
1343          CMP_PTE_USER_READ4_4C(pte); \
13442:
1345
1346#define CMP_PTE_USER_WRITE(pte, tmp, label) \
1347label:    b,a       1f; \
1348          CMP_PTE_USER_WRITE4M(pte,tmp); \
1349          b,a       2f; \
13501: \
1351          CMP_PTE_USER_WRITE4_4C(pte); \
13522:
1353#endif
1354
1355
1356/*
1357 * The calculations in PTE_OF_ADDR and CMP_PTE_USER_* are rather slow:
1358 * in particular, according to Gordon Irlam of the University of Adelaide
1359 * in Australia, these consume at least 18 cycles on an SS1 and 37 on an
1360 * SS2.  Hence, we try to avoid them in the common case.
1361 *
1362 * A chunk of 64 bytes is on a single page if and only if:
1363 *
1364 *        ((base + 64 - 1) & ~(NBPG-1)) == (base & ~(NBPG-1))
1365 *
1366 * Equivalently (and faster to test), the low order bits (base & 4095) must
1367 * be small enough so that the sum (base + 63) does not carry out into the
1368 * upper page-address bits, i.e.,
1369 *
1370 *        (base & (NBPG-1)) < (NBPG - 63)
1371 *
1372 * so we allow testing that here.  This macro is also assumed to be safe
1373 * in a delay slot (modulo overwriting its temporary).
1374 */
1375#define   SLT_IF_1PAGE_RW(addr, tmp, page_offset) \
1376          and       addr, page_offset, tmp; \
1377          sub       page_offset, 62, page_offset; \
1378          cmp       tmp, page_offset
1379
1380/*
1381 * Every trap that enables traps must set up stack space.
1382 * If the trap is from user mode, this involves switching to the kernel
1383 * stack for the current process, and we must also set cpcb->pcb_uw
1384 * so that the window overflow handler can tell user windows from kernel
1385 * windows.
1386 *
1387 * The number of user windows is:
1388 *
1389 *        cpcb->pcb_uw = (cpcb->pcb_wim - 1 - CWP) % nwindows
1390 *
1391 * (where pcb_wim = log2(current %wim) and CWP = low 5 bits of %psr).
1392 * We compute this expression by table lookup in uwtab[CWP - pcb_wim],
1393 * which has been set up as:
1394 *
1395 *        for i in [-nwin+1 .. nwin-1]
1396 *                  uwtab[i] = (nwin - 1 - i) % nwin;
1397 *
1398 * (If you do not believe this works, try it for yourself.)
1399 *
1400 * We also keep one or two more tables:
1401 *
1402 *        for i in 0..nwin-1
1403 *                  wmask[i] = 1 << ((i + 1) % nwindows);
1404 *
1405 * wmask[CWP] tells whether a `rett' would return into the invalid window.
1406 */
1407          .data
1408          .skip     32                            ! alignment byte & negative indices
1409uwtab:    .skip     32                            ! u_char uwtab[-31..31];
1410wmask:    .skip     32                            ! u_char wmask[0..31];
1411
1412          .text
1413/*
1414 * Things begin to grow uglier....
1415 *
1416 * Each trap handler may (always) be running in the trap window.
1417 * If this is the case, it cannot enable further traps until it writes
1418 * the register windows into the stack (or, if the stack is no good,
1419 * the current pcb).
1420 *
1421 * ASSUMPTIONS: TRAP_SETUP() is called with:
1422 *        %l0 = %psr
1423 *        %l1 = return pc
1424 *        %l2 = return npc
1425 *        %l3 = (some value that must not be altered)
1426 * which means we have 4 registers to work with.
1427 *
1428 * The `stackspace' argument is the number of stack bytes to allocate
1429 * for register-saving, and must be at least -64 (and typically more,
1430 * for global registers and %y).
1431 *
1432 * Trapframes should use -CCFSZ-80.  (80 = sizeof(struct trapframe);
1433 * see trap.h.  This basically means EVERYONE.  Interrupt frames could
1434 * get away with less, but currently do not.)
1435 *
1436 * The basic outline here is:
1437 *
1438 *        if (trap came from kernel mode) {
1439 *                  if (we are in the trap window)
1440 *                            save it away;
1441 *                  %sp = %fp - stackspace;
1442 *        } else {
1443 *                  compute the number of user windows;
1444 *                  if (we are in the trap window)
1445 *                            save it away;
1446 *                  %sp = (top of kernel stack) - stackspace;
1447 *        }
1448 *
1449 * Again, the number of user windows is:
1450 *
1451 *        cpcb->pcb_uw = (cpcb->pcb_wim - 1 - CWP) % nwindows
1452 *
1453 * (where pcb_wim = log2(current %wim) and CWP is the low 5 bits of %psr),
1454 * and this is computed as `uwtab[CWP - pcb_wim]'.
1455 *
1456 * NOTE: if you change this code, you will have to look carefully
1457 * at the window overflow and underflow handlers and make sure they
1458 * have similar changes made as needed.
1459 */
1460#define   CALL_CLEAN_TRAP_WINDOW \
1461          sethi     %hi(clean_trap_window), %l7; \
1462          jmpl      %l7 + %lo(clean_trap_window), %l4; \
1463           mov      %g7, %l7  /* save %g7 in %l7 for clean_trap_window */
1464
1465#define   TRAP_SETUP(stackspace) \
1466          TRAP_TRACE(%l3,%l5); \
1467          rd        %wim, %l4; \
1468          mov       1, %l5; \
1469          sll       %l5, %l0, %l5; \
1470          btst      PSR_PS, %l0; \
1471          bz        1f; \
1472           btst     %l5, %l4; \
1473          /* came from kernel mode; cond codes indicate trap window */ \
1474          bz,a      3f; \
1475           add      %fp, stackspace, %sp;         /* want to just set %sp */ \
1476          CALL_CLEAN_TRAP_WINDOW;                 /* but maybe need to clean first */ \
1477          b         3f; \
1478           add      %fp, stackspace, %sp; \
14791: \
1480          /* came from user mode: compute pcb_nw */ \
1481          sethi     %hi(cpcb), %l6; \
1482          ld        [%l6 + %lo(cpcb)], %l6; \
1483          ld        [%l6 + PCB_WIM], %l5; \
1484          and       %l0, 31, %l4; \
1485          sub       %l4, %l5, %l5; \
1486          set       uwtab, %l4; \
1487          ldub      [%l4 + %l5], %l5; \
1488          st        %l5, [%l6 + PCB_UW]; \
1489          /* cond codes still indicate whether in trap window */ \
1490          bz,a      2f; \
1491           sethi    %hi(USPACE+(stackspace)), %l5; \
1492          /* yes, in trap window; must clean it */ \
1493          CALL_CLEAN_TRAP_WINDOW; \
1494          sethi     %hi(cpcb), %l6; \
1495          ld        [%l6 + %lo(cpcb)], %l6; \
1496          sethi     %hi(USPACE+(stackspace)), %l5; \
14972: \
1498          /* trap window is (now) clean: set %sp */ \
1499          or        %l5, %lo(USPACE+(stackspace)), %l5; \
1500          add       %l6, %l5, %sp; \
1501          SET_SP_REDZONE(%l6, %l5); \
15023: \
1503          CHECK_SP_REDZONE(%l6, %l5)
1504
1505/*
1506 * Interrupt setup is almost exactly like trap setup, but we need to
1507 * go to the interrupt stack if (a) we came from user mode or (b) we
1508 * came from kernel mode on the kernel stack.
1509 */
1510#if defined(MULTIPROCESSOR)
1511/*
1512 * SMP kernels: read `eintstack' from cpuinfo structure. Since the
1513 * location of the interrupt stack is not known in advance, we need
1514 * to check the current %fp against both ends of the stack space.
1515 */
1516#define   INTR_SETUP(stackspace) \
1517          TRAP_TRACE(%l3,%l5); \
1518          rd        %wim, %l4; \
1519          mov       1, %l5; \
1520          sll       %l5, %l0, %l5; \
1521          btst      PSR_PS, %l0; \
1522          bz        1f; \
1523           btst     %l5, %l4; \
1524          /* came from kernel mode; cond codes still indicate trap window */ \
1525          bz,a      0f; \
1526           sethi    %hi(_EINTSTACKP), %l7; \
1527          CALL_CLEAN_TRAP_WINDOW; \
1528          sethi     %hi(_EINTSTACKP), %l7; \
15290:        /* now if not intstack > %fp >= eintstack, we were on the kernel stack */ \
1530          ld        [%l7 + %lo(_EINTSTACKP)], %l7; \
1531          cmp       %fp, %l7; \
1532          bge,a     3f;                           /* %fp >= eintstack */ \
1533           add      %l7, stackspace, %sp;         /* so switch to intstack */ \
1534          sethi     %hi(INT_STACK_SIZE), %l6; \
1535          sub       %l7, %l6, %l6; \
1536          cmp       %fp, %l6; \
1537          blu,a     3f;                           /* %fp < intstack */ \
1538           add      %l7, stackspace, %sp;         /* so switch to intstack */ \
1539          b         4f; \
1540           add      %fp, stackspace, %sp;         /* else stay on intstack */ \
15411: \
1542          /* came from user mode: compute pcb_nw */ \
1543          sethi     %hi(cpcb), %l6; \
1544          ld        [%l6 + %lo(cpcb)], %l6; \
1545          ld        [%l6 + PCB_WIM], %l5; \
1546          and       %l0, 31, %l4; \
1547          sub       %l4, %l5, %l5; \
1548          set       uwtab, %l4; \
1549          ldub      [%l4 + %l5], %l5; \
1550          st        %l5, [%l6 + PCB_UW]; \
1551          /* cond codes still indicate whether in trap window */ \
1552          bz,a      2f; \
1553           sethi    %hi(_EINTSTACKP), %l7; \
1554          /* yes, in trap window; must save regs */ \
1555          CALL_CLEAN_TRAP_WINDOW; \
1556          sethi     %hi(_EINTSTACKP), %l7; \
15572: \
1558          ld        [%l7 + %lo(_EINTSTACKP)], %l7; \
1559          add       %l7, stackspace, %sp; \
15603: \
1561          SET_SP_REDZONE_VAR(_EINTSTACKP, -INT_STACK_SIZE, %l6, %l5); \
15624: \
1563          CHECK_SP_REDZONE(%l6, %l5)
1564
1565#else /* MULTIPROCESSOR */
1566
1567#define   INTR_SETUP(stackspace) \
1568          TRAP_TRACE(%l3,%l5); \
1569          rd        %wim, %l4; \
1570          mov       1, %l5; \
1571          sll       %l5, %l0, %l5; \
1572          btst      PSR_PS, %l0; \
1573          bz        1f; \
1574           btst     %l5, %l4; \
1575          /* came from kernel mode; cond codes still indicate trap window */ \
1576          bz,a      0f; \
1577           sethi    %hi(_C_LABEL(eintstack)), %l7; \
1578          CALL_CLEAN_TRAP_WINDOW; \
1579          sethi     %hi(_C_LABEL(eintstack)), %l7; \
15800:        /* now if %fp >= eintstack, we were on the kernel stack */ \
1581          cmp       %fp, %l7; \
1582          bge,a     3f; \
1583           add      %l7, stackspace, %sp;         /* so switch to intstack */ \
1584          b         4f; \
1585           add      %fp, stackspace, %sp;         /* else stay on intstack */ \
15861: \
1587          /* came from user mode: compute pcb_nw */ \
1588          sethi     %hi(cpcb), %l6; \
1589          ld        [%l6 + %lo(cpcb)], %l6; \
1590          ld        [%l6 + PCB_WIM], %l5; \
1591          and       %l0, 31, %l4; \
1592          sub       %l4, %l5, %l5; \
1593          set       uwtab, %l4; \
1594          ldub      [%l4 + %l5], %l5; \
1595          st        %l5, [%l6 + PCB_UW]; \
1596          /* cond codes still indicate whether in trap window */ \
1597          bz,a      2f; \
1598           sethi    %hi(_C_LABEL(eintstack)), %l7; \
1599          /* yes, in trap window; must save regs */ \
1600          CALL_CLEAN_TRAP_WINDOW; \
1601          sethi     %hi(_C_LABEL(eintstack)), %l7; \
16022: \
1603          add       %l7, stackspace, %sp; \
16043: \
1605          SET_SP_REDZONE_CONST(_C_LABEL(intstack), %l6, %l5); \
16064: \
1607          CHECK_SP_REDZONE(%l6, %l5)
1608#endif /* MULTIPROCESSOR */
1609
1610/*
1611 * Handler for making the trap window shiny clean.
1612 *
1613 * On entry:
1614 *        cpcb->pcb_nw = number of user windows
1615 *        %l0 = %psr
1616 *        %l1 must not be clobbered
1617 *        %l2 must not be clobbered
1618 *        %l3 must not be clobbered
1619 *        %l4 = address for `return'
1620 *        %l7 = saved %g7 (we put this in a delay slot above, to save work)
1621 *
1622 * On return:
1623 *        %wim has changed, along with cpcb->pcb_wim
1624 *        %g7 has been restored
1625 *
1626 * Normally, we push only one window.
1627 */
1628clean_trap_window:
1629          mov       %g5, %l5            ! save %g5
1630          mov       %g6, %l6            ! ... and %g6
1631/*        mov       %g7, %l7            ! ... and %g7 (already done for us) */
1632          sethi     %hi(cpcb), %g6                ! get current pcb
1633          ld        [%g6 + %lo(cpcb)], %g6
1634
1635          /* Figure out whether it is a user window (cpcb->pcb_uw > 0). */
1636          ld        [%g6 + PCB_UW], %g7
1637          deccc     %g7
1638          bge       ctw_user
1639           save     %g0, %g0, %g0                 ! in any case, enter window to save
1640
1641          /* The window to be pushed is a kernel window. */
1642          std       %l0, [%sp + (0*8)]
1643ctw_merge:
1644          std       %l2, [%sp + (1*8)]
1645          std       %l4, [%sp + (2*8)]
1646          std       %l6, [%sp + (3*8)]
1647          std       %i0, [%sp + (4*8)]
1648          std       %i2, [%sp + (5*8)]
1649          std       %i4, [%sp + (6*8)]
1650          std       %i6, [%sp + (7*8)]
1651
1652          /* Set up new window invalid mask, and update cpcb->pcb_wim. */
1653          rd        %psr, %g7           ! g7 = (junk << 5) + new_cwp
1654          mov       1, %g5                        ! g5 = 1 << new_cwp;
1655          sll       %g5, %g7, %g5
1656          wr        %g5, 0, %wim                  ! setwim(g5);
1657          and       %g7, 31, %g7                  ! cpcb->pcb_wim = g7 & 31;
1658          sethi     %hi(cpcb), %g6                ! re-get current pcb
1659          ld        [%g6 + %lo(cpcb)], %g6
1660          st        %g7, [%g6 + PCB_WIM]
1661          nop
1662          restore                                 ! back to trap window
1663
1664          mov       %l5, %g5            ! restore g5
1665          mov       %l6, %g6            ! ... and g6
1666          jmp       %l4 + 8                       ! return to caller
1667           mov      %l7, %g7            ! ... and g7
1668          /* NOTREACHED */
1669
1670ctw_user:
1671          /*
1672           * The window to be pushed is a user window.
1673           * We must verify the stack pointer (alignment & permissions).
1674           * See comments above definition of PTE_OF_ADDR.
1675           */
1676          st        %g7, [%g6 + PCB_UW] ! cpcb->pcb_uw--;
1677          btst      7, %sp                        ! if not aligned,
1678          bne       ctw_invalid                   ! choke on it
1679           .empty
1680
1681          sethi     %hi(_C_LABEL(pgofset)), %g6   ! trash %g6=curpcb
1682          ld        [%g6 + %lo(_C_LABEL(pgofset))], %g6
1683          PTE_OF_ADDR(%sp, %g7, ctw_invalid, %g6, NOP_ON_4M_1)
1684          CMP_PTE_USER_WRITE(%g7, %g5, NOP_ON_4M_2) ! likewise if not writable
1685          bne       ctw_invalid
1686           .empty
1687          /* Note side-effect of SLT_IF_1PAGE_RW: decrements %g6 by 62 */
1688          SLT_IF_1PAGE_RW(%sp, %g7, %g6)
1689          bl,a      ctw_merge           ! all ok if only 1
1690           std      %l0, [%sp]
1691          add       %sp, 7*8, %g5                 ! check last addr too
1692          add       %g6, 62, %g6                  /* restore %g6 to `pgofset' */
1693          PTE_OF_ADDR(%g5, %g7, ctw_invalid, %g6, NOP_ON_4M_3)
1694          CMP_PTE_USER_WRITE(%g7, %g6, NOP_ON_4M_4)
1695          be,a      ctw_merge           ! all ok: store <l0,l1> and merge
1696           std      %l0, [%sp]
1697
1698          /*
1699           * The window we wanted to push could not be pushed.
1700           * Instead, save ALL user windows into the pcb.
1701           * We will notice later that we did this, when we
1702           * get ready to return from our trap or syscall.
1703           *
1704           * The code here is run rarely and need not be optimal.
1705           */
1706ctw_invalid:
1707          /*
1708           * Reread cpcb->pcb_uw.  We decremented this earlier,
1709           * so it is off by one.
1710           */
1711          sethi     %hi(cpcb), %g6                ! re-get current pcb
1712          ld        [%g6 + %lo(cpcb)], %g6
1713
1714          ld        [%g6 + PCB_UW], %g7 ! (number of user windows) - 1
1715          add       %g6, PCB_RW, %g5
1716
1717          /* save g7+1 windows, starting with the current one */
17181:                                                ! do {
1719          std       %l0, [%g5 + (0*8)]  !         rw->rw_local[0] = l0;
1720          std       %l2, [%g5 + (1*8)]  !         ...
1721          std       %l4, [%g5 + (2*8)]
1722          std       %l6, [%g5 + (3*8)]
1723          std       %i0, [%g5 + (4*8)]
1724          std       %i2, [%g5 + (5*8)]
1725          std       %i4, [%g5 + (6*8)]
1726          std       %i6, [%g5 + (7*8)]
1727          deccc     %g7                           !         if (n > 0) save(), rw++;
1728          bge,a     1b                            ! } while (--n >= 0);
1729           save     %g5, 64, %g5
1730
1731          /* stash sp for bottommost window */
1732          st        %sp, [%g5 + 64 + (7*8)]
1733
1734          /* set up new wim */
1735          rd        %psr, %g7           ! g7 = (junk << 5) + new_cwp;
1736          mov       1, %g5                        ! g5 = 1 << new_cwp;
1737          sll       %g5, %g7, %g5
1738          wr        %g5, 0, %wim                  ! wim = g5;
1739          and       %g7, 31, %g7
1740          st        %g7, [%g6 + PCB_WIM]          ! cpcb->pcb_wim = new_cwp;
1741
1742          /* fix up pcb fields */
1743          ld        [%g6 + PCB_UW], %g7 ! n = cpcb->pcb_uw;
1744          add       %g7, 1, %g5
1745          st        %g5, [%g6 + PCB_NSAVED]       ! cpcb->pcb_nsaved = n + 1;
1746          st        %g0, [%g6 + PCB_UW] ! cpcb->pcb_uw = 0;
1747
1748          /* return to trap window */
17491:        deccc     %g7                           ! do {
1750          bge       1b                            !         restore();
1751           restore                      ! } while (--n >= 0);
1752
1753          mov       %l5, %g5            ! restore g5, g6, & g7, and return
1754          mov       %l6, %g6
1755          jmp       %l4 + 8
1756           mov      %l7, %g7
1757          /* NOTREACHED */
1758
1759
1760/*
1761 * Each memory access (text or data) fault, from user or kernel mode,
1762 * comes here.  We read the error register and figure out what has
1763 * happened.
1764 *
1765 * This cannot be done from C code since we must not enable traps (and
1766 * hence may not use the `save' instruction) until we have decided that
1767 * the error is or is not an asynchronous one that showed up after a
1768 * synchronous error, but which must be handled before the sync err.
1769 *
1770 * Most memory faults are user mode text or data faults, which can cause
1771 * signal delivery or ptracing, for which we must build a full trapframe.
1772 * It does not seem worthwhile to work to avoid this in the other cases,
1773 * so we store all the %g registers on the stack immediately.
1774 *
1775 * On entry:
1776 *        %l0 = %psr
1777 *        %l1 = return pc
1778 *        %l2 = return npc
1779 *        %l3 = T_TEXTFAULT or T_DATAFAULT
1780 *
1781 * Internal:
1782 *        %l4 = %y, until we call mem_access_fault (then onto trapframe)
1783 *        %l5 = IE_reg_addr, if async mem error
1784 *
1785 */
1786
1787#if defined(SUN4)
1788_ENTRY(memfault_sun4)
1789memfault_sun4:
1790          TRAP_SETUP(-CCFSZ-80)
1791          ! tally interrupt (curcpu()->cpu_data.cpu_nfault++) (clobbers %o0,%o1)
1792          INCR64(CPUINFO_VA + CPUINFO_NFAULT)
1793
1794          st        %g1, [%sp + CCFSZ + 20]       ! save g1
1795          rd        %y, %l4                       ! save y
1796
1797          /*
1798           * registers:
1799           * memerr.ctrl      = memory error control reg., error if 0x80 set
1800           * memerr.vaddr     = address of memory error
1801           * buserr = basically just like sun4c sync error reg but
1802           *                    no SER_WRITE bit (have to figure out from code).
1803           */
1804          set       _C_LABEL(par_err_reg), %o0 ! memerr ctrl addr -- XXX mapped?
1805          ld        [%o0], %o0                    ! get it
1806          std       %g2, [%sp + CCFSZ + 24]       ! save g2, g3
1807          ld        [%o0], %o1                    ! memerr ctrl register
1808          inc       4, %o0                        ! now VA of memerr vaddr register
1809          std       %g4, [%sp + CCFSZ + 32]       ! (sneak g4,g5 in here)
1810          ld        [%o0], %o2                    ! memerr virt addr
1811          st        %g0, [%o0]                    ! NOTE: this clears latching!!!
1812          btst      ME_REG_IERR, %o1    ! memory error?
1813                                                  ! XXX this value may not be correct
1814                                                  ! as I got some parity errors and the
1815                                                  ! correct bits were not on?
1816          std       %g6, [%sp + CCFSZ + 40]
1817          bz,a      0f                            ! no, just a regular fault
1818           wr       %l0, PSR_ET, %psr   ! (and reenable traps)
1819
1820          /* memory error = death for now XXX */
1821          clr       %o3
1822          clr       %o4
1823          call      _C_LABEL(memerr4_4c)          ! memerr(0, ser, sva, 0, 0)
1824           clr      %o0
1825          call      _C_LABEL(prom_halt)
1826           nop
1827
18280:
1829          /*
1830           * have to make SUN4 emulate SUN4C.   4C code expects
1831           * SER in %o1 and the offending VA in %o2, everything else is ok.
1832           * (must figure out if SER_WRITE should be set)
1833           */
1834          set       AC_BUS_ERR, %o0               ! bus error register
1835          cmp       %l3, T_TEXTFAULT    ! text fault always on PC
1836          be        normal_mem_fault    ! go
1837           lduba    [%o0] ASI_CONTROL, %o1        ! get its value
1838
1839#define STORE_BIT 21 /* bit that indicates a store instruction for sparc */
1840          ld        [%l1], %o3                    ! offending instruction in %o3 [l1=pc]
1841          srl       %o3, STORE_BIT, %o3 ! get load/store bit (wont fit simm13)
1842          btst      1, %o3                        ! test for store operation
1843
1844          bz        normal_mem_fault    ! if (z) is a load (so branch)
1845           sethi    %hi(SER_WRITE), %o5     ! damn SER_WRITE wont fit simm13
1846!         or        %lo(SER_WRITE), %o5, %o5! not necessary since %lo is zero
1847          or        %o5, %o1, %o1                 ! set SER_WRITE
1848#if defined(SUN4C) || defined(SUN4M)
1849          ba,a      normal_mem_fault
1850           !!nop                                  ! XXX make efficient later
1851#endif /* SUN4C || SUN4M */
1852#endif /* SUN4 */
1853
1854#if defined(SUN4C)
1855_ENTRY(memfault_sun4c)
1856memfault_sun4c:
1857          TRAP_SETUP(-CCFSZ-80)
1858          ! tally fault (curcpu()->cpu_data.cpu_nfault++) (clobbers %o0,%o1,%o2)
1859          INCR64(CPUINFO_VA + CPUINFO_NFAULT)
1860
1861          st        %g1, [%sp + CCFSZ + 20]       ! save g1
1862          rd        %y, %l4                       ! save y
1863
1864          /*
1865           * We know about the layout of the error registers here.
1866           *        addr      reg
1867           *        ----      ---
1868           *        a         AC_SYNC_ERR
1869           *        a+4       AC_SYNC_VA
1870           *        a+8       AC_ASYNC_ERR
1871           *        a+12      AC_ASYNC_VA
1872           */
1873
1874#if AC_SYNC_ERR + 4 != AC_SYNC_VA || \
1875    AC_SYNC_ERR + 8 != AC_ASYNC_ERR || AC_SYNC_ERR + 12 != AC_ASYNC_VA
1876          help help help                ! I, I, I wanna be a lifeguard
1877#endif
1878          set       AC_SYNC_ERR, %o0
1879          std       %g2, [%sp + CCFSZ + 24]       ! save g2, g3
1880          lda       [%o0] ASI_CONTROL, %o1        ! sync err reg
1881          inc       4, %o0
1882          std       %g4, [%sp + CCFSZ + 32]       ! (sneak g4,g5 in here)
1883          lda       [%o0] ASI_CONTROL, %o2        ! sync virt addr
1884          btst      SER_MEMERR, %o1               ! memory error?
1885          std       %g6, [%sp + CCFSZ + 40]
1886          bz,a      normal_mem_fault    ! no, just a regular fault
1887           wr       %l0, PSR_ET, %psr   ! (and reenable traps)
1888
1889          /*
1890           * We got a synchronous memory error.  It could be one that
1891           * happened because there were two stores in a row, and the
1892           * first went into the write buffer, and the second caused this
1893           * synchronous trap; so there could now be a pending async error.
1894           * This is in fact the case iff the two va's differ.
1895           */
1896          inc       4, %o0
1897          lda       [%o0] ASI_CONTROL, %o3        ! async err reg
1898          inc       4, %o0
1899          lda       [%o0] ASI_CONTROL, %o4        ! async virt addr
1900          cmp       %o2, %o4
1901          be,a      1f                            ! no, not an async err
1902           wr       %l0, PSR_ET, %psr   ! (and reenable traps)
1903
1904          /*
1905           * Handle the async error; ignore the sync error for now
1906           * (we may end up getting it again, but so what?).
1907           * This code is essentially the same as that at `nmi' below,
1908           * but the register usage is different and we cannot merge.
1909           */
1910          sethi     %hi(INTRREG_VA), %l5          ! ienab_bic(IE_ALLIE);
1911          ldub      [%l5 + %lo(INTRREG_VA)], %o0
1912          andn      %o0, IE_ALLIE, %o0
1913          stb       %o0, [%l5 + %lo(INTRREG_VA)]
1914
1915          /*
1916           * Now reenable traps and call C code.
1917           * %o1 through %o4 still hold the error reg contents.
1918           * If memerr() returns, return from the trap.
1919           */
1920          wr        %l0, PSR_ET, %psr
1921          call      _C_LABEL(memerr4_4c)          ! memerr(0, ser, sva, aer, ava)
1922           clr      %o0
1923
1924          ld        [%sp + CCFSZ + 20], %g1       ! restore g1 through g7
1925          wr        %l0, 0, %psr                  ! and disable traps, 3 instr delay
1926          ldd       [%sp + CCFSZ + 24], %g2
1927          ldd       [%sp + CCFSZ + 32], %g4
1928          ldd       [%sp + CCFSZ + 40], %g6
1929          /* now safe to set IE_ALLIE again */
1930          ldub      [%l5 + %lo(INTRREG_VA)], %o1
1931          or        %o1, IE_ALLIE, %o1
1932          stb       %o1, [%l5 + %lo(INTRREG_VA)]
1933          b         return_from_trap
1934           wr       %l4, 0, %y                    ! restore y
1935
1936          /*
1937           * Trap was a synchronous memory error.
1938           * %o1 through %o4 still hold the error reg contents.
1939           */
19401:
1941          call      _C_LABEL(memerr4_4c)          ! memerr(1, ser, sva, aer, ava)
1942           mov      1, %o0
1943
1944          ld        [%sp + CCFSZ + 20], %g1       ! restore g1 through g7
1945          ldd       [%sp + CCFSZ + 24], %g2
1946          ldd       [%sp + CCFSZ + 32], %g4
1947          ldd       [%sp + CCFSZ + 40], %g6
1948          wr        %l4, 0, %y                    ! restore y
1949          b         return_from_trap
1950           wr       %l0, 0, %psr
1951          /* NOTREACHED */
1952#endif /* SUN4C */
1953
1954#if defined(SUN4M)
1955_ENTRY(memfault_sun4m)
1956memfault_sun4m:
1957          sethi     %hi(CPUINFO_VA+CPUINFO_GETSYNCFLT), %l4
1958          ld        [%l4 + %lo(CPUINFO_VA+CPUINFO_GETSYNCFLT)], %l5
1959          sethi     %hi(CPUINFO_VA+CPUINFO_SYNCFLTDUMP), %l4
1960          jmpl      %l5, %l7
1961           or       %l4, %lo(CPUINFO_VA+CPUINFO_SYNCFLTDUMP), %l4
1962          TRAP_SETUP(-CCFSZ-80)
1963          ! tally fault (curcpu()->cpu_data.cpu_nfault++) (clobbers %o0,%o1,%o2)
1964          INCR64(CPUINFO_VA + CPUINFO_NFAULT)
1965
1966          st        %g1, [%sp + CCFSZ + 20]       ! save g1
1967          rd        %y, %l4                       ! save y
1968
1969          std       %g2, [%sp + CCFSZ + 24]       ! save g2, g3
1970          std       %g4, [%sp + CCFSZ + 32]       ! save g4, g5
1971          std       %g6, [%sp + CCFSZ + 40]       ! sneak in g6, g7
1972
1973          ! retrieve sync fault status/address
1974          sethi     %hi(CPUINFO_VA+CPUINFO_SYNCFLTDUMP), %o0
1975          ld        [%o0 + %lo(CPUINFO_VA+CPUINFO_SYNCFLTDUMP)], %o1
1976          ld        [%o0 + %lo(CPUINFO_VA+CPUINFO_SYNCFLTDUMP+4)], %o2
1977
1978          wr        %l0, PSR_ET, %psr   ! reenable traps
1979
1980          /* Finish stackframe, call C trap handler */
1981          std       %l0, [%sp + CCFSZ + 0]        ! set tf.tf_psr, tf.tf_pc
1982          mov       %l3, %o0            ! (argument: type)
1983          st        %l2, [%sp + CCFSZ + 8]        ! set tf.tf_npc
1984          st        %l4, [%sp + CCFSZ + 12]       ! set tf.tf_y
1985          std       %i0, [%sp + CCFSZ + 48]       ! tf.tf_out[0], etc
1986          std       %i2, [%sp + CCFSZ + 56]
1987          std       %i4, [%sp + CCFSZ + 64]
1988          std       %i6, [%sp + CCFSZ + 72]
1989                                                  ! mem_access_fault(type,sfsr,sfva,&tf);
1990          call      _C_LABEL(mem_access_fault4m)
1991           add      %sp, CCFSZ, %o3               ! (argument: &tf)
1992
1993          ldd       [%sp + CCFSZ + 0], %l0        ! load new values
1994          ldd       [%sp + CCFSZ + 8], %l2
1995          wr        %l3, 0, %y
1996          ld        [%sp + CCFSZ + 20], %g1
1997          ldd       [%sp + CCFSZ + 24], %g2
1998          ldd       [%sp + CCFSZ + 32], %g4
1999          ldd       [%sp + CCFSZ + 40], %g6
2000          ldd       [%sp + CCFSZ + 48], %i0
2001          ldd       [%sp + CCFSZ + 56], %i2
2002          ldd       [%sp + CCFSZ + 64], %i4
2003          ldd       [%sp + CCFSZ + 72], %i6
2004
2005          b         return_from_trap    ! go return
2006           wr       %l0, 0, %psr                  ! (but first disable traps again)
2007#endif /* SUN4M */
2008
2009normal_mem_fault:
2010          /*
2011           * Trap was some other error; call C code to deal with it.
2012           * Must finish trap frame (psr,pc,npc,%y,%o0..%o7) in case
2013           * we decide to deliver a signal or ptrace the process.
2014           * %g1..%g7 were already set up above.
2015           */
2016          std       %l0, [%sp + CCFSZ + 0]        ! set tf.tf_psr, tf.tf_pc
2017          mov       %l3, %o0            ! (argument: type)
2018          st        %l2, [%sp + CCFSZ + 8]        ! set tf.tf_npc
2019          st        %l4, [%sp + CCFSZ + 12]       ! set tf.tf_y
2020          mov       %l1, %o3            ! (argument: pc)
2021          std       %i0, [%sp + CCFSZ + 48]       ! tf.tf_out[0], etc
2022          std       %i2, [%sp + CCFSZ + 56]
2023          mov       %l0, %o4            ! (argument: psr)
2024          std       %i4, [%sp + CCFSZ + 64]
2025          std       %i6, [%sp + CCFSZ + 72]
2026          call      _C_LABEL(mem_access_fault)! mem_access_fault(type, ser, sva,
2027                                                  !                   pc, psr, &tf);
2028           add      %sp, CCFSZ, %o5               ! (argument: &tf)
2029
2030          ldd       [%sp + CCFSZ + 0], %l0        ! load new values
2031          ldd       [%sp + CCFSZ + 8], %l2
2032          wr        %l3, 0, %y
2033          ld        [%sp + CCFSZ + 20], %g1
2034          ldd       [%sp + CCFSZ + 24], %g2
2035          ldd       [%sp + CCFSZ + 32], %g4
2036          ldd       [%sp + CCFSZ + 40], %g6
2037          ldd       [%sp + CCFSZ + 48], %i0
2038          ldd       [%sp + CCFSZ + 56], %i2
2039          ldd       [%sp + CCFSZ + 64], %i4
2040          ldd       [%sp + CCFSZ + 72], %i6
2041
2042          b         return_from_trap    ! go return
2043           wr       %l0, 0, %psr                  ! (but first disable traps again)
2044
2045illinst4m:
2046          /*
2047           * Cypress CPUs like to generate an Illegal Instruction trap
2048           * for FLUSH instructions. Since we turn FLUSHes into no-ops
2049           * (see also trap.c/emul.c), we check for this case here in
2050           * the trap window, saving the overhead of a slow trap.
2051           *
2052           * We have to be careful not to incur a trap while probing
2053           * for the instruction in user space. Use the Inhibit Fault
2054           * bit in the PCR register to prevent that.
2055           */
2056
2057          btst      PSR_PS, %l0                   ! slowtrap() if from kernel
2058          bnz       slowtrap
2059           .empty
2060
2061          ! clear fault status
2062          set       SRMMU_SFSR, %l7
2063          lda       [%l7]ASI_SRMMU, %g0
2064
2065          ! turn on the fault inhibit in PCR
2066          !set      SRMMU_PCR, reg                          - SRMMU_PCR == 0, so use %g0
2067          lda       [%g0]ASI_SRMMU, %l4
2068          or        %l4, SRMMU_PCR_NF, %l5
2069          sta       %l5, [%g0]ASI_SRMMU
2070
2071          ! load the insn word as if user insn fetch
2072          lda       [%l1]ASI_USERI, %l5
2073
2074          sta       %l4, [%g0]ASI_SRMMU           ! restore PCR
2075
2076          ! check fault status; if we have a fault, take a regular trap
2077          set       SRMMU_SFAR, %l6
2078          lda       [%l6]ASI_SRMMU, %g0           ! fault VA; must be read first
2079          lda       [%l7]ASI_SRMMU, %l6           ! fault status
2080          andcc     %l6, SFSR_FAV, %l6            ! get fault status bits
2081          bnz       slowtrap
2082           .empty
2083
2084          ! we got the insn; check whether it was a FLUSH
2085          ! instruction format: op=2, op3=0x3b (see also instr.h)
2086          set       ((3 << 30) | (0x3f << 19)), %l7         ! extract op & op3 fields
2087          and       %l5, %l7, %l6
2088          set       ((2 << 30) | (0x3b << 19)), %l7         ! any FLUSH opcode
2089          cmp       %l6, %l7
2090          bne       slowtrap
2091           nop
2092
2093          mov       %l2, %l1                      ! ADVANCE <pc,npc>
2094          mov       %l0, %psr                     ! and return from trap
2095           add      %l2, 4, %l2
2096          RETT
2097
2098
2099/*
2100 * fp_exception has to check to see if we are trying to save
2101 * the FP state, and if so, continue to save the FP state.
2102 *
2103 * We do not even bother checking to see if we were in kernel mode,
2104 * since users have no access to the special_fp_store instruction.
2105 *
2106 * This whole idea was stolen from Sprite.
2107 */
2108fp_exception:
2109          set       special_fp_store, %l4         ! see if we came from the special one
2110          cmp       %l1, %l4            ! pc == special_fp_store?
2111          bne       slowtrap            ! no, go handle per usual
2112           .empty
2113          sethi     %hi(savefpcont), %l4          ! yes, "return" to the special code
2114          or        %lo(savefpcont), %l4, %l4
2115          jmp       %l4
2116           rett     %l4 + 4
2117
2118/*
2119 * slowtrap() builds a trap frame and calls trap().
2120 * This is called `slowtrap' because it *is*....
2121 * We have to build a full frame for ptrace(), for instance.
2122 *
2123 * Registers:
2124 *        %l0 = %psr
2125 *        %l1 = return pc
2126 *        %l2 = return npc
2127 *        %l3 = trap code
2128 */
2129slowtrap:
2130          TRAP_SETUP(-CCFSZ-80)
2131          /*
2132           * Phew, ready to enable traps and call C code.
2133           */
2134          mov       %l3, %o0            ! put type in %o0 for later
2135Lslowtrap_reenter:
2136          wr        %l0, PSR_ET, %psr   ! traps on again
2137          std       %l0, [%sp + CCFSZ]  ! tf.tf_psr = psr; tf.tf_pc = ret_pc;
2138          rd        %y, %l3
2139          std       %l2, [%sp + CCFSZ + 8]        ! tf.tf_npc = return_npc; tf.tf_y = %y;
2140          st        %g1, [%sp + CCFSZ + 20]
2141          std       %g2, [%sp + CCFSZ + 24]
2142          std       %g4, [%sp + CCFSZ + 32]
2143          std       %g6, [%sp + CCFSZ + 40]
2144          std       %i0, [%sp + CCFSZ + 48]
2145          mov       %l0, %o1            ! (psr)
2146          std       %i2, [%sp + CCFSZ + 56]
2147          mov       %l1, %o2            ! (pc)
2148          std       %i4, [%sp + CCFSZ + 64]
2149          add       %sp, CCFSZ, %o3               ! (&tf)
2150          call      _C_LABEL(trap)                ! trap(type, psr, pc, &tf)
2151           std      %i6, [%sp + CCFSZ + 72]
2152
2153          ldd       [%sp + CCFSZ], %l0  ! load new values
2154          ldd       [%sp + CCFSZ + 8], %l2
2155          wr        %l3, 0, %y
2156          ld        [%sp + CCFSZ + 20], %g1
2157          ldd       [%sp + CCFSZ + 24], %g2
2158          ldd       [%sp + CCFSZ + 32], %g4
2159          ldd       [%sp + CCFSZ + 40], %g6
2160          ldd       [%sp + CCFSZ + 48], %i0
2161          ldd       [%sp + CCFSZ + 56], %i2
2162          ldd       [%sp + CCFSZ + 64], %i4
2163          ldd       [%sp + CCFSZ + 72], %i6
2164          b         return_from_trap
2165           wr       %l0, 0, %psr
2166
2167/*
2168 * Do a `software' trap by re-entering the trap code, possibly first
2169 * switching from interrupt stack to kernel stack.  This is used for
2170 * scheduling and signal ASTs (which generally occur from softclock or
2171 * tty or net interrupts) and register window saves (which might occur
2172 * from anywhere).
2173 *
2174 * The current window is the trap window, and it is by definition clean.
2175 * We enter with the trap type in %o0.  All we have to do is jump to
2176 * Lslowtrap_reenter above, but maybe after switching stacks....
2177 */
2178softtrap:
2179#if defined(MULTIPROCESSOR)
2180          /*
2181           * The interrupt stack is not at a fixed location
2182           * and %sp must be checked against both ends.
2183           */
2184          sethi     %hi(_EINTSTACKP), %l6
2185          ld        [%l6 + %lo(_EINTSTACKP)], %l7
2186          cmp       %sp, %l7
2187          bge       Lslowtrap_reenter
2188           .empty
2189          set       INT_STACK_SIZE, %l6
2190          sub       %l7, %l6, %l7
2191          cmp       %sp, %l7
2192          blu       Lslowtrap_reenter
2193           .empty
2194#else
2195          sethi     %hi(_C_LABEL(eintstack)), %l7
2196          cmp       %sp, %l7
2197          bge       Lslowtrap_reenter
2198           .empty
2199#endif
2200          sethi     %hi(cpcb), %l6
2201          ld        [%l6 + %lo(cpcb)], %l6
2202          set       USPACE-CCFSZ-80, %l5
2203          add       %l6, %l5, %l7
2204          SET_SP_REDZONE(%l6, %l5)
2205          b         Lslowtrap_reenter
2206           mov      %l7, %sp
2207
2208#ifdef KGDB
2209/*
2210 * bpt is entered on all breakpoint traps.
2211 * If this is a kernel breakpoint, we do not want to call trap().
2212 * Among other reasons, this way we can set breakpoints in trap().
2213 */
2214bpt:
2215          btst      PSR_PS, %l0                   ! breakpoint from kernel?
2216          bz        slowtrap            ! no, go do regular trap
2217           nop
2218
2219/* XXXSMP */
2220          /*
2221           * Build a trap frame for kgdb_trap_glue to copy.
2222           * Enable traps but set ipl high so that we will not
2223           * see interrupts from within breakpoints.
2224           */
2225          TRAP_SETUP(-CCFSZ-80)
2226          or        %l0, PSR_PIL, %l4   ! splhigh()
2227          wr        %l4, 0, %psr                  ! the manual claims that this
2228          wr        %l4, PSR_ET, %psr   ! song and dance is necessary
2229          std       %l0, [%sp + CCFSZ + 0]        ! tf.tf_psr, tf.tf_pc
2230          mov       %l3, %o0            ! trap type arg for kgdb_trap_glue
2231          rd        %y, %l3
2232          std       %l2, [%sp + CCFSZ + 8]        ! tf.tf_npc, tf.tf_y
2233          rd        %wim, %l3
2234          st        %l3, [%sp + CCFSZ + 16]       ! tf.tf_wim (a kgdb-only r/o field)
2235          st        %g1, [%sp + CCFSZ + 20]       ! tf.tf_global[1]
2236          std       %g2, [%sp + CCFSZ + 24]       ! etc
2237          std       %g4, [%sp + CCFSZ + 32]
2238          std       %g6, [%sp + CCFSZ + 40]
2239          std       %i0, [%sp + CCFSZ + 48]       ! tf.tf_in[0..1]
2240          std       %i2, [%sp + CCFSZ + 56]       ! etc
2241          std       %i4, [%sp + CCFSZ + 64]
2242          std       %i6, [%sp + CCFSZ + 72]
2243
2244          /*
2245           * Now call kgdb_trap_glue(); if it returns, call trap().
2246           */
2247          mov       %o0, %l3            ! gotta save trap type
2248          call      _C_LABEL(kgdb_trap_glue)! kgdb_trap_glue(type, &trapframe)
2249           add      %sp, CCFSZ, %o1               ! (&trapframe)
2250
2251          /*
2252           * Use slowtrap to call trap---but first erase our tracks
2253           * (put the registers back the way they were).
2254           */
2255          mov       %l3, %o0            ! slowtrap will need trap type
2256          ld        [%sp + CCFSZ + 12], %l3
2257          wr        %l3, 0, %y
2258          ld        [%sp + CCFSZ + 20], %g1
2259          ldd       [%sp + CCFSZ + 24], %g2
2260          ldd       [%sp + CCFSZ + 32], %g4
2261          b         Lslowtrap_reenter
2262           ldd      [%sp + CCFSZ + 40], %g6
2263
2264/*
2265 * Enter kernel breakpoint.  Write all the windows (not including the
2266 * current window) into the stack, so that backtrace works.  Copy the
2267 * supplied trap frame to the kgdb stack and switch stacks.
2268 *
2269 * kgdb_trap_glue(type, tf0)
2270 *        int type;
2271 *        struct trapframe *tf0;
2272 */
2273_ENTRY(_C_LABEL(kgdb_trap_glue))
2274          save      %sp, -CCFSZ, %sp
2275
2276          call      _C_LABEL(write_all_windows)
2277           mov      %sp, %l4            ! %l4 = current %sp
2278
2279          /* copy trapframe to top of kgdb stack */
2280          set       _C_LABEL(kgdb_stack) + KGDB_STACK_SIZE - 80, %l0
2281                                                  ! %l0 = tfcopy -> end_of_kgdb_stack
2282          mov       80, %l1
22831:        ldd       [%i1], %l2
2284          inc       8, %i1
2285          deccc     8, %l1
2286          std       %l2, [%l0]
2287          bg        1b
2288           inc      8, %l0
2289
2290#if defined(DEBUG) && !defined(MULTIPROCESSOR)
2291          /* save old red zone and then turn it off */
2292          sethi     %hi(_redzone), %l7
2293          ld        [%l7 + %lo(_redzone)], %l6
2294          st        %g0, [%l7 + %lo(_redzone)]
2295#endif
2296          /* switch to kgdb stack */
2297          add       %l0, -CCFSZ-80, %sp
2298
2299          /* if (kgdb_trap(type, tfcopy)) kgdb_rett(tfcopy); */
2300          mov       %i0, %o0
2301          call      _C_LABEL(kgdb_trap)
2302          add       %l0, -80, %o1
2303          tst       %o0
2304          bnz,a     kgdb_rett
2305           add      %l0, -80, %g1
2306
2307          /*
2308           * kgdb_trap() did not handle the trap at all so the stack is
2309           * still intact.  A simple `restore' will put everything back,
2310           * after we reset the stack pointer.
2311           */
2312          mov       %l4, %sp
2313#if defined(DEBUG) && !defined(MULTIPROCESSOR)
2314          st        %l6, [%l7 + %lo(_redzone)]    ! restore red zone
2315#endif
2316          ret
2317          restore
2318
2319/*
2320 * Return from kgdb trap.  This is sort of special.
2321 *
2322 * We know that kgdb_trap_glue wrote the window above it, so that we will
2323 * be able to (and are sure to have to) load it up.  We also know that we
2324 * came from kernel land and can assume that the %fp (%i6) we load here
2325 * is proper.  We must also be sure not to lower ipl (it is at splhigh())
2326 * until we have traps disabled, due to the SPARC taking traps at the
2327 * new ipl before noticing that PSR_ET has been turned off.  We are on
2328 * the kgdb stack, so this could be disastrous.
2329 *
2330 * Note that the trapframe argument in %g1 points into the current stack
2331 * frame (current window).  We abandon this window when we move %g1->tf_psr
2332 * into %psr, but we will not have loaded the new %sp yet, so again traps
2333 * must be disabled.
2334 */
2335kgdb_rett:
2336          rd        %psr, %g4           ! turn off traps
2337          wr        %g4, PSR_ET, %psr
2338          /* use the three-instruction delay to do something useful */
2339          ld        [%g1], %g2                    ! pick up new %psr
2340          ld        [%g1 + 12], %g3               ! set %y
2341          wr        %g3, 0, %y
2342#if defined(DEBUG) && !defined(MULTIPROCESSOR)
2343          st        %l6, [%l7 + %lo(_redzone)] ! and restore red zone
2344#endif
2345          wr        %g0, 0, %wim                  ! enable window changes
2346          nop; nop; nop
2347          /* now safe to set the new psr (changes CWP, leaves traps disabled) */
2348          wr        %g2, 0, %psr                  ! set rett psr (including cond codes)
2349          /* 3 instruction delay before we can use the new window */
2350/*1*/     ldd       [%g1 + 24], %g2               ! set new %g2, %g3
2351/*2*/     ldd       [%g1 + 32], %g4               ! set new %g4, %g5
2352/*3*/     ldd       [%g1 + 40], %g6               ! set new %g6, %g7
2353
2354          /* now we can use the new window */
2355          mov       %g1, %l4
2356          ld        [%l4 + 4], %l1                ! get new pc
2357          ld        [%l4 + 8], %l2                ! get new npc
2358          ld        [%l4 + 20], %g1               ! set new %g1
2359
2360          /* set up returnee's out registers, including its %sp */
2361          ldd       [%l4 + 48], %i0
2362          ldd       [%l4 + 56], %i2
2363          ldd       [%l4 + 64], %i4
2364          ldd       [%l4 + 72], %i6
2365
2366          /* load returnee's window, making the window above it be invalid */
2367          restore
2368          restore   %g0, 1, %l1                   ! move to inval window and set %l1 = 1
2369          rd        %psr, %l0
2370          sll       %l1, %l0, %l1
2371          wr        %l1, 0, %wim                  ! %wim = 1 << (%psr & 31)
2372          sethi     %hi(cpcb), %l1
2373          ld        [%l1 + %lo(cpcb)], %l1
2374          and       %l0, 31, %l0                  ! CWP = %psr & 31;
2375          st        %l0, [%l1 + PCB_WIM]          ! cpcb->pcb_wim = CWP;
2376          save      %g0, %g0, %g0                 ! back to window to reload
2377          LOADWIN(%sp)
2378          save      %g0, %g0, %g0                 ! back to trap window
2379          /* note, we have not altered condition codes; safe to just rett */
2380          RETT
2381#endif
2382
2383/*
2384 * syscall() builds a trap frame and calls syscall().
2385 * sun_syscall is same but delivers sun system call number
2386 * XXX    should not have to save&reload ALL the registers just for
2387 *        ptrace...
2388 */
2389_C_LABEL(_syscall):
2390          TRAP_SETUP(-CCFSZ-80)
2391#ifdef DEBUG
2392          or        %g1, 0x1000, %l6    ! mark syscall
2393          TRAP_TRACE(%l6,%l5)
2394#endif
2395          wr        %l0, PSR_ET, %psr
2396          std       %l0, [%sp + CCFSZ + 0]        ! tf_psr, tf_pc
2397          rd        %y, %l3
2398          std       %l2, [%sp + CCFSZ + 8]        ! tf_npc, tf_y
2399          st        %g1, [%sp + CCFSZ + 20]       ! tf_g[1]
2400          std       %g2, [%sp + CCFSZ + 24]       ! tf_g[2], tf_g[3]
2401          std       %g4, [%sp + CCFSZ + 32]       ! etc
2402          std       %g6, [%sp + CCFSZ + 40]
2403          mov       %g1, %o0            ! (code)
2404          std       %i0, [%sp + CCFSZ + 48]
2405          add       %sp, CCFSZ, %o1               ! (&tf)
2406          std       %i2, [%sp + CCFSZ + 56]
2407          mov       %l1, %o2            ! (pc)
2408          std       %i4, [%sp + CCFSZ + 64]
2409
2410          sethi     %hi(curlwp), %l1
2411          ld        [%l1 + %lo(curlwp)], %l1
2412          ld        [%l1 + L_PROC], %l1
2413          ld        [%l1 + P_MD_SYSCALL], %l1
2414          call      %l1                           ! syscall(code, &tf, pc, suncompat)
2415           std      %i6, [%sp + CCFSZ + 72]
2416          ! now load em all up again, sigh
2417          ldd       [%sp + CCFSZ + 0], %l0        ! new %psr, new pc
2418          ldd       [%sp + CCFSZ + 8], %l2        ! new npc, new %y
2419          wr        %l3, 0, %y
2420          /* see `lwp_trampoline' for the reason for this label */
2421return_from_syscall:
2422          ld        [%sp + CCFSZ + 20], %g1
2423          ldd       [%sp + CCFSZ + 24], %g2
2424          ldd       [%sp + CCFSZ + 32], %g4
2425          ldd       [%sp + CCFSZ + 40], %g6
2426          ldd       [%sp + CCFSZ + 48], %i0
2427          ldd       [%sp + CCFSZ + 56], %i2
2428          ldd       [%sp + CCFSZ + 64], %i4
2429          ldd       [%sp + CCFSZ + 72], %i6
2430          b         return_from_trap
2431           wr       %l0, 0, %psr
2432
2433/*
2434 * Interrupts.  Software interrupts must be cleared from the software
2435 * interrupt enable register.  Rather than calling ienab_bic for each,
2436 * we do them in-line before enabling traps.
2437 *
2438 * After preliminary setup work, the interrupt is passed to each
2439 * registered handler in turn.  These are expected to return nonzero if
2440 * they took care of the interrupt.  If a handler claims the interrupt,
2441 * we exit (hardware interrupts are latched in the requestor so we'll
2442 * just take another interrupt in the unlikely event of simultaneous
2443 * interrupts from two different devices at the same level).  If we go
2444 * through all the registered handlers and no one claims it, we report a
2445 * stray interrupt.  This is more or less done as:
2446 *
2447 *        for (ih = intrhand[intlev]; ih; ih = ih->ih_next)
2448 *                  if ((*ih->ih_fun)(ih->ih_arg ? ih->ih_arg : &frame))
2449 *                            return;
2450 *        strayintr(&frame);
2451 *
2452 * Software interrupts are almost the same with three exceptions:
2453 * (1) we clear the interrupt from the software interrupt enable
2454 *     register before calling any handler (we have to clear it first
2455 *     to avoid an interrupt-losing race),
2456 * (2) we always call all the registered handlers (there is no way
2457 *     to tell if the single bit in the software interrupt register
2458 *     represents one or many requests)
2459 * (3) we never announce a stray interrupt (because of (1), another
2460 *     interrupt request can come in while we're in the handler.  If
2461 *     the handler deals with everything for both the original & the
2462 *     new request, we'll erroneously report a stray interrupt when
2463 *     we take the software interrupt for the new request.
2464 *
2465 * Inputs:
2466 *        %l0 = %psr
2467 *        %l1 = return pc
2468 *        %l2 = return npc
2469 *        %l3 = interrupt level
2470 *        (software interrupt only) %l4 = bits to clear in interrupt register
2471 *
2472 * Internal:
2473 *        %l4, %l5: local variables
2474 *        %l6 = %y
2475 *        %l7 = %g1
2476 *        %g2..%g7 go to stack
2477 *
2478 * An interrupt frame is built in the space for a full trapframe;
2479 * this contains the psr, pc, npc, and interrupt level.
2480 */
2481softintr_sun44c:
2482          /*
2483           * Entry point for level 1, 4 or 6 interrupts on sun4/sun4c
2484           * which may be software interrupts. Check the interrupt
2485           * register to see whether we're dealing software or hardware
2486           * interrupt.
2487           */
2488          sethi     %hi(INTRREG_VA), %l6
2489          ldub      [%l6 + %lo(INTRREG_VA)], %l5
2490          btst      %l5, %l4            ! is IE_L{1,4,6} set?
2491          bz        sparc_interrupt44c  ! if not, must be a hw intr
2492          andn      %l5, %l4, %l5                 ! clear soft intr bit
2493          stb       %l5, [%l6 + %lo(INTRREG_VA)]
2494
2495softintr_common:
2496          INTR_SETUP(-CCFSZ-80)
2497          std       %g2, [%sp + CCFSZ + 24]       ! save registers
2498          ! tally softint (curcpu()->cpu_data.cpu_nintr++) (clobbers %o0,%o1,%o2)
2499          INCR64(CPUINFO_VA + CPUINFO_NSOFT)
2500          mov       %g1, %l7
2501          rd        %y, %l6
2502          std       %g4, [%sp + CCFSZ + 32]
2503          andn      %l0, PSR_PIL, %l4   ! %l4 = psr & ~PSR_PIL |
2504          sll       %l3, 8, %l5                   !         intlev << IPLSHIFT
2505          std       %g6, [%sp + CCFSZ + 40]
2506          or        %l5, %l4, %l4                 !                             ;
2507          wr        %l4, 0, %psr                  ! the manual claims this
2508          wr        %l4, PSR_ET, %psr   ! song and dance is necessary
2509          std       %l0, [%sp + CCFSZ + 0]        ! set up intrframe/clockframe
2510          sll       %l3, 2, %l5
2511
2512          set       CPUINFO_VA + CPUINFO_SINTRCNT, %l4      ! sintrcnt[intlev].ev_count++;
2513          sll       %l3, EV_STRUCTSHIFT, %o2
2514          ldd       [%l4 + %o2], %o0
2515          std       %l2, [%sp + CCFSZ + 8]        ! set up intrframe/clockframe
2516          inccc   %o1
2517          addx    %o0, 0, %o0
2518          std       %o0, [%l4 + %o2]
2519
2520          set       _C_LABEL(sintrhand), %l4! %l4 = sintrhand[intlev];
2521          ld        [%l4 + %l5], %l4
2522
2523          sethi     %hi(CPUINFO_VA+CPUINFO_IDEPTH), %o2
2524          ld        [ %o2 + %lo(CPUINFO_VA+CPUINFO_IDEPTH) ], %o3
2525          inc       %o3
2526          st        %o3, [ %o2 + %lo(CPUINFO_VA+CPUINFO_IDEPTH) ]
2527
2528          b         3f
2529           st       %fp, [%sp + CCFSZ + 16]
2530
25311:        ld        [%l4 + IH_CLASSIPL], %o2 ! ih->ih_classipl
2532          rd        %psr, %o3           !  (bits already shifted to PIL field)
2533          andn      %o3, PSR_PIL, %o3   ! %o3 = psr & ~PSR_PIL
2534          wr        %o3, %o2, %psr                ! splraise(ih->ih_classipl)
2535          ld        [%l4 + IH_FUN], %o1
2536          ld        [%l4 + IH_ARG], %o0
2537          nop                                     ! one more isns before touching ICC
2538          tst       %o0
2539          bz,a      2f
2540           add      %sp, CCFSZ, %o0
25412:        jmpl      %o1, %o7            !         (void)(*ih->ih_fun)(...)
2542           ld       [%l4 + IH_NEXT], %l4          !         and ih = ih->ih_next
25433:        tst       %l4                           ! while ih != NULL
2544          bnz       1b
2545           nop
2546
2547          sethi     %hi(CPUINFO_VA+CPUINFO_IDEPTH), %o2
2548          ld        [ %o2 + %lo(CPUINFO_VA+CPUINFO_IDEPTH) ], %o3
2549          dec       %o3
2550          st        %o3, [ %o2 + %lo(CPUINFO_VA+CPUINFO_IDEPTH) ]
2551
2552          mov       %l7, %g1
2553          wr        %l6, 0, %y
2554          ldd       [%sp + CCFSZ + 24], %g2
2555          ldd       [%sp + CCFSZ + 32], %g4
2556          ldd       [%sp + CCFSZ + 40], %g6
2557          b         return_from_trap
2558           wr       %l0, 0, %psr
2559
2560          /*
2561           * _sparc_interrupt{44c,4m} is exported for paranoia checking
2562           * (see intr.c).
2563           */
2564#if defined(SUN4M)
2565_ENTRY(_C_LABEL(sparc_interrupt4m))
2566#if !defined(MSIIEP)          /* "normal" sun4m */
2567          sethi     %hi(CPUINFO_VA+CPUINFO_INTREG), %l6
2568          ld        [%l6 + %lo(CPUINFO_VA+CPUINFO_INTREG)], %l7
2569          mov       1, %l4
2570          ld        [%l7 + ICR_PI_PEND_OFFSET], %l5         ! get pending interrupts
2571          sll       %l4, %l3, %l4       ! hw intr bits are in the lower halfword
2572
2573          btst      %l4, %l5  ! has pending hw intr at this level?
2574          bnz       sparc_interrupt_common
2575           nop
2576
2577          ! both softint pending and clear bits are in upper halfwords of
2578          ! their respective registers so shift the test bit in %l4 up there
2579          sll       %l4, 16, %l4
2580
2581          st        %l4, [%l7 + ICR_PI_CLR_OFFSET]          ! ack soft intr
2582#if defined(MULTIPROCESSOR)
2583          cmp       %l3, 14
2584          be        lev14_softint
2585#endif
2586          /* Drain hw reg; might be necessary for Ross CPUs */
2587           ld       [%l7 + ICR_PI_PEND_OFFSET], %g0
2588
2589#ifdef DIAGNOSTIC
2590          btst      %l4, %l5  ! make sure softint pending bit is set
2591          bnz       softintr_common
2592          /* FALLTHROUGH to sparc_interrupt4m_bogus */
2593#else
2594          b         softintr_common
2595#endif
2596           nop
2597
2598#else /* MSIIEP */
2599          sethi     %hi(MSIIEP_PCIC_VA), %l6
2600          mov       1, %l4
2601          xor       %l3, 0x18, %l7      ! change endianness of the resulting bit mask
2602          ld        [%l6 + PCIC_PROC_IPR_REG], %l5 ! get pending interrupts
2603          sll       %l4, %l7, %l4       ! hw intr bits are in the upper halfword
2604                                        ! because the register is little-endian
2605          btst      %l4, %l5  ! has pending hw intr at this level?
2606          bnz       sparc_interrupt_common
2607           nop
2608
2609          srl       %l4, 16, %l4        ! move the mask bit into the lower 16 bit
2610                                        ! so we can use it to clear a sw interrupt
2611
2612#ifdef DIAGNOSTIC
2613          ! check if there's really a sw interrupt pending
2614          btst      %l4, %l5  ! make sure softint pending bit is set
2615          bnz       softintr_common
2616           sth      %l4, [%l6 + PCIC_SOFT_INTR_CLEAR_REG]
2617          /* FALLTHROUGH to sparc_interrupt4m_bogus */
2618#else
2619          b         softintr_common
2620           sth      %l4, [%l6 + PCIC_SOFT_INTR_CLEAR_REG]
2621#endif
2622
2623#endif /* MSIIEP */
2624
2625#ifdef DIAGNOSTIC
2626          /*
2627           * sparc_interrupt4m detected that neither hardware nor software
2628           * interrupt pending bit is set for this interrupt.  Report this
2629           * situation, this is most probably a symptom of a driver bug.
2630           */
2631sparc_interrupt4m_bogus:
2632          INTR_SETUP(-CCFSZ-80)
2633          std       %g2, [%sp + CCFSZ + 24]       ! save registers
2634          ! tally interrupt (curcpu()->cpu_data.cpu_nintr++) (clobbers %o0,%o1)
2635          INCR64X(CPUINFO_VA + CPUINFO_NINTR, %o0, %o1, %l7)
2636          mov       %g1, %l7
2637          rd        %y, %l6
2638          std       %g4, [%sp + CCFSZ + 32]
2639          andn      %l0, PSR_PIL, %l4   ! %l4 = psr & ~PSR_PIL |
2640          sll       %l3, 8, %l5                   !         intlev << IPLSHIFT
2641          std       %g6, [%sp + CCFSZ + 40]
2642          or        %l5, %l4, %l4                 !                             ;
2643          wr        %l4, 0, %psr                  ! the manual claims this
2644          wr        %l4, PSR_ET, %psr   ! song and dance is necessary
2645          std       %l0, [%sp + CCFSZ + 0]        ! set up intrframe/clockframe
2646          sll       %l3, 2, %l5
2647
2648          set       CPUINFO_VA + CPUINFO_INTRCNT, %l4       ! intrcnt[intlev].ev_count++;
2649          sll       %l3, EV_STRUCTSHIFT, %o2
2650          ldd       [%l4 + %o2], %o0
2651          std       %l2, [%sp + CCFSZ + 8]        ! set up intrframe/clockframe
2652          inccc   %o1
2653          addx    %o0, 0, %o0
2654          std       %o0, [%l4 + %o2]
2655
2656          st        %fp, [%sp + CCFSZ + 16]
2657
2658          /* Unhandled interrupts while cold cause IPL to be raised to `high' */
2659          sethi     %hi(_C_LABEL(cold)), %o0
2660          ld        [%o0 + %lo(_C_LABEL(cold))], %o0
2661          tst       %o0                           ! if (cold) {
2662          bnz,a     1f                            !         splhigh();
2663           or       %l0, 0xf00, %l0               ! } else
2664
2665          call      _C_LABEL(bogusintr) !         bogusintr(&intrframe)
2666           add      %sp, CCFSZ, %o0
2667          /* all done: restore registers and go return */
26681:
2669          mov       %l7, %g1
2670          wr        %l6, 0, %y
2671          ldd       [%sp + CCFSZ + 24], %g2
2672          ldd       [%sp + CCFSZ + 32], %g4
2673          ldd       [%sp + CCFSZ + 40], %g6
2674          b         return_from_trap
2675           wr       %l0, 0, %psr
2676#endif /* DIAGNOSTIC */
2677#endif /* SUN4M */
2678
2679_ENTRY(_C_LABEL(sparc_interrupt44c))
2680sparc_interrupt_common:
2681          INTR_SETUP(-CCFSZ-80)
2682          std       %g2, [%sp + CCFSZ + 24]       ! save registers
2683          ! tally intr (curcpu()->cpu_data.cpu_nintr++) (clobbers %o0,%o1)
2684          INCR64X(CPUINFO_VA + CPUINFO_NINTR, %o0, %o1, %l7)
2685          mov       %g1, %l7
2686          rd        %y, %l6
2687          std       %g4, [%sp + CCFSZ + 32]
2688          andn      %l0, PSR_PIL, %l4   ! %l4 = psr & ~PSR_PIL |
2689          sll       %l3, 8, %l5                   !         intlev << IPLSHIFT
2690          std       %g6, [%sp + CCFSZ + 40]
2691          or        %l5, %l4, %l4                 !                             ;
2692          wr        %l4, 0, %psr                  ! the manual claims this
2693          wr        %l4, PSR_ET, %psr   ! song and dance is necessary
2694          std       %l0, [%sp + CCFSZ + 0]        ! set up intrframe/clockframe
2695          sll       %l3, 2, %l5
2696
2697          set       CPUINFO_VA + CPUINFO_INTRCNT, %l4       ! intrcnt[intlev].ev_count++;
2698          sll       %l3, EV_STRUCTSHIFT, %o2
2699          ldd       [%l4 + %o2], %o0
2700          std       %l2, [%sp + CCFSZ + 8]        ! set up intrframe/clockframe
2701          inccc   %o1
2702          addx    %o0, 0, %o0
2703          std       %o0, [%l4 + %o2]
2704
2705          set       _C_LABEL(intrhand), %l4       ! %l4 = intrhand[intlev];
2706          ld        [%l4 + %l5], %l4
2707
2708          sethi     %hi(CPUINFO_VA+CPUINFO_IDEPTH), %o2
2709          ld        [ %o2 + %lo(CPUINFO_VA+CPUINFO_IDEPTH) ], %o3
2710          inc       %o3
2711          st        %o3, [ %o2 + %lo(CPUINFO_VA+CPUINFO_IDEPTH) ]
2712
2713          b         3f
2714           st       %fp, [%sp + CCFSZ + 16]
2715
27161:        ld        [%l4 + IH_CLASSIPL], %o2 ! ih->ih_classipl
2717          rd        %psr, %o3           !  (bits already shifted to PIL field)
2718          andn      %o3, PSR_PIL, %o3   ! %o3 = psr & ~PSR_PIL
2719          wr        %o3, %o2, %psr                ! splraise(ih->ih_classipl)
2720          ld        [%l4 + IH_FUN], %o1
2721          ld        [%l4 + IH_ARG], %o0
2722          nop                                     ! one more isns before touching ICC
2723          tst       %o0
2724          bz,a      2f
2725           add      %sp, CCFSZ, %o0
27262:        jmpl      %o1, %o7            !         handled = (*ih->ih_fun)(...)
2727           ld       [%l4 + IH_NEXT], %l4          !         and ih = ih->ih_next
2728          tst       %o0
2729          bnz       4f                            ! if (handled) break
2730           nop
27313:        tst       %l4
2732          bnz       1b                            ! while (ih)
2733           nop
2734
2735          /* Unhandled interrupts while cold cause IPL to be raised to `high' */
2736          sethi     %hi(_C_LABEL(cold)), %o0
2737          ld        [%o0 + %lo(_C_LABEL(cold))], %o0
2738          tst       %o0                           ! if (cold) {
2739          bnz,a     4f                            !         splhigh();
2740           or       %l0, 0xf00, %l0               ! } else
2741
2742          call      _C_LABEL(strayintr) !         strayintr(&intrframe)
2743           add      %sp, CCFSZ, %o0
2744          /* all done: restore registers and go return */
27454:
2746          sethi     %hi(CPUINFO_VA+CPUINFO_IDEPTH), %o2
2747          ld        [ %o2 + %lo(CPUINFO_VA+CPUINFO_IDEPTH) ], %o3
2748          dec       %o3
2749          st        %o3, [ %o2 + %lo(CPUINFO_VA+CPUINFO_IDEPTH) ]
2750
2751          mov       %l7, %g1
2752          wr        %l6, 0, %y
2753          ldd       [%sp + CCFSZ + 24], %g2
2754          ldd       [%sp + CCFSZ + 32], %g4
2755          ldd       [%sp + CCFSZ + 40], %g6
2756          b         return_from_trap
2757           wr       %l0, 0, %psr
2758
2759#if defined(MULTIPROCESSOR)
2760/*
2761 * Level 14 software interrupt: fast IPI
2762 * <%l0,%l1,%l2> = <psr, pc, npc>
2763 * %l3 = int level
2764 * %l6 = &cpuinfo
2765 */
2766lev14_softint:
2767          sethi     %hi(CPUINFO_VA+CPUINFO_LEV14), %l7
2768          ldd       [%l7 + %lo(CPUINFO_VA+CPUINFO_LEV14)], %l4
2769          inccc     %l5
2770          addx      %l4, %g0, %l4
2771          std       %l4, [%l7 + CPUINFO_LEV14]
2772
2773          sethi     %hi(CPUINFO_VA+CPUINFO_XMSG_TRAP), %l6
2774          ld        [%l6 + %lo(CPUINFO_VA+CPUINFO_XMSG_TRAP)], %l7
2775#ifdef DIAGNOSTIC
2776          tst       %l7
2777          bz        sparc_interrupt4m_bogus
2778           nop
2779#endif
2780          sethi     %hi(CPUINFO_VA+CPUINFO_XMSG_ARG0), %l6
2781          jmp       %l7
2782           ld       [%l6 + %lo(CPUINFO_VA+CPUINFO_XMSG_ARG0)], %l3    ! prefetch 1st arg
2783
2784/*
2785 * Fast flush handlers. xcalled from other CPUs throught soft interrupt 14
2786 * On entry:        %l6 = CPUINFO_VA
2787 *                  %l3 = first argument
2788 *
2789 * As always, these fast trap handlers should preserve all registers
2790 * except %l3 to %l7
2791 */
2792_ENTRY(_C_LABEL(ft_tlb_flush))
2793          !         <%l3 already fetched for us>  ! va
2794          sethi     %hi(CPUINFO_VA+CPUINFO_XMSG_ARG2), %l6
2795          ld        [%l6 + %lo(CPUINFO_VA+CPUINFO_XMSG_ARG2)], %l5    ! level
2796          andn      %l3, 0xfff, %l3                         ! %l3 = (va&~0xfff | lvl);
2797          sethi     %hi(CPUINFO_VA+CPUINFO_XMSG_ARG1), %l6
2798          ld        [%l6 + %lo(CPUINFO_VA+CPUINFO_XMSG_ARG1)], %l4    ! context
2799          or        %l3, %l5, %l3
2800
2801          mov       SRMMU_CXR, %l7                          !
2802          lda       [%l7]ASI_SRMMU, %l5           ! %l5 = old context
2803          sta       %l4, [%l7]ASI_SRMMU           ! set new context
2804
2805          sta       %g0, [%l3]ASI_SRMMUFP                   ! flush TLB
2806
2807ft_rett:
2808          ! common return from Fast Flush handlers
2809          ! enter here with %l5 = ctx to restore, %l6 = CPUINFO_VA, %l7 = ctx reg
2810          mov       1, %l4                                  !
2811          sta       %l5, [%l7]ASI_SRMMU           ! restore context
2812          sethi     %hi(CPUINFO_VA+CPUINFO_XMSG_CMPLT), %l6
2813          st        %l4, [%l6 + %lo(CPUINFO_VA+CPUINFO_XMSG_CMPLT)]   ! completed = 1
2814
2815          mov       %l0, %psr                     ! return from trap
2816           nop
2817          RETT
2818
2819_ENTRY(_C_LABEL(ft_srmmu_vcache_flush_page))
2820          !         <%l3 already fetched for us>  ! va
2821          sethi     %hi(CPUINFO_VA+CPUINFO_XMSG_ARG1), %l6
2822          ld        [%l6 + %lo(CPUINFO_VA+CPUINFO_XMSG_ARG1)], %l4    ! context
2823
2824          mov       SRMMU_CXR, %l7                          !
2825          lda       [%l7]ASI_SRMMU, %l5           ! %l5 = old context
2826          sta       %l4, [%l7]ASI_SRMMU           ! set new context
2827
2828          set       4096, %l4                     ! N = page size
2829          sethi     %hi(CPUINFO_VA+CPUINFO_CACHE_LINESZ), %l6
2830          ld        [%l6 + %lo(CPUINFO_VA+CPUINFO_CACHE_LINESZ)], %l7
28311:
2832          sta       %g0, [%l3]ASI_IDCACHELFP      !  flush cache line
2833          subcc     %l4, %l7, %l4                           !  p += linesz;
2834          bgu       1b                                      ! while ((N -= linesz) > 0)
2835           add      %l3, %l7, %l3
2836
2837          sethi     %hi(CPUINFO_VA+CPUINFO_XMSG_ARG0), %l6
2838          ld        [%l6 + %lo(CPUINFO_VA+CPUINFO_XMSG_ARG0)], %l3    ! reload va
2839          !or       %l3, ASI_SRMMUFP_L3(=0), %l3  ! va |= ASI_SRMMUFP_L3
2840          sta       %g0, [%l3]ASI_SRMMUFP                   ! flush TLB
2841
2842          b         ft_rett
2843           mov      SRMMU_CXR, %l7                          ! reload ctx register
2844
2845_ENTRY(_C_LABEL(ft_srmmu_vcache_flush_segment))
2846          !         <%l3 already fetched for us>  ! vr
2847          sethi     %hi(CPUINFO_VA+CPUINFO_XMSG_ARG1), %l6
2848          ld        [%l6 + %lo(CPUINFO_VA+CPUINFO_XMSG_ARG1)], %l5    ! vs
2849          sethi     %hi(CPUINFO_VA+CPUINFO_XMSG_ARG2), %l6
2850          ld        [%l6 + %lo(CPUINFO_VA+CPUINFO_XMSG_ARG2)], %l4    ! context
2851
2852          sll       %l3, 24, %l3                            ! va = VSTOVA(vr,vs)
2853          sll       %l5, 18, %l5
2854          or        %l3, %l5, %l3
2855
2856          mov       SRMMU_CXR, %l7                          !
2857          lda       [%l7]ASI_SRMMU, %l5           ! %l5 = old context
2858          sta       %l4, [%l7]ASI_SRMMU           ! set new context
2859
2860          sethi     %hi(CPUINFO_VA+CPUINFO_CACHE_NLINES), %l6
2861          ld        [%l6 + %lo(CPUINFO_VA+CPUINFO_CACHE_NLINES)], %l4
2862          sethi     %hi(CPUINFO_VA+CPUINFO_CACHE_LINESZ), %l6
2863          ld        [%l6 + %lo(CPUINFO_VA+CPUINFO_CACHE_LINESZ)], %l7
28641:
2865          sta       %g0, [%l3]ASI_IDCACHELFS      !  flush cache line
2866          deccc     %l4                                     !  p += linesz;
2867          bgu       1b                                      ! while (--nlines > 0)
2868           add      %l3, %l7, %l3
2869
2870          b         ft_rett
2871           mov      SRMMU_CXR, %l7                          ! reload ctx register
2872
2873_ENTRY(_C_LABEL(ft_srmmu_vcache_flush_region))
2874          !         <%l3 already fetched for us>  ! vr
2875          sethi     %hi(CPUINFO_VA+CPUINFO_XMSG_ARG1), %l6
2876          ld        [%l6 + %lo(CPUINFO_VA+CPUINFO_XMSG_ARG1)], %l4    ! context
2877
2878          sll       %l3, 24, %l3                            ! va = VRTOVA(vr)
2879
2880          mov       SRMMU_CXR, %l7                          !
2881          lda       [%l7]ASI_SRMMU, %l5           ! %l5 = old context
2882          sta       %l4, [%l7]ASI_SRMMU           ! set new context
2883
2884          sethi     %hi(CPUINFO_VA+CPUINFO_CACHE_NLINES), %l6
2885          ld        [%l6 + %lo(CPUINFO_VA+CPUINFO_CACHE_NLINES)], %l4
2886          sethi     %hi(CPUINFO_VA+CPUINFO_CACHE_LINESZ), %l6
2887          ld        [%l6 + %lo(CPUINFO_VA+CPUINFO_CACHE_LINESZ)], %l7
28881:
2889          sta       %g0, [%l3]ASI_IDCACHELFR      !  flush cache line
2890          deccc     %l4                                     !  p += linesz;
2891          bgu       1b                                      ! while (--nlines > 0)
2892           add      %l3, %l7, %l3
2893
2894          b         ft_rett
2895           mov      SRMMU_CXR, %l7                          ! reload ctx register
2896
2897_ENTRY(_C_LABEL(ft_srmmu_vcache_flush_context))
2898          !         <%l3 already fetched for us>  ! context
2899
2900          mov       SRMMU_CXR, %l7                          !
2901          lda       [%l7]ASI_SRMMU, %l5           ! %l5 = old context
2902          sta       %l3, [%l7]ASI_SRMMU           ! set new context
2903
2904          sethi     %hi(CPUINFO_VA+CPUINFO_CACHE_NLINES), %l6
2905          ld        [%l6 + %lo(CPUINFO_VA+CPUINFO_CACHE_NLINES)], %l4
2906          sethi     %hi(CPUINFO_VA+CPUINFO_CACHE_LINESZ), %l6
2907          ld        [%l6 + %lo(CPUINFO_VA+CPUINFO_CACHE_LINESZ)], %l7
2908          mov       %g0, %l3                      ! va = 0
29091:
2910          sta       %g0, [%l3]ASI_IDCACHELFC      !  flush cache line
2911          deccc     %l4                                     !  p += linesz;
2912          bgu       1b                                      ! while (--nlines > 0)
2913           add      %l3, %l7, %l3
2914
2915          b         ft_rett
2916           mov      SRMMU_CXR, %l7                          ! reload ctx register
2917
2918_ENTRY(_C_LABEL(ft_srmmu_vcache_flush_range))
2919          !         <%l3 already fetched for us>  ! va
2920          sethi     %hi(CPUINFO_VA+CPUINFO_XMSG_ARG2), %l6
2921          ld        [%l6 + %lo(CPUINFO_VA+CPUINFO_XMSG_ARG2)], %l4    ! context
2922
2923          mov       SRMMU_CXR, %l7                          !
2924          lda       [%l7]ASI_SRMMU, %l5           ! %l5 = old context
2925          sta       %l4, [%l7]ASI_SRMMU           ! set new context
2926
2927          sethi     %hi(CPUINFO_VA+CPUINFO_XMSG_ARG1), %l6
2928          ld        [%l6 + %lo(CPUINFO_VA+CPUINFO_XMSG_ARG1)], %l4    ! size
2929          and       %l3, 7, %l7                             ! double-word alignment
2930          andn      %l3, 7, %l3                             !  off = va & 7; va &= ~7
2931          add       %l4, %l7, %l4                           !  sz += off
2932
2933          sethi     %hi(CPUINFO_VA+CPUINFO_CACHE_LINESZ), %l6
2934          ld        [%l6 + %lo(CPUINFO_VA+CPUINFO_CACHE_LINESZ)], %l7
29351:
2936          sta       %g0, [%l3]ASI_IDCACHELFP      !  flush cache line
2937          subcc     %l4, %l7, %l4                           !  p += linesz;
2938          bgu       1b                                      ! while ((sz -= linesz) > 0)
2939           add      %l3, %l7, %l3
2940
2941          /* Flush TLB on all pages we visited */
2942          sethi     %hi(CPUINFO_VA+CPUINFO_XMSG_ARG0), %l6
2943          ld        [%l6 + %lo(CPUINFO_VA+CPUINFO_XMSG_ARG0)], %l3    ! reload va
2944          sethi     %hi(CPUINFO_VA+CPUINFO_XMSG_ARG1), %l6
2945          ld        [%l6 + %lo(CPUINFO_VA+CPUINFO_XMSG_ARG1)], %l4    ! reload sz
2946          add       %l3, %l4, %l4                           ! %l4 = round_page(va + sz)
2947          add       %l4, 0xfff, %l4
2948          andn      %l4, 0xfff, %l4
2949          andn      %l3, 0xfff, %l3                         ! va &= ~PGOFSET;
2950          sub       %l4, %l3, %l4                           ! and finally: size rounded
2951                                                            ! to page boundary
2952          set       4096, %l7                     ! page size
2953
29542:
2955          !or       %l3, ASI_SRMMUFP_L3(=0), %l3  !  va |= ASI_SRMMUFP_L3
2956          sta       %g0, [%l3]ASI_SRMMUFP                   !  flush TLB
2957          subcc     %l4, %l7, %l4                           ! while ((sz -= PGSIZE) > 0)
2958          bgu       2b
2959           add      %l3, %l7, %l3
2960
2961          b         ft_rett
2962           mov      SRMMU_CXR, %l7                          ! reload ctx register
2963
2964#endif /* MULTIPROCESSOR */
2965
2966#ifdef notyet
2967/*
2968 * Level 12 (ZS serial) interrupt.  Handle it quickly, schedule a
2969 * software interrupt, and get out.  Do the software interrupt directly
2970 * if we would just take it on the way out.
2971 *
2972 * Input:
2973 *        %l0 = %psr
2974 *        %l1 = return pc
2975 *        %l2 = return npc
2976 * Internal:
2977 *        %l3 = zs device
2978 *        %l4, %l5 = temporary
2979 *        %l6 = rr3 (or temporary data) + 0x100 => need soft int
2980 *        %l7 = zs soft status
2981 */
2982zshard:
2983#endif /* notyet */
2984
2985/*
2986 * Level 15 interrupt.  An async memory error has occurred;
2987 * take care of it (typically by panicking, but hey...).
2988 *        %l0 = %psr
2989 *        %l1 = return pc
2990 *        %l2 = return npc
2991 *        %l3 = 15 * 4 (why? just because!)
2992 *
2993 * Internal:
2994 *        %l4 = %y
2995 *        %l5 = %g1
2996 *        %l6 = %g6
2997 *        %l7 = %g7
2998 *  g2, g3, g4, g5 go to stack
2999 *
3000 * This code is almost the same as that in mem_access_fault,
3001 * except that we already know the problem is not a `normal' fault,
3002 * and that we must be extra-careful with interrupt enables.
3003 */
3004
3005#if defined(SUN4)
3006_ENTRY(_C_LABEL(nmi_sun4))
3007          INTR_SETUP(-CCFSZ-80)
3008          ! tally intr (curcpu()->cpu_data.cpu_nintr++) (clobbers %o0,%o1,%o2)
3009          INCR64(CPUINFO_VA + CPUINFO_NINTR)
3010          /*
3011           * Level 15 interrupts are nonmaskable, so with traps off,
3012           * disable all interrupts to prevent recursion.
3013           */
3014          sethi     %hi(INTRREG_VA), %o0
3015          ldub      [%o0 + %lo(INTRREG_VA)], %o1
3016          andn      %o1, IE_ALLIE, %o1
3017          stb       %o1, [%o0 + %lo(INTRREG_VA)]
3018          wr        %l0, PSR_ET, %psr   ! okay, turn traps on again
3019
3020          std       %g2, [%sp + CCFSZ + 0]        ! save g2, g3
3021          rd        %y, %l4                       ! save y
3022
3023          std       %g4, [%sp + CCFSZ + 8]        ! save g4, g5
3024          mov       %g1, %l5            ! save g1, g6, g7
3025          mov       %g6, %l6
3026          mov       %g7, %l7
3027#if defined(SUN4C) || defined(SUN4M)
3028          b,a       nmi_common
3029#endif /* SUN4C || SUN4M */
3030#endif
3031
3032#if defined(SUN4C)
3033_ENTRY(_C_LABEL(nmi_sun4c))
3034          INTR_SETUP(-CCFSZ-80)
3035          ! tally intr (curcpu()->cpu_data.cpu_nintr++) (clobbers %o0,%o1,%o2)
3036          INCR64(CPUINFO_VA + CPUINFO_NINTR)
3037          /*
3038           * Level 15 interrupts are nonmaskable, so with traps off,
3039           * disable all interrupts to prevent recursion.
3040           */
3041          sethi     %hi(INTRREG_VA), %o0
3042          ldub      [%o0 + %lo(INTRREG_VA)], %o1
3043          andn      %o1, IE_ALLIE, %o1
3044          stb       %o1, [%o0 + %lo(INTRREG_VA)]
3045          wr        %l0, PSR_ET, %psr   ! okay, turn traps on again
3046
3047          std       %g2, [%sp + CCFSZ + 0]        ! save g2, g3
3048          rd        %y, %l4                       ! save y
3049
3050          ! must read the sync error register too.
3051          set       AC_SYNC_ERR, %o0
3052          lda       [%o0] ASI_CONTROL, %o1        ! sync err reg
3053          inc       4, %o0
3054          lda       [%o0] ASI_CONTROL, %o2        ! sync virt addr
3055          std       %g4, [%sp + CCFSZ + 8]        ! save g4,g5
3056          mov       %g1, %l5            ! save g1,g6,g7
3057          mov       %g6, %l6
3058          mov       %g7, %l7
3059          inc       4, %o0
3060          lda       [%o0] ASI_CONTROL, %o3        ! async err reg
3061          inc       4, %o0
3062          lda       [%o0] ASI_CONTROL, %o4        ! async virt addr
3063#if defined(SUN4M)
3064          !!b,a     nmi_common
3065#endif /* SUN4M */
3066#endif /* SUN4C */
3067
3068_ENTRY(_C_LABEL(nmi_common))
3069          ! and call C code
3070          call      _C_LABEL(memerr4_4c)          ! memerr(0, ser, sva, aer, ava)
3071           clr      %o0
3072
3073          mov       %l5, %g1            ! restore g1 through g7
3074          ldd       [%sp + CCFSZ + 0], %g2
3075          ldd       [%sp + CCFSZ + 8], %g4
3076          wr        %l0, 0, %psr                  ! re-disable traps
3077          mov       %l6, %g6
3078          mov       %l7, %g7
3079
3080          ! set IE_ALLIE again (safe, we disabled traps again above)
3081          sethi     %hi(INTRREG_VA), %o0
3082          ldub      [%o0 + %lo(INTRREG_VA)], %o1
3083          or        %o1, IE_ALLIE, %o1
3084          stb       %o1, [%o0 + %lo(INTRREG_VA)]
3085          b         return_from_trap
3086           wr       %l4, 0, %y                    ! restore y
3087
3088#if defined(SUN4M)
3089_ENTRY(_C_LABEL(nmi_sun4m))
3090          INTR_SETUP(-CCFSZ-80-8-8)     ! normal frame, plus g2..g5
3091
3092#if !defined(MSIIEP) /* normal sun4m */
3093
3094          /* Read the Pending Interrupts register */
3095          sethi     %hi(CPUINFO_VA+CPUINFO_INTREG), %l6
3096          ld        [%l6 + %lo(CPUINFO_VA+CPUINFO_INTREG)], %l6
3097          ld        [%l6 + ICR_PI_PEND_OFFSET], %l5         ! get pending interrupts
3098
3099          set       _C_LABEL(nmi_soft), %o3                 ! assume a softint
3100          set       PINTR_IC, %o1                           ! hard lvl 15 bit
3101          sethi     %hi(PINTR_SINTRLEV(15)), %o0  ! soft lvl 15 bit
3102          btst      %o0, %l5            ! soft level 15?
3103          bnz,a     1f                            !
3104           mov      %o0, %o1            ! shift int clear bit to SOFTINT 15
3105
3106          set       _C_LABEL(nmi_hard), %o3       /* it's a hardint; switch handler */
3107
3108          /*
3109           * Level 15 interrupts are nonmaskable, so with traps off,
3110           * disable all interrupts to prevent recursion.
3111           */
3112          sethi     %hi(ICR_SI_SET), %o0
3113          set       SINTR_MA, %o2
3114          st        %o2, [%o0 + %lo(ICR_SI_SET)]
3115#if defined(MULTIPROCESSOR) && defined(DDB)
3116          b         2f
3117           clr      %o0
3118#endif
3119
31201:
3121#if defined(MULTIPROCESSOR) && defined(DDB)
3122          /*
3123           * Setup a trapframe for nmi_soft; this might be an IPI telling
3124           * us to pause, so lets save some state for DDB to get at.
3125           */
3126          std       %l0, [%sp + CCFSZ]  ! tf.tf_psr = psr; tf.tf_pc = ret_pc;
3127          rd        %y, %l3
3128          std       %l2, [%sp + CCFSZ + 8]        ! tf.tf_npc = return_npc; tf.tf_y = %y;
3129          st        %g1, [%sp + CCFSZ + 20]
3130          std       %g2, [%sp + CCFSZ + 24]
3131          std       %g4, [%sp + CCFSZ + 32]
3132          std       %g6, [%sp + CCFSZ + 40]
3133          std       %i0, [%sp + CCFSZ + 48]
3134          std       %i2, [%sp + CCFSZ + 56]
3135          std       %i4, [%sp + CCFSZ + 64]
3136          std       %i6, [%sp + CCFSZ + 72]
3137          add       %sp, CCFSZ, %o0
31382:
3139#else
3140          clr       %o0
3141#endif
3142          /*
3143           * Now clear the NMI. Apparently, we must allow some time
3144           * to let the bits sink in..
3145           */
3146          st        %o1, [%l6 + ICR_PI_CLR_OFFSET]
3147           nop; nop; nop;
3148          ld        [%l6 + ICR_PI_PEND_OFFSET], %g0         ! drain register!?
3149           nop;
3150
3151          or        %l0, PSR_PIL, %o4   ! splhigh()
3152          wr        %o4, 0, %psr                  !
3153          wr        %o4, PSR_ET, %psr   ! turn traps on again
3154
3155          std       %g2, [%sp + CCFSZ + 80]       ! save g2, g3
3156          rd        %y, %l4                       ! save y
3157          std       %g4, [%sp + CCFSZ + 88]       ! save g4,g5
3158
3159          /* Finish stackframe, call C trap handler */
3160          mov       %g1, %l5            ! save g1,g6,g7
3161          mov       %g6, %l6
3162
3163          jmpl      %o3, %o7            ! nmi_hard(0) or nmi_soft(&tf)
3164           mov      %g7, %l7
3165
3166          mov       %l5, %g1            ! restore g1 through g7
3167          ldd       [%sp + CCFSZ + 80], %g2
3168          ldd       [%sp + CCFSZ + 88], %g4
3169          wr        %l0, 0, %psr                  ! re-disable traps
3170          mov       %l6, %g6
3171          mov       %l7, %g7
3172
3173          !cmp      %o0, 0                        ! was this a soft nmi
3174          !be       4f
3175          /* XXX - we need to unblock `mask all ints' only on a hard nmi */
3176
3177          ! enable interrupts again (safe, we disabled traps again above)
3178          sethi     %hi(ICR_SI_CLR), %o0
3179          set       SINTR_MA, %o1
3180          st        %o1, [%o0 + %lo(ICR_SI_CLR)]
3181
31824:
3183          b         return_from_trap
3184           wr       %l4, 0, %y                    ! restore y
3185
3186#else /* MSIIEP*/
3187          sethi     %hi(MSIIEP_PCIC_VA), %l6
3188
3189          /* Read the Processor Interrupt Pending register */
3190          ld        [%l6 + PCIC_PROC_IPR_REG], %l5
3191
3192          /*
3193           * Level 15 interrupts are nonmaskable, so with traps off,
3194           * disable all interrupts to prevent recursion.
3195           */
3196          mov       0x80, %l4 ! htole32(MSIIEP_SYS_ITMR_ALL)
3197          st        %l4, [%l6 + PCIC_SYS_ITMR_SET_REG]
3198
3199          set       (1 << 23), %l4      ! htole32(1 << 15)
3200          btst      %l4, %l5  ! has pending level 15 hw intr?
3201          bz        1f
3202           nop
3203
3204          /* hard level 15 interrupt */
3205          sethi     %hi(_C_LABEL(nmi_hard_msiiep)), %o3
3206          b         2f
3207           or       %o3, %lo(_C_LABEL(nmi_hard_msiiep)), %o3
3208
32091:        /* soft level 15 interrupt */
3210          set       (1 << 7), %l4       ! htole16(1 << 15)
3211          sth       %l4, [%l6 + PCIC_SOFT_INTR_CLEAR_REG]
3212          set       _C_LABEL(nmi_soft_msiiep), %o3
32132:
3214
3215          /* XXX:   call sequence is identical to sun4m case above. merge? */
3216          or        %l0, PSR_PIL, %o4   ! splhigh()
3217          wr        %o4, 0, %psr                  !
3218          wr        %o4, PSR_ET, %psr   ! turn traps on again
3219
3220          std       %g2, [%sp + CCFSZ + 80]       ! save g2, g3
3221          rd        %y, %l4                       ! save y
3222          std       %g4, [%sp + CCFSZ + 88]       ! save g4, g5
3223
3224          /* Finish stackframe, call C trap handler */
3225          mov       %g1, %l5            ! save g1, g6, g7
3226          mov       %g6, %l6
3227
3228          call      %o3                           ! nmi_hard(0) or nmi_soft(&tf)
3229           mov      %g7, %l7
3230
3231          mov       %l5, %g1            ! restore g1 through g7
3232          ldd       [%sp + CCFSZ + 80], %g2
3233          ldd       [%sp + CCFSZ + 88], %g4
3234          wr        %l0, 0, %psr                  ! re-disable traps
3235          mov       %l6, %g6
3236          mov       %l7, %g7
3237
3238          ! enable interrupts again (safe, we disabled traps again above)
3239          sethi     %hi(MSIIEP_PCIC_VA), %o0
3240          mov       0x80, %o1 ! htole32(MSIIEP_SYS_ITMR_ALL)
3241          st        %o1, [%o0 + PCIC_SYS_ITMR_CLR_REG]
3242
3243          b         return_from_trap
3244           wr       %l4, 0, %y                    ! restore y
3245#endif /* MSIIEP */
3246#endif /* SUN4M */
3247
3248
3249#ifdef GPROF
3250          .globl    window_of, winof_user
3251          .globl    window_uf, winuf_user, winuf_ok, winuf_invalid
3252          .globl    return_from_trap, rft_kernel, rft_user, rft_invalid
3253          .globl    softtrap, slowtrap
3254          .globl    clean_trap_window, _C_LABEL(_syscall)
3255#endif
3256
3257/*
3258 * Window overflow trap handler.
3259 *        %l0 = %psr
3260 *        %l1 = return pc
3261 *        %l2 = return npc
3262 */
3263window_of:
3264#ifdef TRIVIAL_WINDOW_OVERFLOW_HANDLER
3265          /* a trivial version that assumes %sp is ok */
3266          /* (for testing only!) */
3267          save      %g0, %g0, %g0
3268          std       %l0, [%sp + (0*8)]
3269          rd        %psr, %l0
3270          mov       1, %l1
3271          sll       %l1, %l0, %l0
3272          wr        %l0, 0, %wim
3273          std       %l2, [%sp + (1*8)]
3274          std       %l4, [%sp + (2*8)]
3275          std       %l6, [%sp + (3*8)]
3276          std       %i0, [%sp + (4*8)]
3277          std       %i2, [%sp + (5*8)]
3278          std       %i4, [%sp + (6*8)]
3279          std       %i6, [%sp + (7*8)]
3280          restore
3281          RETT
3282#else
3283          /*
3284           * This is similar to TRAP_SETUP, but we do not want to spend
3285           * a lot of time, so we have separate paths for kernel and user.
3286           * We also know for sure that the window has overflowed.
3287           */
3288          TRAP_TRACE2(5,%l6,%l5)
3289          btst      PSR_PS, %l0
3290          bz        winof_user
3291           sethi    %hi(clean_trap_window), %l7
3292
3293          /*
3294           * Overflow from kernel mode.  Call clean_trap_window to
3295           * do the dirty work, then just return, since we know prev
3296           * window is valid.  clean_trap_windows might dump all *user*
3297           * windows into the pcb, but we do not care: there is at
3298           * least one kernel window (a trap or interrupt frame!)
3299           * above us.
3300           */
3301          jmpl      %l7 + %lo(clean_trap_window), %l4
3302           mov      %g7, %l7            ! for clean_trap_window
3303
3304          wr        %l0, 0, %psr                  ! put back the @%*! cond. codes
3305          nop                                     ! (let them settle in)
3306          RETT
3307
3308winof_user:
3309          /*
3310           * Overflow from user mode.
3311           * If clean_trap_window dumps the registers into the pcb,
3312           * rft_user will need to call trap(), so we need space for
3313           * a trap frame.  We also have to compute pcb_nw.
3314           *
3315           * SHOULD EXPAND IN LINE TO AVOID BUILDING TRAP FRAME ON
3316           * `EASY' SAVES
3317           */
3318          sethi     %hi(cpcb), %l6
3319          ld        [%l6 + %lo(cpcb)], %l6
3320          ld        [%l6 + PCB_WIM], %l5
3321          and       %l0, 31, %l3
3322          sub       %l3, %l5, %l5                 /* l5 = CWP - pcb_wim */
3323          set       uwtab, %l4
3324          ldub      [%l4 + %l5], %l5    /* l5 = uwtab[l5] */
3325          st        %l5, [%l6 + PCB_UW]
3326          jmpl      %l7 + %lo(clean_trap_window), %l4
3327           mov      %g7, %l7            ! for clean_trap_window
3328          sethi     %hi(cpcb), %l6
3329          ld        [%l6 + %lo(cpcb)], %l6
3330          set       USPACE-CCFSZ-80, %l5
3331          add       %l6, %l5, %sp                 /* over to kernel stack */
3332          CHECK_SP_REDZONE(%l6, %l5)
3333
3334          /*
3335           * Copy return_from_trap far enough to allow us
3336           * to jump directly to rft_user_or_recover_pcb_windows
3337           * (since we know that is where we are headed).
3338           */
3339!         and       %l0, 31, %l3                  ! still set (clean_trap_window
3340                                                  ! leaves this register alone)
3341          set       wmask, %l6
3342          ldub      [%l6 + %l3], %l5    ! %l5 = 1 << ((CWP + 1) % nwindows)
3343          b         rft_user_or_recover_pcb_windows
3344           rd       %wim, %l4           ! (read %wim first)
3345#endif /* end `real' version of window overflow trap handler */
3346
3347/*
3348 * Window underflow trap handler.
3349 *        %l0 = %psr
3350 *        %l1 = return pc
3351 *        %l2 = return npc
3352 *
3353 * A picture:
3354 *
3355 *          T R I X
3356 *        0 0 0 1 0 0 0       (%wim)
3357 * [bit numbers increase towards the right;
3358 * `restore' moves right & `save' moves left]
3359 *
3360 * T is the current (Trap) window, R is the window that attempted
3361 * a `Restore' instruction, I is the Invalid window, and X is the
3362 * window we want to make invalid before we return.
3363 *
3364 * Since window R is valid, we cannot use rft_user to restore stuff
3365 * for us.  We have to duplicate its logic.  YUCK.
3366 *
3367 * Incidentally, TRIX are for kids.  Silly rabbit!
3368 */
3369window_uf:
3370#ifdef TRIVIAL_WINDOW_UNDERFLOW_HANDLER
3371          wr        %g0, 0, %wim                  ! allow us to enter I
3372          restore                                 ! to R
3373          nop
3374          nop
3375          restore                                 ! to I
3376          restore   %g0, 1, %l1                   ! to X
3377          rd        %psr, %l0
3378          sll       %l1, %l0, %l0
3379          wr        %l0, 0, %wim
3380          save      %g0, %g0, %g0                 ! back to I
3381          LOADWIN(%sp)
3382          save      %g0, %g0, %g0                 ! back to R
3383          save      %g0, %g0, %g0                 ! back to T
3384          RETT
3385#else
3386          TRAP_TRACE2(6,%l6,%l5)
3387          wr        %g0, 0, %wim                  ! allow us to enter I
3388          btst      PSR_PS, %l0
3389          restore                                 ! enter window R
3390          bz        winuf_user
3391           restore                      ! enter window I
3392
3393          /*
3394           * Underflow from kernel mode.  Just recover the
3395           * registers and go (except that we have to update
3396           * the blasted user pcb fields).
3397           */
3398          restore   %g0, 1, %l1                   ! enter window X, then set %l1 to 1
3399          rd        %psr, %l0           ! cwp = %psr & 31;
3400          and       %l0, 31, %l0
3401          sll       %l1, %l0, %l1                 ! wim = 1 << cwp;
3402          wr        %l1, 0, %wim                  ! setwim(wim);
3403          sethi     %hi(cpcb), %l1
3404          ld        [%l1 + %lo(cpcb)], %l1
3405          st        %l0, [%l1 + PCB_WIM]          ! cpcb->pcb_wim = cwp;
3406          save      %g0, %g0, %g0                 ! back to window I
3407          LOADWIN(%sp)
3408          save      %g0, %g0, %g0                 ! back to R
3409          save      %g0, %g0, %g0                 ! and then to T
3410          wr        %l0, 0, %psr                  ! fix those cond codes....
3411          nop                                     ! (let them settle in)
3412          RETT
3413
3414winuf_user:
3415          /*
3416           * Underflow from user mode.
3417           *
3418           * We cannot use rft_user (as noted above) because
3419           * we must re-execute the `restore' instruction.
3420           * Since it could be, e.g., `restore %l0,0,%l0',
3421           * it is not okay to touch R's registers either.
3422           *
3423           * We are now in window I.
3424           */
3425          btst      7, %sp                        ! if unaligned, it is invalid
3426          bne       winuf_invalid
3427           .empty
3428
3429          sethi     %hi(_C_LABEL(pgofset)), %l4
3430          ld        [%l4 + %lo(_C_LABEL(pgofset))], %l4
3431          PTE_OF_ADDR(%sp, %l7, winuf_invalid, %l4, NOP_ON_4M_5)
3432          CMP_PTE_USER_READ(%l7, %l5, NOP_ON_4M_6) ! if first page not readable,
3433          bne       winuf_invalid                 ! it is invalid
3434           .empty
3435          SLT_IF_1PAGE_RW(%sp, %l7, %l4)          ! first page is readable
3436          bl,a      winuf_ok            ! if only one page, enter window X
3437           restore %g0, 1, %l1                    ! and goto ok, & set %l1 to 1
3438          add       %sp, 7*8, %l5
3439          add     %l4, 62, %l4
3440          PTE_OF_ADDR(%l5, %l7, winuf_invalid, %l4, NOP_ON_4M_7)
3441          CMP_PTE_USER_READ(%l7, %l5, NOP_ON_4M_8) ! check second page too
3442          be,a      winuf_ok            ! enter window X and goto ok
3443           restore %g0, 1, %l1                    ! (and then set %l1 to 1)
3444
3445winuf_invalid:
3446          /*
3447           * We were unable to restore the window because %sp
3448           * is invalid or paged out.  Return to the trap window
3449           * and call trap(T_WINUF).  This will save R to the user
3450           * stack, then load both R and I into the pcb rw[] area,
3451           * and return with pcb_nsaved set to -1 for success, 0 for
3452           * failure.  `Failure' indicates that someone goofed with the
3453           * trap registers (e.g., signals), so that we need to return
3454           * from the trap as from a syscall (probably to a signal handler)
3455           * and let it retry the restore instruction later.  Note that
3456           * window R will have been pushed out to user space, and thus
3457           * be the invalid window, by the time we get back here.  (We
3458           * continue to label it R anyway.)  We must also set %wim again,
3459           * and set pcb_uw to 1, before enabling traps.  (Window R is the
3460           * only window, and it is a user window).
3461           */
3462          save      %g0, %g0, %g0                 ! back to R
3463          save      %g0, 1, %l4                   ! back to T, then %l4 = 1
3464          sethi     %hi(cpcb), %l6
3465          ld        [%l6 + %lo(cpcb)], %l6
3466          st        %l4, [%l6 + PCB_UW] ! pcb_uw = 1
3467          ld        [%l6 + PCB_WIM], %l5          ! get log2(%wim)
3468          sll       %l4, %l5, %l4                 ! %l4 = old %wim
3469          wr        %l4, 0, %wim                  ! window I is now invalid again
3470          set       USPACE-CCFSZ-80, %l5
3471          add       %l6, %l5, %sp                 ! get onto kernel stack
3472          CHECK_SP_REDZONE(%l6, %l5)
3473
3474          /*
3475           * Okay, call trap(T_WINUF, psr, pc, &tf).
3476           * See `slowtrap' above for operation.
3477           */
3478          wr        %l0, PSR_ET, %psr
3479          std       %l0, [%sp + CCFSZ + 0]        ! tf.tf_psr, tf.tf_pc
3480          rd        %y, %l3
3481          std       %l2, [%sp + CCFSZ + 8]        ! tf.tf_npc, tf.tf_y
3482          mov       T_WINUF, %o0
3483          st        %g1, [%sp + CCFSZ + 20]       ! tf.tf_global[1]
3484          mov       %l0, %o1
3485          std       %g2, [%sp + CCFSZ + 24]       ! etc
3486          mov       %l1, %o2
3487          std       %g4, [%sp + CCFSZ + 32]
3488          add       %sp, CCFSZ, %o3
3489          std       %g6, [%sp + CCFSZ + 40]
3490          std       %i0, [%sp + CCFSZ + 48]       ! tf.tf_out[0], etc
3491          std       %i2, [%sp + CCFSZ + 56]
3492          std       %i4, [%sp + CCFSZ + 64]
3493          call      _C_LABEL(trap)                ! trap(T_WINUF, pc, psr, &tf)
3494           std      %i6, [%sp + CCFSZ + 72]       ! tf.tf_out[6]
3495
3496          ldd       [%sp + CCFSZ + 0], %l0        ! new psr, pc
3497          ldd       [%sp + CCFSZ + 8], %l2        ! new npc, %y
3498          wr        %l3, 0, %y
3499          ld        [%sp + CCFSZ + 20], %g1
3500          ldd       [%sp + CCFSZ + 24], %g2
3501          ldd       [%sp + CCFSZ + 32], %g4
3502          ldd       [%sp + CCFSZ + 40], %g6
3503          ldd       [%sp + CCFSZ + 48], %i0       ! %o0 for window R, etc
3504          ldd       [%sp + CCFSZ + 56], %i2
3505          ldd       [%sp + CCFSZ + 64], %i4
3506          wr        %l0, 0, %psr                  ! disable traps: test must be atomic
3507          ldd       [%sp + CCFSZ + 72], %i6
3508          sethi     %hi(cpcb), %l6
3509          ld        [%l6 + %lo(cpcb)], %l6
3510          ld        [%l6 + PCB_NSAVED], %l7       ! if nsaved is -1, we have our regs
3511          tst       %l7
3512          bl,a      1f                            ! got them
3513           wr       %g0, 0, %wim                  ! allow us to enter windows R, I
3514          b,a       return_from_trap
3515
3516          /*
3517           * Got 'em.  Load 'em up.
3518           */
35191:
3520          mov       %g6, %l3            ! save %g6; set %g6 = cpcb
3521          mov       %l6, %g6
3522          st        %g0, [%g6 + PCB_NSAVED]       ! and clear magic flag
3523          restore                                 ! from T to R
3524          restore                                 ! from R to I
3525          restore   %g0, 1, %l1                   ! from I to X, then %l1 = 1
3526          rd        %psr, %l0           ! cwp = %psr;
3527          sll       %l1, %l0, %l1
3528          wr        %l1, 0, %wim                  ! make window X invalid
3529          and       %l0, 31, %l0
3530          st        %l0, [%g6 + PCB_WIM]          ! cpcb->pcb_wim = cwp;
3531          nop                                     ! unnecessary? old wim was 0...
3532          save      %g0, %g0, %g0                 ! back to I
3533          LOADWIN(%g6 + PCB_RW + 64)    ! load from rw[1]
3534          save      %g0, %g0, %g0                 ! back to R
3535          LOADWIN(%g6 + PCB_RW)                   ! load from rw[0]
3536          save      %g0, %g0, %g0                 ! back to T
3537          wr        %l0, 0, %psr                  ! restore condition codes
3538          mov       %l3, %g6            ! fix %g6
3539          RETT
3540
3541          /*
3542           * Restoring from user stack, but everything has checked out
3543           * as good.  We are now in window X, and %l1 = 1.  Window R
3544           * is still valid and holds user values.
3545           */
3546winuf_ok:
3547          rd        %psr, %l0
3548          sll       %l1, %l0, %l1
3549          wr        %l1, 0, %wim                  ! make this one invalid
3550          sethi     %hi(cpcb), %l2
3551          ld        [%l2 + %lo(cpcb)], %l2
3552          and       %l0, 31, %l0
3553          st        %l0, [%l2 + PCB_WIM]          ! cpcb->pcb_wim = cwp;
3554          save      %g0, %g0, %g0                 ! back to I
3555          LOADWIN(%sp)
3556          save      %g0, %g0, %g0                 ! back to R
3557          save      %g0, %g0, %g0                 ! back to T
3558          wr        %l0, 0, %psr                  ! restore condition codes
3559          nop                                     ! it takes three to tangle
3560          RETT
3561#endif /* end `real' version of window underflow trap handler */
3562
3563/*
3564 * Various return-from-trap routines (see return_from_trap).
3565 */
3566
3567/*
3568 * Return from trap, to kernel.
3569 *        %l0 = %psr
3570 *        %l1 = return pc
3571 *        %l2 = return npc
3572 *        %l4 = %wim
3573 *        %l5 = bit for previous window
3574 */
3575rft_kernel:
3576          btst      %l5, %l4            ! if (wim & l5)
3577          bnz       1f                            !         goto reload;
3578           wr       %l0, 0, %psr                  ! but first put !@#*% cond codes back
3579
3580          /* previous window is valid; just rett */
3581          nop                                     ! wait for cond codes to settle in
3582          RETT
3583
3584          /*
3585           * Previous window is invalid.
3586           * Update %wim and then reload l0..i7 from frame.
3587           *
3588           *          T I X
3589           *        0 0 1 0 0   (%wim)
3590           * [see picture in window_uf handler]
3591           *
3592           * T is the current (Trap) window, I is the Invalid window,
3593           * and X is the window we want to make invalid.  Window X
3594           * currently has no useful values.
3595           */
35961:
3597          wr        %g0, 0, %wim                  ! allow us to enter window I
3598          nop; nop; nop                           ! (it takes a while)
3599          restore                                 ! enter window I
3600          restore   %g0, 1, %l1                   ! enter window X, then %l1 = 1
3601          rd        %psr, %l0           ! CWP = %psr & 31;
3602          and       %l0, 31, %l0
3603          sll       %l1, %l0, %l1                 ! wim = 1 << CWP;
3604          wr        %l1, 0, %wim                  ! setwim(wim);
3605          sethi     %hi(cpcb), %l1
3606          ld        [%l1 + %lo(cpcb)], %l1
3607          st        %l0, [%l1 + PCB_WIM]          ! cpcb->pcb_wim = l0 & 31;
3608          save      %g0, %g0, %g0                 ! back to window I
3609          LOADWIN(%sp)
3610          save      %g0, %g0, %g0                 ! back to window T
3611          /*
3612           * Note that the condition codes are still set from
3613           * the code at rft_kernel; we can simply return.
3614           */
3615          RETT
3616
3617/*
3618 * Return from trap, to user.  Checks for scheduling trap (`ast') first;
3619 * will re-enter trap() if set.  Note that we may have to switch from
3620 * the interrupt stack to the kernel stack in this case.
3621 *        %l0 = %psr
3622 *        %l1 = return pc
3623 *        %l2 = return npc
3624 *        %l4 = %wim
3625 *        %l5 = bit for previous window
3626 *        %l6 = cpcb
3627 * If returning to a valid window, just set psr and return.
3628 */
3629rft_user:
3630!         sethi     %hi(_WANT_AST)), %l7          ! (done below)
3631          ld        [%l7 + %lo(_WANT_AST)], %l7
3632          tst       %l7                           ! want AST trap?
3633          bne,a     softtrap            ! yes, re-enter trap with type T_AST
3634           mov      T_AST, %o0
3635
3636          btst      %l5, %l4            ! if (wim & l5)
3637          bnz       1f                            !         goto reload;
3638           wr       %l0, 0, %psr                  ! restore cond codes
3639          nop                                     ! (three instruction delay)
3640          RETT
3641
3642          /*
3643           * Previous window is invalid.
3644           * Before we try to load it, we must verify its stack pointer.
3645           * This is much like the underflow handler, but a bit easier
3646           * since we can use our own local registers.
3647           */
36481:
3649          btst      7, %fp                        ! if unaligned, address is invalid
3650          bne       rft_invalid
3651           .empty
3652
3653          sethi     %hi(_C_LABEL(pgofset)), %l3
3654          ld        [%l3 + %lo(_C_LABEL(pgofset))], %l3
3655          PTE_OF_ADDR(%fp, %l7, rft_invalid, %l3, NOP_ON_4M_9)
3656          CMP_PTE_USER_READ(%l7, %l5, NOP_ON_4M_10)         ! try first page
3657          bne       rft_invalid                   ! no good
3658           .empty
3659          SLT_IF_1PAGE_RW(%fp, %l7, %l3)
3660          bl,a      rft_user_ok                   ! only 1 page: ok
3661           wr       %g0, 0, %wim
3662          add       %fp, 7*8, %l5
3663          add       %l3, 62, %l3
3664          PTE_OF_ADDR(%l5, %l7, rft_invalid, %l3, NOP_ON_4M_11)
3665          CMP_PTE_USER_READ(%l7, %l5, NOP_ON_4M_12)         ! check 2nd page too
3666          be,a      rft_user_ok
3667           wr       %g0, 0, %wim
3668
3669          /*
3670           * The window we wanted to pull could not be pulled.  Instead,
3671           * re-enter trap with type T_RWRET.  This will pull the window
3672           * into cpcb->pcb_rw[0] and set cpcb->pcb_nsaved to -1, which we
3673           * will detect when we try to return again.
3674           */
3675rft_invalid:
3676          b         softtrap
3677           mov      T_RWRET, %o0
3678
3679          /*
3680           * The window we want to pull can be pulled directly.
3681           */
3682rft_user_ok:
3683!         wr        %g0, 0, %wim                  ! allow us to get into it
3684          wr        %l0, 0, %psr                  ! fix up the cond codes now
3685          nop; nop; nop
3686          restore                                 ! enter window I
3687          restore   %g0, 1, %l1                   ! enter window X, then %l1 = 1
3688          rd        %psr, %l0           ! l0 = (junk << 5) + CWP;
3689          sll       %l1, %l0, %l1                 ! %wim = 1 << CWP;
3690          wr        %l1, 0, %wim
3691          sethi     %hi(cpcb), %l1
3692          ld        [%l1 + %lo(cpcb)], %l1
3693          and       %l0, 31, %l0
3694          st        %l0, [%l1 + PCB_WIM]          ! cpcb->pcb_wim = l0 & 31;
3695          save      %g0, %g0, %g0                 ! back to window I
3696          LOADWIN(%sp)                            ! suck hard
3697          save      %g0, %g0, %g0                 ! back to window T
3698          RETT
3699
3700/*
3701 * Return from trap.  Entered after a
3702 *        wr        %l0, 0, %psr
3703 * which disables traps so that we can rett; registers are:
3704 *
3705 *        %l0 = %psr
3706 *        %l1 = return pc
3707 *        %l2 = return npc
3708 *
3709 * (%l3..%l7 anything).
3710 *
3711 * If we are returning to user code, we must:
3712 *  1.  Check for register windows in the pcb that belong on the stack.
3713 *        If there are any, reenter trap with type T_WINOF.
3714 *  2.  Make sure the register windows will not underflow.  This is
3715 *        much easier in kernel mode....
3716 */
3717return_from_trap:
3718!         wr        %l0, 0, %psr                  ! disable traps so we can rett
3719! (someone else did this already)
3720          and       %l0, 31, %l5
3721          set       wmask, %l6
3722          ldub      [%l6 + %l5], %l5    ! %l5 = 1 << ((CWP + 1) % nwindows)
3723          btst      PSR_PS, %l0                   ! returning to userland?
3724          bnz       rft_kernel                    ! no, go return to kernel
3725           rd       %wim, %l4           ! (read %wim in any case)
3726
3727rft_user_or_recover_pcb_windows:
3728          /*
3729           * (entered with %l4=%wim, %l5=wmask[cwp]; %l0..%l2 as usual)
3730           *
3731           * check cpcb->pcb_nsaved:
3732           * if 0, do a `normal' return to user (see rft_user);
3733           * if > 0, cpcb->pcb_rw[] holds registers to be copied to stack;
3734           * if -1, cpcb->pcb_rw[0] holds user registers for rett window
3735           * from an earlier T_RWRET pseudo-trap.
3736           */
3737          sethi     %hi(cpcb), %l6
3738          ld        [%l6 + %lo(cpcb)], %l6
3739          ld        [%l6 + PCB_NSAVED], %l7
3740          tst       %l7
3741          bz,a      rft_user
3742           sethi    %hi(_WANT_AST), %l7 ! first instr of rft_user
3743
3744          bg,a      softtrap            ! if (pcb_nsaved > 0)
3745           mov      T_WINOF, %o0                  !         trap(T_WINOF);
3746
3747          /*
3748           * To get here, we must have tried to return from a previous
3749           * trap and discovered that it would cause a window underflow.
3750           * We then must have tried to pull the registers out of the
3751           * user stack (from the address in %fp==%i6) and discovered
3752           * that it was either unaligned or not loaded in memory, and
3753           * therefore we ran a trap(T_RWRET), which loaded one set of
3754           * registers into cpcb->pcb_pcb_rw[0] (if it had killed the
3755           * process due to a bad stack, we would not be here).
3756           *
3757           * We want to load pcb_rw[0] into the previous window, which
3758           * we know is currently invalid.  In other words, we want
3759           * %wim to be 1 << ((cwp + 2) % nwindows).
3760           */
3761          wr        %g0, 0, %wim                  ! enable restores
3762          mov       %g6, %l3            ! save g6 in l3
3763          mov       %l6, %g6            ! set g6 = &u
3764          st        %g0, [%g6 + PCB_NSAVED]       ! clear cpcb->pcb_nsaved
3765          restore                                 ! enter window I
3766          restore   %g0, 1, %l1                   ! enter window X, then %l1 = 1
3767          rd        %psr, %l0
3768          sll       %l1, %l0, %l1                 ! %wim = 1 << CWP;
3769          wr        %l1, 0, %wim
3770          and       %l0, 31, %l0
3771          st        %l0, [%g6 + PCB_WIM]          ! cpcb->pcb_wim = CWP;
3772          nop                                     ! unnecessary? old wim was 0...
3773          save      %g0, %g0, %g0                 ! back to window I
3774          LOADWIN(%g6 + PCB_RW)
3775          save      %g0, %g0, %g0                 ! back to window T (trap window)
3776          wr        %l0, 0, %psr                  ! cond codes, cond codes everywhere
3777          mov       %l3, %g6            ! restore g6
3778          RETT
3779
3780! exported end marker for kernel gdb
3781          .globl    _C_LABEL(endtrapcode)
3782_C_LABEL(endtrapcode):
3783
3784/*
3785 * init_tables(nwin) int nwin;
3786 *
3787 * Set up the uwtab and wmask tables.
3788 * We know nwin > 1.
3789 */
3790init_tables:
3791          /*
3792           * for (i = -nwin, j = nwin - 2; ++i < 0; j--)
3793           *        uwtab[i] = j;
3794           * (loop runs at least once)
3795           */
3796          set       uwtab, %o3
3797          sub       %g0, %o0, %o1                 ! i = -nwin + 1
3798          inc       %o1
3799          add       %o0, -2, %o2                  ! j = nwin - 2;
38000:
3801          stb       %o2, [%o3 + %o1]    ! uwtab[i] = j;
38021:
3803          inccc     %o1                           ! ++i < 0?
3804          bl        0b                            ! yes, continue loop
3805           dec      %o2                           ! in any case, j--
3806
3807          /*
3808           * (i now equals 0)
3809           * for (j = nwin - 1; i < nwin; i++, j--)
3810           *        uwtab[i] = j;
3811           * (loop runs at least twice)
3812           */
3813          sub       %o0, 1, %o2                   ! j = nwin - 1
38140:
3815          stb       %o2, [%o3 + %o1]    ! uwtab[i] = j
3816          inc       %o1                           ! i++
38171:
3818          cmp       %o1, %o0            ! i < nwin?
3819          bl        0b                            ! yes, continue
3820           dec      %o2                           ! in any case, j--
3821
3822          /*
3823           * We observe that, for i in 0..nwin-2, (i+1)%nwin == i+1;
3824           * for i==nwin-1, (i+1)%nwin == 0.
3825           * To avoid adding 1, we run i from 1 to nwin and set
3826           * wmask[i-1].
3827           *
3828           * for (i = j = 1; i < nwin; i++) {
3829           *        j <<= 1;  (j now == 1 << i)
3830           *        wmask[i - 1] = j;
3831           * }
3832           * (loop runs at least once)
3833           */
3834          set       wmask - 1, %o3
3835          mov       1, %o1                        ! i = 1;
3836          mov       2, %o2                        ! j = 2;
38370:
3838          stb       %o2, [%o3 + %o1]    ! (wmask - 1)[i] = j;
3839          inc       %o1                           ! i++
3840          cmp       %o1, %o0            ! i < nwin?
3841          bl,a      0b                            ! yes, continue
3842           sll      %o2, 1, %o2                   ! (and j <<= 1)
3843
3844          /*
3845           * Now i==nwin, so we want wmask[i-1] = 1.
3846           */
3847          mov       1, %o2                        ! j = 1;
3848          retl
3849           stb      %o2, [%o3 + %o1]    ! (wmask - 1)[i] = j;
3850
3851
3852dostart:
3853          /*
3854           * Startup.
3855           *
3856           * We may have been loaded in low RAM, at some address which
3857           * is page aligned (PROM_LOADADDR actually) rather than where we
3858           * want to run (KERNBASE+PROM_LOADADDR).  Until we get everything set,
3859           * we have to be sure to use only pc-relative addressing.
3860           */
3861
3862          /*
3863           * Find out if the above is the case.
3864           */
38650:        call      1f
3866           sethi    %hi(0b), %l0                  ! %l0 = virtual address of 0:
38671:        or        %l0, %lo(0b), %l0
3868          sub       %l0, %o7, %l7                 ! subtract actual physical address of 0:
3869
3870          /*
3871           * If we're already running at our desired virtual load address,
3872           * %l7 will be set to 0, otherwise it will be KERNBASE.
3873           * From now on until the end of locore bootstrap code, %l7 will
3874           * be used to relocate memory references.
3875           */
3876#define RELOCATE(l,r)                   \
3877          set       l, r;               \
3878          sub       r, %l7, r
3879
3880          /*
3881           * We use the bootinfo method to pass arguments, and the new
3882           * magic number indicates that. A pointer to the kernel top, i.e.
3883           * the first address after the load kernel image (including DDB
3884           * symbols, if any) is passed in %o4[0] and the bootinfo structure
3885           * is passed in %o4[1].
3886           *
3887           * A magic number is passed in %o5 to allow for bootloaders
3888           * that know nothing about the bootinfo structure or previous
3889           * DDB symbol loading conventions.
3890           *
3891           * For compatibility with older versions, we check for DDB arguments
3892           * if the older magic number is there. The loader passes `kernel_top'
3893           * (previously known as `esym') in %o4.
3894           *
3895           * Note: we don't touch %o1-%o3; SunOS bootloaders seem to use them
3896           * for their own mirky business.
3897           *
3898           * Pre-NetBSD 1.3 bootblocks had KERNBASE compiled in, and used it
3899           * to compute the value of `kernel_top' (previously known as `esym').
3900           * In order to successfully boot a kernel built with a different value
3901           * for KERNBASE using old bootblocks, we fixup `kernel_top' here by
3902           * the difference between KERNBASE and the old value (known to be
3903           * 0xf8000000) compiled into pre-1.3 bootblocks.
3904           */
3905
3906          set       0x44444232, %l3               ! bootinfo magic
3907          cmp       %o5, %l3
3908          bne       1f
3909           nop
3910
3911          /* The loader has passed to us a `bootinfo' structure */
3912          ld        [%o4], %l3                    ! 1st word is kernel_top
3913          add       %l3, %l7, %o5                 ! relocate: + KERNBASE
3914          RELOCATE(_C_LABEL(kernel_top),%l3)
3915          st        %o5, [%l3]                    ! and store it
3916
3917          ld        [%o4 + 4], %l3                ! 2nd word is bootinfo
3918          add       %l3, %l7, %o5                 ! relocate
3919          RELOCATE(_C_LABEL(bootinfo),%l3)
3920          st        %o5, [%l3]                    ! store bootinfo
3921          b,a       4f
3922
39231:
3924#ifdef DDB
3925          /* Check for old-style DDB loader magic */
3926          set       KERNBASE, %l4
3927          set       0x44444231, %l3               ! Is it DDB_MAGIC1?
3928          cmp       %o5, %l3
3929          be,a      2f
3930           clr      %l4                           ! if DDB_MAGIC1, clear %l4
3931
3932          set       0x44444230, %l3               ! Is it DDB_MAGIC0?
3933          cmp       %o5, %l3            ! if so, need to relocate %o4
3934          bne       3f                            /* if not, there's no bootloader info */
3935
3936                                                  ! note: %l4 set to KERNBASE above.
3937          set       0xf8000000, %l5               ! compute correction term:
3938          sub       %l5, %l4, %l4                 !  old KERNBASE (0xf8000000 ) - KERNBASE
3939
39402:
3941          tst       %o4                           ! do we have the symbols?
3942          bz        3f
3943           sub      %o4, %l4, %o4                 ! apply compat correction
3944          sethi     %hi(_C_LABEL(kernel_top) - KERNBASE), %l3 ! and store it
3945          st        %o4, [%l3 + %lo(_C_LABEL(kernel_top) - KERNBASE)]
3946          b,a       4f
39473:
3948#endif
3949          /*
3950           * The boot loader did not pass in a value for `kernel_top';
3951           * let it default to `end'.
3952           */
3953          set       end, %o4
3954          RELOCATE(_C_LABEL(kernel_top),%l3)
3955          st        %o4, [%l3]          ! store kernel_top
3956
39574:
3958
3959          /*
3960           * Sun4 passes in the `load address'.  Although possible, its highly
3961           * unlikely that OpenBoot would place the prom vector there.
3962           */
3963          set       PROM_LOADADDR, %g7
3964          cmp       %o0, %g7
3965          be        is_sun4
3966           nop
3967
3968#if defined(SUN4C) || defined(SUN4M) || defined(SUN4D)
3969          /*
3970           * Be prepared to get OF client entry in either %o0 or %o3.
3971           * XXX Will this ever trip on sun4d?  Let's hope not!
3972           */
3973          cmp       %o0, 0
3974          be        is_openfirm
3975           nop
3976
3977          mov       %o0, %g7            ! save romp passed by boot code
3978
3979          /* First, check `romp->pv_magic' */
3980          ld        [%g7 + PV_MAGIC], %o0         ! v = pv->pv_magic
3981          set       OBP_MAGIC, %o1
3982          cmp       %o0, %o1            ! if ( v != OBP_MAGIC) {
3983          bne       is_sun4m            !    assume this is an OPENFIRM machine
3984           nop                                    ! }
3985
3986          /*
3987           * are we on a sun4c or a sun4m or a sun4d?
3988           */
3989          ld        [%g7 + PV_NODEOPS], %o4       ! node = pv->pv_nodeops->no_nextnode(0)
3990          ld        [%o4 + NO_NEXTNODE], %o4
3991          call      %o4
3992           mov      0, %o0                        ! node
3993
3994          !mov      %o0, %l0
3995          RELOCATE(cputypvar,%o1)                 ! name = "compatible"
3996          RELOCATE(cputypval,%l2)                 ! buffer ptr (assume buffer long enough)
3997          ld        [%g7 + PV_NODEOPS], %o4       ! (void)pv->pv_nodeops->no_getprop(...)
3998          ld        [%o4 + NO_GETPROP], %o4
3999          call       %o4
4000           mov      %l2, %o2
4001          !set      cputypval-KERNBASE, %o2       ! buffer ptr
4002          ldub      [%l2 + 4], %o0                ! which is it... "sun4c", "sun4m", "sun4d"?
4003          cmp       %o0, 'c'
4004          be        is_sun4c
4005           nop
4006          cmp       %o0, 'm'
4007          be        is_sun4m
4008           nop
4009          cmp       %o0, 'd'
4010          be        is_sun4d
4011           nop
4012#endif /* SUN4C || SUN4M || SUN4D */
4013
4014          /*
4015           * Don't know what type of machine this is; just halt back
4016           * out to the PROM.
4017           */
4018          ld        [%g7 + PV_HALT], %o1          ! by this kernel, then halt
4019          call      %o1
4020           nop
4021
4022is_openfirm:
4023          ! OF client entry in %o3 (kernel booted directly by PROM?)
4024          mov       %o3, %g7
4025          /* FALLTHROUGH to sun4m case */
4026
4027is_sun4m:
4028#if defined(SUN4M)
4029          set       trapbase_sun4m, %g6
4030          mov       SUN4CM_PGSHIFT, %g5
4031          b         start_havetype
4032           mov      CPU_SUN4M, %g4
4033#else
4034          RELOCATE(sun4m_notsup,%o0)
4035          ld        [%g7 + PV_EVAL], %o1
4036          call      %o1                           ! print a message saying that the
4037           nop                                    ! sun4m architecture is not supported
4038          ld        [%g7 + PV_HALT], %o1          ! by this kernel, then halt
4039          call      %o1
4040           nop
4041          /*NOTREACHED*/
4042#endif
4043is_sun4d:
4044#if defined(SUN4D)
4045          set       trapbase_sun4m, %g6 /* XXXJRT trapbase_sun4d */
4046          mov       SUN4CM_PGSHIFT, %g5
4047          b         start_havetype
4048           mov      CPU_SUN4D, %g4
4049#else
4050          RELOCATE(sun4d_notsup,%o0)
4051          ld        [%g7 + PV_EVAL], %o1
4052          call      %o1                           ! print a message saying that the
4053           nop                                    ! sun4d architecture is not supported
4054          ld        [%g7 + PV_HALT], %o1          ! by this kernel, then halt
4055          call      %o1
4056           nop
4057          /*NOTREACHED*/
4058#endif
4059is_sun4c:
4060#if defined(SUN4C)
4061          set       trapbase_sun4c, %g6
4062          mov       SUN4CM_PGSHIFT, %g5
4063
4064          set       AC_CONTEXT, %g1               ! paranoia: set context to kernel
4065          stba      %g0, [%g1] ASI_CONTROL
4066
4067          b         start_havetype
4068           mov      CPU_SUN4C, %g4                ! XXX CPU_SUN4
4069#else
4070          RELOCATE(sun4c_notsup,%o0)
4071
4072          ld        [%g7 + PV_ROMVEC_VERS], %o1
4073          cmp       %o1, 0
4074          bne       1f
4075           nop
4076
4077          ! stupid version 0 rom interface is pv_eval(int length, char *string)
4078          mov       %o0, %o1
40792:        ldub      [%o0], %o4
4080          tst       %o4
4081          bne       2b
4082           inc      %o0
4083          dec       %o0
4084          sub       %o0, %o1, %o0
4085
40861:        ld        [%g7 + PV_EVAL], %o2
4087          call      %o2                           ! print a message saying that the
4088           nop                                    ! sun4c architecture is not supported
4089          ld        [%g7 + PV_HALT], %o1          ! by this kernel, then halt
4090          call      %o1
4091           nop
4092          /*NOTREACHED*/
4093#endif
4094is_sun4:
4095#if defined(SUN4)
4096          set       trapbase_sun4, %g6
4097          mov       SUN4_PGSHIFT, %g5
4098
4099          set       AC_CONTEXT, %g1               ! paranoia: set context to kernel
4100          stba      %g0, [%g1] ASI_CONTROL
4101
4102          b         start_havetype
4103           mov      CPU_SUN4, %g4
4104#else
4105          set       PROM_BASE, %g7
4106
4107          RELOCATE(sun4_notsup,%o0)
4108          ld        [%g7 + OLDMON_PRINTF], %o1
4109          call      %o1                           ! print a message saying that the
4110           nop                                    ! sun4 architecture is not supported
4111          ld        [%g7 + OLDMON_HALT], %o1 ! by this kernel, then halt
4112          call      %o1
4113           nop
4114          /*NOTREACHED*/
4115#endif
4116
4117start_havetype:
4118          cmp       %l7, 0
4119          be        startmap_done
4120
4121          /*
4122           * Step 1: double map low RAM (addresses [0.._end-start-1])
4123           * to KERNBASE (addresses [KERNBASE.._end-1]).  None of these
4124           * are `bad' aliases (since they are all on segment boundaries)
4125           * so we do not have to worry about cache aliasing.
4126           *
4127           * We map in another couple of segments just to have some
4128           * more memory (512K, actually) guaranteed available for
4129           * bootstrap code (pmap_bootstrap needs memory to hold MMU
4130           * and context data structures). Note: this is only relevant
4131           * for 2-level MMU sun4/sun4c machines.
4132           */
4133          clr       %l0                           ! lowva
4134          set       KERNBASE, %l1                 ! highva
4135
4136          sethi     %hi(_C_LABEL(kernel_top) - KERNBASE), %o0
4137          ld        [%o0 + %lo(_C_LABEL(kernel_top) - KERNBASE)], %o1
4138          set       (2 << 18), %o2                ! add slack for sun4c MMU
4139          add       %o1, %o2, %l2                 ! last va that must be remapped
4140
4141          /*
4142           * Need different initial mapping functions for different
4143           * types of machines.
4144           */
4145#if defined(SUN4C)
4146          cmp       %g4, CPU_SUN4C
4147          bne       1f
4148           set      1 << 18, %l3                  ! segment size in bytes
41490:
4150          lduba     [%l0] ASI_SEGMAP, %l4         ! segmap[highva] = segmap[lowva];
4151          stba      %l4, [%l1] ASI_SEGMAP
4152          add       %l3, %l1, %l1                 ! highva += segsiz;
4153          cmp       %l1, %l2            ! done?
4154          blu       0b                            ! no, loop
4155           add      %l3, %l0, %l0                 ! (and lowva += segsz)
4156          b,a       startmap_done
41571:
4158#endif /* SUN4C */
4159
4160#if defined(SUN4)
4161          cmp       %g4, CPU_SUN4
4162          bne       2f
4163#if defined(SUN4_MMU3L)
4164          set       AC_IDPROM+1, %l3
4165          lduba     [%l3] ASI_CONTROL, %l3
4166          cmp       %l3, 0x24 ! XXX - SUN4_400
4167          bne       no_3mmu
4168           nop
4169
4170          /*
4171           * Three-level sun4 MMU.
4172           * Double-map by duplicating a single region entry (which covers
4173           * 16MB) corresponding to the kernel's virtual load address.
4174           */
4175          add       %l0, 2, %l0                   ! get to proper half-word in RG space
4176          add       %l1, 2, %l1
4177          lduha     [%l0] ASI_REGMAP, %l4         ! regmap[highva] = regmap[lowva];
4178          stha      %l4, [%l1] ASI_REGMAP
4179          b,a       startmap_done
4180no_3mmu:
4181#endif
4182
4183          /*
4184           * Three-level sun4 MMU.
4185           * Double-map by duplicating the required number of segment
4186           * entries corresponding to the kernel's virtual load address.
4187           */
4188          set       1 << 18, %l3                  ! segment size in bytes
41890:
4190          lduha     [%l0] ASI_SEGMAP, %l4         ! segmap[highva] = segmap[lowva];
4191          stha      %l4, [%l1] ASI_SEGMAP
4192          add       %l3, %l1, %l1                 ! highva += segsiz;
4193          cmp       %l1, %l2            ! done?
4194          blu       0b                            ! no, loop
4195           add      %l3, %l0, %l0                 ! (and lowva += segsz)
4196          b,a       startmap_done
41972:
4198#endif /* SUN4 */
4199
4200#if defined(SUN4M) || defined(SUN4D)
4201          cmp       %g4, CPU_SUN4M
4202          beq       3f
4203           nop
4204          cmp       %g4, CPU_SUN4D
4205          bne       4f
4206
42073:
4208          /*
4209           * The OBP guarantees us a 16MB mapping using a level 1 PTE at
4210           * the start of the memory bank in which we were loaded. All we
4211           * have to do is copy the entry.
4212           * Also, we must check to see if we have a TI Viking in non-mbus mode,
4213           * and if so do appropriate flipping and turning off traps before
4214           * we dork with MMU passthrough.  -grrr
4215           */
4216
4217          sethi     %hi(0x40000000), %o1          ! TI version bit
4218          rd        %psr, %o0
4219          andcc     %o0, %o1, %g0
4220          be        remap_notvik                  ! is non-TI normal MBUS module
4221          lda       [%g0] ASI_SRMMU, %o0          ! load MMU
4222          andcc     %o0, 0x800, %g0
4223          bne       remap_notvik                  ! It is a viking MBUS module
4224          nop
4225
4226          /*
4227           * Ok, we have a non-Mbus TI Viking, a MicroSparc.
4228           * In this scenario, in order to play with the MMU
4229           * passthrough safely, we need turn off traps, flip
4230           * the AC bit on in the mmu status register, do our
4231           * passthroughs, then restore the mmu reg and %psr
4232           */
4233          rd        %psr, %o4           ! saved here till done
4234          andn      %o4, 0x20, %o5
4235          wr        %o5, 0x0, %psr
4236          nop; nop; nop;
4237          set       SRMMU_CXTPTR, %o0
4238          lda       [%o0] ASI_SRMMU, %o0          ! get context table ptr
4239          sll       %o0, 4, %o0                   ! make physical
4240          lda       [%g0] ASI_SRMMU, %o3          ! hold mmu-sreg here
4241          /* 0x8000 is AC bit in Viking mmu-ctl reg */
4242          set       0x8000, %o2
4243          or        %o3, %o2, %o2
4244          sta       %o2, [%g0] ASI_SRMMU          ! AC bit on
4245
4246          lda       [%o0] ASI_BYPASS, %o1
4247          srl       %o1, 4, %o1
4248          sll       %o1, 8, %o1                   ! get phys addr of l1 entry
4249          lda       [%o1] ASI_BYPASS, %l4
4250          srl       %l1, 22, %o2                  ! note: 22 == RGSHIFT - 2
4251          add       %o1, %o2, %o1
4252          sta       %l4, [%o1] ASI_BYPASS
4253
4254          sta       %o3, [%g0] ASI_SRMMU          ! restore mmu-sreg
4255          wr        %o4, 0x0, %psr                ! restore psr
4256          b,a       startmap_done
4257
4258          /*
4259           * The following is generic and should work on all
4260           * Mbus based SRMMU's.
4261           */
4262remap_notvik:
4263          set       SRMMU_CXTPTR, %o0
4264          lda       [%o0] ASI_SRMMU, %o0          ! get context table ptr
4265          sll       %o0, 4, %o0                   ! make physical
4266          lda       [%o0] ASI_BYPASS, %o1
4267          srl       %o1, 4, %o1
4268          sll       %o1, 8, %o1                   ! get phys addr of l1 entry
4269          lda       [%o1] ASI_BYPASS, %l4
4270          srl       %l1, 22, %o2                  ! note: 22 == RGSHIFT - 2
4271          add       %o1, %o2, %o1
4272          sta       %l4, [%o1] ASI_BYPASS
4273          !b,a      startmap_done
42744:
4275#endif /* SUN4M || SUN4D */
4276          ! botch! We should blow up.
4277
4278startmap_done:
4279          /*
4280           * All set, fix pc and npc.  Once we are where we should be,
4281           * we can give ourselves a stack and enable traps.
4282           */
4283          set       1f, %g1
4284          jmp       %g1
4285           nop
42861:
4287          sethi     %hi(_C_LABEL(cputyp)), %o0    ! what type of CPU we are on
4288          st        %g4, [%o0 + %lo(_C_LABEL(cputyp))]
4289
4290          sethi     %hi(_C_LABEL(pgshift)), %o0   ! pgshift = log2(nbpg)
4291          st        %g5, [%o0 + %lo(_C_LABEL(pgshift))]
4292
4293          mov       1, %o0                        ! nbpg = 1 << pgshift
4294          sll       %o0, %g5, %g5
4295          sethi     %hi(_C_LABEL(nbpg)), %o0      ! nbpg = bytes in a page
4296          st        %g5, [%o0 + %lo(_C_LABEL(nbpg))]
4297
4298          sub       %g5, 1, %g5
4299          sethi     %hi(_C_LABEL(pgofset)), %o0 ! page offset = bytes in a page - 1
4300          st        %g5, [%o0 + %lo(_C_LABEL(pgofset))]
4301
4302          rd        %psr, %g3           ! paranoia: make sure ...
4303          andn      %g3, PSR_ET, %g3    ! we have traps off
4304          wr        %g3, 0, %psr                  ! so that we can fiddle safely
4305          nop; nop; nop
4306
4307          wr        %g0, 0, %wim                  ! make sure we can set psr
4308          nop; nop; nop
4309          wr        %g0, PSR_S|PSR_PS|PSR_PIL, %psr         ! set initial psr
4310           nop; nop; nop
4311
4312          wr        %g0, 2, %wim                  ! set initial %wim (w1 invalid)
4313          mov       1, %g1                        ! set pcb_wim (log2(%wim) = 1)
4314          sethi     %hi(_C_LABEL(u0) + PCB_WIM), %g2
4315          st        %g1, [%g2 + %lo(_C_LABEL(u0) + PCB_WIM)]
4316
4317          set       USRSTACK - CCFSZ, %fp         ! as if called from user code
4318          set       estack0 - CCFSZ - 80, %sp ! via syscall(boot_me_up) or somesuch
4319          rd        %psr, %l0
4320          wr        %l0, PSR_ET, %psr
4321          nop; nop; nop
4322
4323          /* Export actual trapbase */
4324          sethi     %hi(_C_LABEL(trapbase)), %o0
4325          st        %g6, [%o0+%lo(_C_LABEL(trapbase))]
4326
4327#ifdef notdef
4328          /*
4329           * Step 2: clear BSS.  This may just be paranoia; the boot
4330           * loader might already do it for us; but what the hell.
4331           */
4332          set       _edata, %o0                   ! bzero(edata, end - edata)
4333          set       _end, %o1
4334          call      _C_LABEL(bzero)
4335           sub      %o1, %o0, %o1
4336#endif
4337
4338          /*
4339           * Stash prom vectors now, after bzero, as it lives in bss
4340           * (which we just zeroed).
4341           * This depends on the fact that bzero does not use %g7.
4342           */
4343          sethi     %hi(_C_LABEL(romp)), %l0
4344          st        %g7, [%l0 + %lo(_C_LABEL(romp))]
4345
4346          /*
4347           * Step 3: compute number of windows and set up tables.
4348           * We could do some of this later.
4349           */
4350          save      %sp, -64, %sp
4351          rd        %psr, %g1
4352          restore
4353          and       %g1, 31, %g1                  ! want just the CWP bits
4354          add       %g1, 1, %o0                   ! compute nwindows
4355          sethi     %hi(_C_LABEL(nwindows)), %o1  ! may as well tell everyone
4356          call      init_tables
4357           st       %o0, [%o1 + %lo(_C_LABEL(nwindows))]
4358
4359#if defined(SUN4) || defined(SUN4C)
4360          /*
4361           * Some sun4/sun4c models have fewer than 8 windows. For extra
4362           * speed, we do not need to save/restore those windows
4363           * The save/restore code has 6 "save"'s followed by 6
4364           * "restore"'s -- we "nop" out the last "save" and first
4365           * "restore"
4366           */
4367          cmp       %o0, 8
4368          be        1f
4369noplab:    nop
4370          sethi     %hi(noplab), %l0
4371          ld        [%l0 + %lo(noplab)], %l1
4372          set       Lwb1, %l0
4373          st        %l1, [%l0 + 5*4]
4374          st        %l1, [%l0 + 6*4]
43751:
4376#endif
4377
4378#if (defined(SUN4) || defined(SUN4C)) && (defined(SUN4M) || defined(SUN4D))
4379
4380          /*
4381           * Patch instructions at specified labels that start
4382           * per-architecture code-paths.
4383           */
4384Lgandul:  nop
4385
4386#define MUNGE(label) \
4387          sethi     %hi(label), %o0; \
4388          st        %l0, [%o0 + %lo(label)]
4389
4390          sethi     %hi(Lgandul), %o0
4391          ld        [%o0 + %lo(Lgandul)], %l0     ! %l0 = NOP
4392
4393          cmp       %g4, CPU_SUN4M
4394          beq,a     2f
4395           nop
4396
4397          cmp       %g4, CPU_SUN4D
4398          bne,a     1f
4399           nop
4400
44012:        ! this should be automated!
4402          MUNGE(NOP_ON_4M_1)
4403          MUNGE(NOP_ON_4M_2)
4404          MUNGE(NOP_ON_4M_3)
4405          MUNGE(NOP_ON_4M_4)
4406          MUNGE(NOP_ON_4M_5)
4407          MUNGE(NOP_ON_4M_6)
4408          MUNGE(NOP_ON_4M_7)
4409          MUNGE(NOP_ON_4M_8)
4410          MUNGE(NOP_ON_4M_9)
4411          MUNGE(NOP_ON_4M_10)
4412          MUNGE(NOP_ON_4M_11)
4413          MUNGE(NOP_ON_4M_12)
4414          b,a       2f
4415
44161:
4417#if 0 /* currently there are no NOP_ON_4_4C_* */
4418          MUNGE(NOP_ON_4_4C_1)
4419#endif
4420
44212:
4422
4423#undef MUNGE
4424#endif /* (SUN4 || SUN4C) && (SUN4M || SUN4D) */
4425
4426          /*
4427           * Step 4: change the trap base register, now that our trap handlers
4428           * will function (they need the tables we just set up).
4429           * This depends on the fact that memset does not use %g6.
4430           */
4431          wr        %g6, 0, %tbr
4432          nop; nop; nop                           ! paranoia
4433
4434          /* Clear `cpuinfo': memset(&cpuinfo, 0, sizeof cpuinfo) */
4435          sethi     %hi(CPUINFO_VA), %o0
4436          set       CPUINFO_STRUCTSIZE, %o2
4437          call      _C_LABEL(memset)
4438           clr      %o1
4439
4440          /*
4441           * Initialize `cpuinfo' fields which are needed early.  Note
4442           * we make the cpuinfo self-reference at the local VA for now.
4443           * It may be changed to reference a global VA later.
4444           */
4445          set       _C_LABEL(u0), %o0             ! cpuinfo.curpcb = u0;
4446          sethi     %hi(cpcb), %l0
4447          st        %o0, [%l0 + %lo(cpcb)]
4448
4449          sethi     %hi(CPUINFO_VA), %o0                    ! cpuinfo.ci_self = &cpuinfo;
4450          sethi     %hi(_CISELFP), %l0
4451          st        %o0, [%l0 + %lo(_CISELFP)]
4452
4453          set       _C_LABEL(eintstack), %o0      ! cpuinfo.eintstack= _eintstack;
4454          sethi     %hi(_EINTSTACKP), %l0
4455          st        %o0, [%l0 + %lo(_EINTSTACKP)]
4456
4457          /*
4458           * Ready to run C code; finish bootstrap.
4459           */
4460          call      _C_LABEL(bootstrap)
4461           nop
4462
4463          /*
4464           * Call main.  This returns to us after loading /sbin/init into
4465           * user space.  (If the exec fails, main() does not return.)
4466           */
4467          call      _C_LABEL(main)
4468           clr      %o0                           ! our frame arg is ignored
4469          /*NOTREACHED*/
4470
4471/*
4472 * Openfirmware entry point: openfirmware(void *args)
4473 */
4474ENTRY(openfirmware)
4475          sethi     %hi(_C_LABEL(romp)), %o1
4476          ld        [%o1 + %lo(_C_LABEL(romp))], %o2
4477          jmp       %o2
4478           nop
4479
4480#if defined(SUN4M) || defined(SUN4D)
4481/*
4482 * V8 multiply and divide routines, to be copied over the code
4483 * for the V6/V7 routines.  Seems a shame to spend the call, but....
4484 * Note: while .umul and .smul return a 64-bit result in %o1%o0,
4485 * gcc only really cares about the low 32 bits in %o0.  This is
4486 * really just gcc output, cleaned up a bit.
4487 */
4488          .globl    _C_LABEL(sparc_v8_muldiv)
4489_C_LABEL(sparc_v8_muldiv):
4490          save    %sp, -CCFSZ, %sp
4491
4492#define   OVERWRITE(rtn, v8_rtn, len)   \
4493          set       v8_rtn, %o0;                  \
4494          set       rtn, %o1;           \
4495          call      _C_LABEL(bcopy);    \
4496           mov      len, %o2;           \
4497          /* now flush the insn cache */          \
4498          set       rtn, %o0;           \
4499           mov      len, %o1;           \
45000:                                                \
4501          flush     %o0;                          \
4502          subcc     %o1, 8, %o1;                  \
4503          bgu       0b;                           \
4504           add      %o0, 8, %o0;                  \
4505
4506          OVERWRITE(.mul,  v8_smul, .Lv8_smul_len)
4507          OVERWRITE(.umul, v8_umul, .Lv8_umul_len)
4508          OVERWRITE(.div,  v8_sdiv, .Lv8_sdiv_len)
4509          OVERWRITE(.udiv, v8_udiv, .Lv8_udiv_len)
4510          OVERWRITE(.rem,  v8_srem, .Lv8_srem_len)
4511          OVERWRITE(.urem, v8_urem, .Lv8_urem_len)
4512#undef    OVERWRITE
4513          ret
4514           restore
4515
4516v8_smul:
4517          retl
4518           smul     %o0, %o1, %o0
4519.Lv8_smul_len = .-v8_smul
4520v8_umul:
4521          retl
4522           umul     %o0, %o1, %o0
4523!v8_umul_len = 2 * 4
4524.Lv8_umul_len = .-v8_umul
4525v8_sdiv:
4526          sra       %o0, 31, %g2
4527          wr        %g2, 0, %y
4528          nop; nop; nop
4529          retl
4530           sdiv     %o0, %o1, %o0
4531.Lv8_sdiv_len = .-v8_sdiv
4532v8_udiv:
4533          wr        %g0, 0, %y
4534          nop; nop; nop
4535          retl
4536           udiv     %o0, %o1, %o0
4537.Lv8_udiv_len = .-v8_udiv
4538v8_srem:
4539          sra       %o0, 31, %g3
4540          wr        %g3, 0, %y
4541          nop; nop; nop
4542          sdiv      %o0, %o1, %g2
4543          smul      %g2, %o1, %g2
4544          retl
4545           sub      %o0, %g2, %o0
4546.Lv8_srem_len = .-v8_srem
4547v8_urem:
4548          wr        %g0, 0, %y
4549          nop; nop; nop
4550          udiv      %o0, %o1, %g2
4551          smul      %g2, %o1, %g2
4552          retl
4553           sub      %o0, %g2, %o0
4554.Lv8_urem_len = .-v8_urem
4555
4556#endif /* SUN4M || SUN4D */
4557
4558#if defined(MULTIPROCESSOR)
4559          /*
4560           * Entry point for non-boot CPUs in MP systems.
4561           */
4562          .globl    _C_LABEL(cpu_hatch)
4563_C_LABEL(cpu_hatch):
4564          rd        %psr, %g3           ! paranoia: make sure ...
4565          andn      %g3, PSR_ET, %g3    ! we have traps off
4566          wr        %g3, 0, %psr                  ! so that we can fiddle safely
4567          nop; nop; nop
4568
4569          wr        %g0, 0, %wim                  ! make sure we can set psr
4570          nop; nop; nop
4571          wr        %g0, PSR_S|PSR_PS|PSR_PIL, %psr         ! set initial psr
4572          nop; nop; nop
4573
4574          wr        %g0, 2, %wim                  ! set initial %wim (w1 invalid)
4575
4576          /* Initialize Trap Base register */
4577          sethi     %hi(_C_LABEL(trapbase)), %o0
4578          ld        [%o0+%lo(_C_LABEL(trapbase))], %g6
4579          wr        %g6, 0, %tbr
4580          nop; nop; nop                           ! paranoia
4581
4582          /*
4583           * Use this CPUs idlelwp's stack
4584           */
4585          sethi     %hi(cpcb), %o0
4586          ld        [%o0 + %lo(cpcb)], %o0
4587          set       USPACE - 80 - CCFSZ, %sp
4588          add       %o0, %sp, %sp
4589
4590          add       80, %sp, %fp
4591
4592          /* Enable traps */
4593          rd        %psr, %l0
4594          wr        %l0, PSR_ET, %psr
4595          nop; nop
4596
4597          /* Call C code */
4598          call      _C_LABEL(cpu_setup)
4599           nop                                    ! 3rd from above
4600
4601          /* Enable interrupts */
4602          rd        %psr, %l0
4603          andn      %l0, PSR_PIL, %l0   ! psr &= ~PSR_PIL;
4604          wr        %l0, 0, %psr                  ! (void) spl0();
4605          nop; nop; nop
4606
4607          /* Wait for go_smp_cpus to go */
4608          set       _C_LABEL(go_smp_cpus), %l1
4609          ld        [%l1], %l0
46101:
4611          cmp       %l0, %g0
4612          be        1b
4613           ld       [%l1], %l0
4614
4615          b         idle_loop
4616           nop
4617
4618#endif /* MULTIPROCESSOR */
4619
4620#ifdef COMPAT_16
4621#include "sigcode_state.s"
4622
4623          .globl    _C_LABEL(sigcode)
4624          .globl    _C_LABEL(esigcode)
4625_C_LABEL(sigcode):
4626
4627          SAVE_STATE
4628
4629          ldd       [%fp + 64], %o0               ! sig, code
4630          ld        [%fp + 76], %o3               ! arg3
4631          call      %g1                           ! (*sa->sa_handler)(sig,code,scp,arg3)
4632           add      %fp, 64 + 16, %o2   ! scp
4633
4634          RESTORE_STATE
4635
4636          ! get registers back & set syscall #
4637          restore   %g0, SYS_compat_16___sigreturn14, %g1
4638          add       %sp, 64 + 16, %o0   ! compute scp
4639          t         ST_SYSCALL                    ! sigreturn(scp)
4640          ! sigreturn does not return unless it fails
4641          mov       SYS_exit, %g1                 ! exit(errno)
4642          t         ST_SYSCALL
4643          /* NOTREACHED */
4644_C_LABEL(esigcode):
4645#endif /* COMPAT_16 */
4646
4647
4648/*
4649 * Primitives
4650 */
4651
4652/*
4653 * General-purpose NULL routine.
4654 */
4655ENTRY(sparc_noop)
4656          retl
4657           nop
4658
4659/*
4660 * getfp() - get stack frame pointer
4661 */
4662ENTRY(getfp)
4663          retl
4664           mov %fp, %o0
4665
4666/*
4667 * copyinstr(fromaddr, toaddr, maxlength, &lencopied)
4668 *
4669 * Copy a null terminated string from the user address space into
4670 * the kernel address space.
4671 */
4672ENTRY(copyinstr)
4673          ! %o0 = fromaddr, %o1 = toaddr, %o2 = maxlen, %o3 = &lencopied
4674          mov       %o1, %o5            ! save = toaddr;
4675          tst       %o2                           ! maxlen == 0?
4676          beq,a     Lcstoolong                    ! yes, return ENAMETOOLONG
4677           sethi    %hi(cpcb), %o4
4678
4679          set       KERNBASE, %o4
4680          cmp       %o0, %o4            ! fromaddr < KERNBASE?
4681          blu       Lcsdocopy           ! yes, go do it
4682           sethi    %hi(cpcb), %o4                ! (first instr of copy)
4683
4684          b         Lcsdone                       ! no, return EFAULT
4685           mov      EFAULT, %o0
4686
4687/*
4688 * copyoutstr(fromaddr, toaddr, maxlength, &lencopied)
4689 *
4690 * Copy a null terminated string from the kernel
4691 * address space to the user address space.
4692 */
4693ENTRY(copyoutstr)
4694          ! %o0 = fromaddr, %o1 = toaddr, %o2 = maxlen, %o3 = &lencopied
4695          mov       %o1, %o5            ! save = toaddr;
4696          tst       %o2                           ! maxlen == 0?
4697          beq,a     Lcstoolong                    ! yes, return ENAMETOOLONG
4698           sethi    %hi(cpcb), %o4
4699
4700          set       KERNBASE, %o4
4701          cmp       %o1, %o4            ! toaddr < KERNBASE?
4702          blu       Lcsdocopy           ! yes, go do it
4703           sethi    %hi(cpcb), %o4                ! (first instr of copy)
4704
4705          b         Lcsdone                       ! no, return EFAULT
4706           mov      EFAULT, %o0
4707
4708Lcsdocopy:
4709!         sethi     %hi(cpcb), %o4                ! (done earlier)
4710          ld        [%o4 + %lo(cpcb)], %o4        ! catch faults
4711          set       Lcsdone, %g1
4712          st        %g1, [%o4 + PCB_ONFAULT]
4713
4714! XXX should do this in bigger chunks when possible
47150:                                                ! loop:
4716          ldsb      [%o0], %g1                    !         c = *fromaddr;
4717          tst       %g1
4718          stb       %g1, [%o1]                    !         *toaddr++ = c;
4719          be        1f                            !         if (c == NULL)
4720           inc      %o1                           !                   goto ok;
4721          deccc     %o2                           !         if (--len > 0) {
4722          bgu       0b                            !                   fromaddr++;
4723           inc      %o0                           !                   goto loop;
4724                                                  !         }
4725Lcstoolong:                                       !
4726          b         Lcsdone                       !         error = ENAMETOOLONG;
4727           mov      ENAMETOOLONG, %o0   !         goto done;
47281:                                                ! ok:
4729          clr       %o0                           !    error = 0;
4730Lcsdone:                                ! done:
4731          sub       %o1, %o5, %o1                 !         len = to - save;
4732          tst       %o3                           !         if (lencopied)
4733          bnz,a     3f
4734           st       %o1, [%o3]                    !                   *lencopied = len;
47353:
4736          retl                                    ! cpcb->pcb_onfault = 0;
4737           st       %g0, [%o4 + PCB_ONFAULT]! return (error);
4738
4739/*
4740 * Copyin(src, dst, len)
4741 *
4742 * Copy specified amount of data from user space into the kernel.
4743 */
4744ENTRY(copyin)
4745          set       KERNBASE, %o3
4746          cmp       %o0, %o3            ! src < KERNBASE?
4747          blu,a     Ldocopy                       ! yes, can try it
4748           sethi    %hi(cpcb), %o3
4749
4750          /* source address points into kernel space: return EFAULT */
4751          retl
4752           mov      EFAULT, %o0
4753
4754/*
4755 * Copyout(src, dst, len)
4756 *
4757 * Copy specified amount of data from kernel to user space.
4758 * Just like copyin, except that the `dst' addresses are user space
4759 * rather than the `src' addresses.
4760 */
4761ENTRY(copyout)
4762          set       KERNBASE, %o3
4763          cmp       %o1, %o3            ! dst < KERBASE?
4764          blu,a     Ldocopy
4765           sethi    %hi(cpcb), %o3
4766
4767          /* destination address points into kernel space: return EFAULT */
4768          retl
4769           mov      EFAULT, %o0
4770
4771          /*
4772           * ******NOTE****** this depends on bcopy() not using %g7
4773           */
4774Ldocopy:
4775!         sethi     %hi(cpcb), %o3
4776          ld        [%o3 + %lo(cpcb)], %o3
4777          set       Lcopyfault, %o4
4778          mov       %o7, %g7            ! save return address
4779          call      _C_LABEL(bcopy)               ! bcopy(src, dst, len)
4780           st       %o4, [%o3 + PCB_ONFAULT]
4781
4782          sethi     %hi(cpcb), %o3
4783          ld        [%o3 + %lo(cpcb)], %o3
4784          st        %g0, [%o3 + PCB_ONFAULT]
4785          jmp       %g7 + 8
4786           clr      %o0                           ! return 0
4787
4788! Copyin or copyout fault.  Clear cpcb->pcb_onfault.
4789! The return value was already put in %o0 by the fault handler.
4790! Note that although we were in bcopy, there is no state to clean up;
4791! the only special thing is that we have to return to [g7 + 8] rather than
4792! [o7 + 8].
4793Lcopyfault:
4794          sethi     %hi(cpcb), %o3
4795          ld        [%o3 + %lo(cpcb)], %o3
4796          jmp       %g7 + 8
4797           st       %g0, [%o3 + PCB_ONFAULT]
4798
4799
4800/*
4801 * Write all user windows presently in the CPU back to the user's stack.
4802 * We just do `save' instructions until pcb_uw == 0.
4803 *
4804 *        p = cpcb;
4805 *        nsaves = 0;
4806 *        while (p->pcb_uw > 0)
4807 *                  save(), nsaves++;
4808 *        while (--nsaves >= 0)
4809 *                  restore();
4810 */
4811ENTRY(write_user_windows)
4812          sethi     %hi(cpcb), %g6
4813          ld        [%g6 + %lo(cpcb)], %g6
4814          b         2f
4815           clr      %g5
48161:
4817          save      %sp, -64, %sp
48182:
4819          ld        [%g6 + PCB_UW], %g7
4820          tst       %g7
4821          bg,a      1b
4822           inc      %g5
48233:
4824          deccc     %g5
4825          bge,a     3b
4826           restore
4827          retl
4828           nop
4829
4830/*
4831 * cpu_switchto() runs an lwp, saving the current one away.
4832 */
4833ENTRY(cpu_switchto)
4834          /*
4835           * Register Usage:
4836           *        %g1 = oldlwp (return value)
4837           *        %g2 = psr
4838           *        %g3 = newlwp
4839           *        %g5 = newpcb
4840           *        %l1 = oldpsr (excluding ipl bits)
4841           *        %l6 = %hi(cpcb)
4842           *        %o0 = tmp 1
4843           *        %o1 = tmp 2
4844           *        %o2 = tmp 3
4845           *        %o3 = vmspace->vm_pmap
4846           */
4847          save      %sp, -CCFSZ, %sp
4848          mov       %i0, %g1                      ! save oldlwp
4849          mov       %i1, %g3                      ! and newlwp
4850
4851          sethi     %hi(cpcb), %l6
4852
4853          rd        %psr, %l1                     ! psr = %psr;
4854
4855          ld        [%l6 + %lo(cpcb)], %o0
4856
4857          std       %i6, [%o0 + PCB_SP]           ! cpcb->pcb_<sp,pc> = <fp,pc>;
4858
4859          st        %l1, [%o0 + PCB_PSR]                    ! cpcb->pcb_pcb = psr
4860
4861          /*
4862           * Save the old process: write back all windows (excluding
4863           * the current one).  XXX crude; knows nwindows <= 8
4864           */
4865#define   SAVE save %sp, -64, %sp
4866Lwb1:     SAVE; SAVE; SAVE; SAVE; SAVE; SAVE;     /* 6 of each: */
4867          restore; restore; restore; restore; restore; restore
4868
4869          andn      %l1, PSR_PIL, %l1             ! oldpsr &= ~PSR_PIL;
4870
4871          /*
4872           * Load the new process.  To load, we must change stacks and
4873           * and alter cpcb. We must also load the CWP and WIM from the
4874           * new process' PCB, since, when we finally return from
4875           * the trap, the CWP of the trap window must match the
4876           * CWP stored in the trap frame.
4877           *
4878           * Once the new CWP is set below our local registers become
4879           * invalid, so, we use globals at that point for any values
4880           * we need afterwards.
4881           */
4882
4883          ld        [%g3 + L_PCB], %g5  ! newpcb
4884          ld        [%g5 + PCB_PSR], %g2    ! cwpbits = newpcb->pcb_psr;
4885
4886          /* traps off while we switch to the new stack */
4887          wr        %l1, (IPL_SCHED << 8) | PSR_ET, %psr
4888
4889          /* set new cpcb, and curlwp */
4890          sethi     %hi(curlwp), %l7
4891          st        %g5, [%l6 + %lo(cpcb)]                  ! cpcb = newpcb;
4892
4893          /*
4894           * Issue barriers to coordinate mutex_exit on this CPU with
4895           * mutex_vector_enter on another CPU.
4896           *
4897           * 1. Any prior mutex_exit by oldlwp must be visible to other
4898           *    CPUs before we set ci_curlwp := newlwp on this one,
4899           *    requiring a store-before-store barrier.
4900           *
4901           * 2. ci_curlwp := newlwp must be visible on all other CPUs
4902           *    before any subsequent mutex_exit by newlwp can even test
4903           *    whether there might be waiters, requiring a
4904           *    store-before-load barrier.
4905           *
4906           * See kern_mutex.c for details -- this is necessary for
4907           * adaptive mutexes to detect whether the lwp is on the CPU in
4908           * order to safely block without requiring atomic r/m/w in
4909           * mutex_exit.
4910           */
4911          /* stbar -- store-before-store, not needed on TSO */
4912          st      %g3, [%l7 + %lo(curlwp)]        ! curlwp = l;
4913#ifdef MULTIPROCESSOR
4914          ldstub    [%sp - 4], %g0      /* makeshift store-before-load barrier */
4915#endif
4916
4917          /* compute new wim */
4918          ld        [%g5 + PCB_WIM], %o0
4919          mov       1, %o1
4920          sll       %o1, %o0, %o0
4921          wr        %o0, 0, %wim                  ! %wim = 1 << newpcb->pcb_wim;
4922
4923          /* now must not change %psr for 3 more instrs */
4924          /* Clear FP & CP enable bits, as well as the PIL field */
4925/*1,2*/   set     PSR_EF|PSR_EC|PSR_PIL, %o0
4926/*3*/     andn    %g2, %o0, %g2           ! newpsr &= ~(PSR_EF|PSR_EC|PSR_PIL);
4927          /* set new psr, but with traps disabled */
4928          wr      %g2, (IPL_SCHED << 8)|PSR_ET, %psr ! %psr = newpsr ^ PSR_ET;
4929          /* load new stack and return address */
4930          ldd       [%g5 + PCB_SP], %i6 ! <fp,pc> = newpcb->pcb_<sp,pc>
4931          add       %fp, -CCFSZ, %sp    ! set stack frame for this window
4932
4933#ifdef DEBUG
4934          mov       %g5, %o0
4935          SET_SP_REDZONE(%o0, %o1)
4936          CHECK_SP_REDZONE(%o0, %o1)
4937#endif
4938
4939          /* finally, enable traps and continue at splsched() */
4940          wr      %g2, IPL_SCHED << 8 , %psr      ! psr = newpsr;
4941
4942          /*
4943           * Now running p.
4944           */
4945
4946          /*
4947           * Check for restartable atomic sequences (RAS)
4948           */
4949          ld        [%g3 + L_PROC], %o0 ! now %o0 points to p
4950          ld        [%o0 + P_RASLIST], %o1        ! any RAS in p?
4951          cmp       %o1, 0
4952          be        Lsw_noras           ! no, skip RAS check
4953           mov      %g1, %i0            ! restore oldlwp (for return value)
4954          ld        [%g3 + L_TF], %l3   ! pointer to trap frame
4955          call      _C_LABEL(ras_lookup)
4956           ld       [%l3 + TF_PC], %o1
4957          cmp       %o0, -1
4958          be        Lsw_noras
4959           add      %o0, 4, %o1
4960          st        %o0, [%l3 + TF_PC]  ! store rewound %pc
4961          st        %o1, [%l3 + TF_NPC] ! and %npc
4962
4963Lsw_noras:
4964
4965          ret
4966           restore                      ! return (oldlwp)
4967
4968/*
4969 * Call the idlespin() function if it exists, otherwise just return.
4970 */
4971ENTRY(cpu_idle)
4972          sethi     %hi(CPUINFO_VA+CPUINFO_IDLESPIN), %o0
4973          ld        [%o0 + %lo(CPUINFO_VA+CPUINFO_IDLESPIN)], %o1
4974          tst       %o1
4975          bz        1f
4976           nop
4977          jmp       %o1
4978           nop
49791:
4980          retl
4981           nop
4982
4983/*
4984 * Snapshot the current process so that stack frames are up to date.
4985 * Only used just before a crash dump.
4986 */
4987ENTRY(snapshot)
4988          std       %o6, [%o0 + PCB_SP] ! save sp
4989          rd        %psr, %o1           ! save psr
4990          st        %o1, [%o0 + PCB_PSR]
4991
4992          /*
4993           * Just like switch(); same XXX comments apply.
4994           * 7 of each.  Minor tweak: the 7th restore is
4995           * done after a ret.
4996           */
4997          SAVE; SAVE; SAVE; SAVE; SAVE; SAVE; SAVE
4998          restore; restore; restore; restore; restore; restore; ret; restore
4999
5000
5001/*
5002 * cpu_lwp_fork() arranges for lwp_trampoline() to run when the
5003 * nascent lwp is selected by switch().
5004 *
5005 * The switch frame will contain pointer to struct lwp of this lwp in
5006 * %l2, a pointer to the function to call in %l0, and an argument to
5007 * pass to it in %l1 (we abuse the callee-saved registers).
5008 *
5009 * We enter lwp_trampoline as if we are "returning" from
5010 * cpu_switchto(), so %o0 contains previous lwp (the one we are
5011 * switching from) that we pass to lwp_startup().
5012 *
5013 * If the function *(%l0) returns, we arrange for an immediate return
5014 * to user mode.  This happens in two known cases: after execve(2) of
5015 * init, and when returning a child to user mode after a fork(2).
5016 *
5017 * If were setting up a kernel thread, the function *(%l0) will not
5018 * return.
5019 */
5020ENTRY(lwp_trampoline)
5021          /*
5022           * Note: cpu_lwp_fork() has set up a stack frame for us to run
5023           * in, so we can call other functions from here without using
5024           * `save ... restore'.
5025           */
5026
5027          ! newlwp in %l2, oldlwp already in %o0
5028          call      lwp_startup
5029           mov      %l2, %o1
5030
5031          call      %l0
5032           mov      %l1, %o0
5033
5034          /*
5035           * Here we finish up as in syscall, but simplified.
5036           * cpu_lwp_fork() (or sendsig(), if we took a pending signal
5037           * in child_return()) will have set the user-space return
5038           * address in tf_pc. In both cases, %npc should be %pc + 4.
5039           */
5040          rd      %psr, %l2
5041          ld        [%sp + CCFSZ + 4], %l1        ! pc = tf->tf_pc from cpu_lwp_fork()
5042          and       %l2, PSR_CWP, %o1   ! keep current CWP
5043          or        %o1, PSR_S, %l0               ! user psr
5044          b         return_from_syscall
5045           add      %l1, 4, %l2                   ! npc = pc+4
5046
5047/**************************************************************************/
5048
5049#define   UFETCHSTORE_PROLOGUE                                                             \
5050          set       KERNBASE, %o2                                                         ;\
5051          cmp       %o0, %o2            /* if addr >= KERNBASE... */  ;\
5052          bgeu      Lufetchstore_badaddr                                                  ;\
5053           .empty                                                                         ;\
5054          sethi     %hi(cpcb), %o2                /* cpcb->pcb_onfault =          */      ;\
5055          ld        [%o2 + %lo(cpcb)], %o2        /*    Lufetchstore_fault  */  ;\
5056          set       Lufetchstore_fault, %o3                                               ;\
5057          st        %o3, [%o2 + PCB_ONFAULT]
5058
5059          /* keep to a single insn; it's used in a branch delay slot */
5060#define   UFETCHSTORE_EPILOGUE                                                            \
5061          st        %g0, [%o2 + PCB_ONFAULT]! cpcb->pcb_onfault = NULL
5062
5063#define   UFETCHSTORE_RETURN_SUCCESS                                            \
5064          retl                                                                  ;         \
5065           clr      %o0
5066
5067/* LINTSTUB: int _ufetch_8(const uint8_t *uaddr, uint8_t *valp); */
5068ENTRY(_ufetch_8)
5069          UFETCHSTORE_PROLOGUE
5070          ldub      [%o0], %o0                    ! %o0 = *uaddr
5071          UFETCHSTORE_EPILOGUE
5072          stb       %o0, [%o1]                    ! *valp = %o0
5073          UFETCHSTORE_RETURN_SUCCESS
5074
5075/* LINTSTUB: int _ufetch_16(const uint16_t *uaddr, uint16_t *valp); */
5076ENTRY(_ufetch_16)
5077          UFETCHSTORE_PROLOGUE
5078          lduh      [%o0], %o0                    ! %o0 = *uaddr
5079          UFETCHSTORE_EPILOGUE
5080          sth       %o0, [%o1]                    ! *valp = %o0
5081          UFETCHSTORE_RETURN_SUCCESS
5082
5083/* LINTSTUB: int _ufetch_32(const uint32_t *uaddr, uint32_t *valp); */
5084ENTRY(_ufetch_32)
5085          UFETCHSTORE_PROLOGUE
5086          ld        [%o0], %o0                    ! %o0 = *uaddr
5087          UFETCHSTORE_EPILOGUE
5088          st        %o0, [%o1]                    ! *valp = %o0
5089          UFETCHSTORE_RETURN_SUCCESS
5090
5091/* LINTSTUB: int _ustore_8(uint8_t *uaddr, uint8_t val); */
5092ENTRY(_ustore_8)
5093          UFETCHSTORE_PROLOGUE
5094          stb       %o1, [%o0]                    ! *uaddr = val
5095          UFETCHSTORE_EPILOGUE
5096          UFETCHSTORE_RETURN_SUCCESS
5097
5098/* LINTSTUB: int _ustore_16(uint16_t *uaddr, uint16_t val); */
5099ENTRY(_ustore_16)
5100          UFETCHSTORE_PROLOGUE
5101          sth       %o1, [%o0]                    ! *uaddr = val
5102          UFETCHSTORE_EPILOGUE
5103          UFETCHSTORE_RETURN_SUCCESS
5104
5105/* LINTSTUB: int _ustore_32(uint32_t *uaddr, uint32_t val); */
5106ENTRY(_ustore_32)
5107          UFETCHSTORE_PROLOGUE
5108          st        %o1, [%o0]                    ! *uaddr = val
5109          UFETCHSTORE_EPILOGUE
5110          UFETCHSTORE_RETURN_SUCCESS
5111
5112Lufetchstore_badaddr:
5113          retl                                    ! return EFAULT
5114           mov      EFAULT, %o0
5115
5116Lufetchstore_fault:
5117          retl
5118           UFETCHSTORE_EPILOGUE                   ! error already in %o0
5119
5120/**************************************************************************/
5121
5122/* probeget and probeset are meant to be used during autoconfiguration */
5123
5124          .globl    _C_LABEL(sparc_fsbail)
5125_C_LABEL(sparc_fsbail):
5126          st        %g0, [%o2 + PCB_ONFAULT]! error in r/w, clear pcb_onfault
5127          retl                                    ! and return error indicator
5128           mov      -1, %o0
5129
5130/*
5131 * probeget(addr, size) void *addr; int size;
5132 *
5133 * Read or write a (byte,word,longword) from the given address.
5134 * Like {fu,su}{byte,halfword,word} but our caller is supposed
5135 * to know what he is doing... the address can be anywhere.
5136 *
5137 * We optimize for space, rather than time, here.
5138 */
5139ENTRY(probeget)
5140          ! %o0 = addr, %o1 = (1,2,4)
5141          sethi     %hi(cpcb), %o2
5142          ld        [%o2 + %lo(cpcb)], %o2        ! cpcb->pcb_onfault = sparc_fsbail;
5143          set       sparc_fsbail, %o5
5144          st        %o5, [%o2 + PCB_ONFAULT]
5145          btst      1, %o1
5146          bnz,a     0f                            ! if (len & 1)
5147           ldub     [%o0], %o0                    !         value = *(char *)addr;
51480:        btst      2, %o1
5149          bnz,a     0f                            ! if (len & 2)
5150           lduh     [%o0], %o0                    !         value = *(short *)addr;
51510:        btst      4, %o1
5152          bnz,a     0f                            ! if (len & 4)
5153           ld       [%o0], %o0                    !         value = *(int *)addr;
51540:        retl                                    ! made it, clear onfault and return
5155           st       %g0, [%o2 + PCB_ONFAULT]
5156
5157/*
5158 * probeset(addr, size, val) void *addr; int size, val;
5159 *
5160 * As above, but we return 0 on success.
5161 */
5162ENTRY(probeset)
5163          ! %o0 = addr, %o1 = (1,2,4), %o2 = val
5164          sethi     %hi(cpcb), %o3
5165          ld        [%o3 + %lo(cpcb)], %o3        ! cpcb->pcb_onfault = sparc_fsbail;
5166          set       sparc_fsbail, %o5
5167          st        %o5, [%o3 + PCB_ONFAULT]
5168          btst      1, %o1
5169          bnz,a     0f                            ! if (len & 1)
5170           stb      %o2, [%o0]                    !         *(char *)addr = value;
51710:        btst      2, %o1
5172          bnz,a     0f                            ! if (len & 2)
5173           sth      %o2, [%o0]                    !         *(short *)addr = value;
51740:        btst      4, %o1
5175          bnz,a     0f                            ! if (len & 4)
5176           st       %o2, [%o0]                    !         *(int *)addr = value;
51770:        clr       %o0                           ! made it, clear onfault and return 0
5178          retl
5179           st       %g0, [%o3 + PCB_ONFAULT]
5180
5181/*
5182 * int xldcontrolb(void *, pcb)
5183 *                      %o0     %o1
5184 *
5185 * read a byte from the specified address in ASI_CONTROL space.
5186 */
5187ENTRY(xldcontrolb)
5188          !sethi    %hi(cpcb), %o2
5189          !ld       [%o2 + %lo(cpcb)], %o2        ! cpcb->pcb_onfault = sparc_fsbail;
5190          or        %o1, %g0, %o2                 ! %o2 = %o1
5191          set       _C_LABEL(sparc_fsbail), %o5
5192          st        %o5, [%o2 + PCB_ONFAULT]
5193          lduba     [%o0] ASI_CONTROL, %o0        ! read
51940:        retl
5195           st       %g0, [%o2 + PCB_ONFAULT]
5196
5197/*
5198 * int fkbyte(void *, pcb)
5199 *              %o0      %o1
5200 *
5201 * Just like fubyte(), but for kernel space.
5202 * (currently used to work around unexplained transient bus errors
5203 *  when reading the VME interrupt vector)
5204 */
5205ENTRY(fkbyte)
5206          or        %o1, %g0, %o2                 ! %o2 = %o1
5207          set       _C_LABEL(sparc_fsbail), %o5
5208          st        %o5, [%o2 + PCB_ONFAULT]
5209          ldub      [%o0], %o0                    ! fetch the byte
5210          retl                                    ! made it
5211           st       %g0, [%o2 + PCB_ONFAULT]! but first clear onfault
5212
5213
5214/*
5215 * copywords(src, dst, nbytes)
5216 *
5217 * Copy `nbytes' bytes from src to dst, both of which are word-aligned;
5218 * nbytes is a multiple of four.  It may, however, be zero, in which case
5219 * nothing is to be copied.
5220 */
5221ENTRY(copywords)
5222          ! %o0 = src, %o1 = dst, %o2 = nbytes
5223          b         1f
5224          deccc     4, %o2
52250:
5226          st        %o3, [%o1 + %o2]
5227          deccc     4, %o2                        ! while ((n -= 4) >= 0)
52281:
5229          bge,a     0b                            !    *(int *)(dst+n) = *(int *)(src+n);
5230          ld        [%o0 + %o2], %o3
5231          retl
5232          nop
5233
5234/*
5235 * qcopy(src, dst, nbytes)
5236 *
5237 * (q for `quad' or `quick', as opposed to b for byte/block copy)
5238 *
5239 * Just like copywords, but everything is multiples of 8.
5240 */
5241ENTRY(qcopy)
5242          b         1f
5243          deccc     8, %o2
52440:
5245          std       %o4, [%o1 + %o2]
5246          deccc     8, %o2
52471:
5248          bge,a     0b
5249          ldd       [%o0 + %o2], %o4
5250          retl
5251          nop
5252
5253/*
5254 * qzero(addr, nbytes)
5255 *
5256 * Zeroes `nbytes' bytes of a quad-aligned virtual address,
5257 * where nbytes is itself a multiple of 8.
5258 */
5259ENTRY(qzero)
5260          ! %o0 = addr, %o1 = len (in bytes)
5261          clr       %g1
52620:
5263          deccc     8, %o1                        ! while ((n =- 8) >= 0)
5264          bge,a     0b
5265          std       %g0, [%o0 + %o1]    !         *(quad *)(addr + n) = 0;
5266          retl
5267          nop
5268
5269/*
5270 * kernel bcopy
5271 * Assumes regions do not overlap; has no useful return value.
5272 *
5273 * Must not use %g7 (see copyin/copyout above).
5274 */
5275
5276#define   BCOPY_SMALL         32        /* if < 32, copy by bytes */
5277
5278ENTRY(bcopy)
5279          cmp       %o2, BCOPY_SMALL
5280          bge,a     Lbcopy_fancy        ! if >= this many, go be fancy.
5281          btst      7, %o0              ! (part of being fancy)
5282
5283          /*
5284           * Not much to copy, just do it a byte at a time.
5285           */
5286          deccc     %o2                 ! while (--len >= 0)
5287          bl        1f
5288           .empty
52890:
5290          inc       %o0
5291          ldsb      [%o0 - 1], %o4      !         (++dst)[-1] = *src++;
5292          stb       %o4, [%o1]
5293          deccc     %o2
5294          bge       0b
5295          inc       %o1
52961:
5297          retl
5298           nop
5299          /* NOTREACHED */
5300
5301          /*
5302           * Plenty of data to copy, so try to do it optimally.
5303           */
5304Lbcopy_fancy:
5305          ! check for common case first: everything lines up.
5306!         btst      7, %o0              ! done already
5307          bne       1f
5308           .empty
5309          btst      7, %o1
5310          be,a      Lbcopy_doubles
5311          dec       8, %o2              ! if all lined up, len -= 8, goto bcopy_doubes
5312
5313          ! If the low bits match, we can make these line up.
53141:
5315          xor       %o0, %o1, %o3       ! t = src ^ dst;
5316          btst      1, %o3              ! if (t & 1) {
5317          be,a      1f
5318          btst      1, %o0              ! [delay slot: if (src & 1)]
5319
5320          ! low bits do not match, must copy by bytes.
53210:
5322          ldsb      [%o0], %o4          !         do {
5323          inc       %o0                 !                   (++dst)[-1] = *src++;
5324          inc       %o1
5325          deccc     %o2
5326          bnz       0b                  !         } while (--len != 0);
5327          stb       %o4, [%o1 - 1]
5328          retl
5329           nop
5330          /* NOTREACHED */
5331
5332          ! lowest bit matches, so we can copy by words, if nothing else
53331:
5334          be,a      1f                  ! if (src & 1) {
5335          btst      2, %o3              ! [delay slot: if (t & 2)]
5336
5337          ! although low bits match, both are 1: must copy 1 byte to align
5338          ldsb      [%o0], %o4          !         *dst++ = *src++;
5339          stb       %o4, [%o1]
5340          inc       %o0
5341          inc       %o1
5342          dec       %o2                 !         len--;
5343          btst      2, %o3              ! } [if (t & 2)]
53441:
5345          be,a      1f                  ! if (t & 2) {
5346          btst      2, %o0              ! [delay slot: if (src & 2)]
5347          dec       2, %o2              !         len -= 2;
53480:
5349          ldsh      [%o0], %o4          !         do {
5350          sth       %o4, [%o1]          !                   *(short *)dst = *(short *)src;
5351          inc       2, %o0              !                   dst += 2, src += 2;
5352          deccc     2, %o2              !         } while ((len -= 2) >= 0);
5353          bge       0b
5354          inc       2, %o1
5355          b         Lbcopy_mopb         !         goto mop_up_byte;
5356          btst      1, %o2              ! } [delay slot: if (len & 1)]
5357          /* NOTREACHED */
5358
5359          ! low two bits match, so we can copy by longwords
53601:
5361          be,a      1f                  ! if (src & 2) {
5362          btst      4, %o3              ! [delay slot: if (t & 4)]
5363
5364          ! although low 2 bits match, they are 10: must copy one short to align
5365          ldsh      [%o0], %o4          !         (*short *)dst = *(short *)src;
5366          sth       %o4, [%o1]
5367          inc       2, %o0              !         dst += 2;
5368          inc       2, %o1              !         src += 2;
5369          dec       2, %o2              !         len -= 2;
5370          btst      4, %o3              ! } [if (t & 4)]
53711:
5372          be,a      1f                  ! if (t & 4) {
5373          btst      4, %o0              ! [delay slot: if (src & 4)]
5374          dec       4, %o2              !         len -= 4;
53750:
5376          ld        [%o0], %o4          !         do {
5377          st        %o4, [%o1]          !                   *(int *)dst = *(int *)src;
5378          inc       4, %o0              !                   dst += 4, src += 4;
5379          deccc     4, %o2              !         } while ((len -= 4) >= 0);
5380          bge       0b
5381          inc       4, %o1
5382          b         Lbcopy_mopw         !         goto mop_up_word_and_byte;
5383          btst      2, %o2              ! } [delay slot: if (len & 2)]
5384          /* NOTREACHED */
5385
5386          ! low three bits match, so we can copy by doublewords
53871:
5388          be        1f                  ! if (src & 4) {
5389          dec       8, %o2              ! [delay slot: len -= 8]
5390          ld        [%o0], %o4          !         *(int *)dst = *(int *)src;
5391          st        %o4, [%o1]
5392          inc       4, %o0              !         dst += 4, src += 4, len -= 4;
5393          inc       4, %o1
5394          dec       4, %o2              ! }
53951:
5396Lbcopy_doubles:
5397          ldd       [%o0], %o4          ! do {
5398          std       %o4, [%o1]          !         *(double *)dst = *(double *)src;
5399          inc       8, %o0              !         dst += 8, src += 8;
5400          deccc     8, %o2              ! } while ((len -= 8) >= 0);
5401          bge       Lbcopy_doubles
5402          inc       8, %o1
5403
5404          ! check for a usual case again (save work)
5405          btst      7, %o2              ! if ((len & 7) == 0)
5406          be        Lbcopy_done         !         goto bcopy_done;
5407
5408          btst      4, %o2              ! if ((len & 4)) == 0)
5409          be,a      Lbcopy_mopw         !         goto mop_up_word_and_byte;
5410          btst      2, %o2              ! [delay slot: if (len & 2)]
5411          ld        [%o0], %o4          !         *(int *)dst = *(int *)src;
5412          st        %o4, [%o1]
5413          inc       4, %o0              !         dst += 4;
5414          inc       4, %o1              !         src += 4;
5415          btst      2, %o2              ! } [if (len & 2)]
5416
54171:
5418          ! mop up trailing word (if present) and byte (if present).
5419Lbcopy_mopw:
5420          be        Lbcopy_mopb         ! no word, go mop up byte
5421          btst      1, %o2              ! [delay slot: if (len & 1)]
5422          ldsh      [%o0], %o4          ! *(short *)dst = *(short *)src;
5423          be        Lbcopy_done         ! if ((len & 1) == 0) goto done;
5424          sth       %o4, [%o1]
5425          ldsb      [%o0 + 2], %o4      ! dst[2] = src[2];
5426          retl
5427           stb      %o4, [%o1 + 2]
5428          /* NOTREACHED */
5429
5430          ! mop up trailing byte (if present).
5431Lbcopy_mopb:
5432          bne,a     1f
5433          ldsb      [%o0], %o4
5434
5435Lbcopy_done:
5436          retl
5437           nop
5438
54391:
5440          retl
5441           stb      %o4,[%o1]
5442
5443/*
5444 * kcopy() is exactly like bcopy except that it set pcb_onfault such that
5445 * when a fault occurs, it is able to return -1 to indicate this to the
5446 * caller.
5447 */
5448ENTRY(kcopy)
5449          sethi     %hi(cpcb), %o5                ! cpcb->pcb_onfault = Lkcerr;
5450          ld        [%o5 + %lo(cpcb)], %o5
5451          set       Lkcerr, %o3
5452          ld        [%o5 + PCB_ONFAULT], %g1! save current onfault handler
5453          st        %o3, [%o5 + PCB_ONFAULT]
5454
5455          cmp       %o2, BCOPY_SMALL
5456Lkcopy_start:
5457          bge,a     Lkcopy_fancy        ! if >= this many, go be fancy.
5458           btst     7, %o0              ! (part of being fancy)
5459
5460          /*
5461           * Not much to copy, just do it a byte at a time.
5462           */
5463          deccc     %o2                 ! while (--len >= 0)
5464          bl        1f
5465           .empty
54660:
5467          ldsb      [%o0], %o4          !         *dst++ = *src++;
5468          inc       %o0
5469          stb       %o4, [%o1]
5470          deccc     %o2
5471          bge       0b
5472           inc      %o1
54731:
5474          st        %g1, [%o5 + PCB_ONFAULT]      ! restore onfault
5475          retl
5476           mov      0, %o0              ! delay slot: return success
5477          /* NOTREACHED */
5478
5479          /*
5480           * Plenty of data to copy, so try to do it optimally.
5481           */
5482Lkcopy_fancy:
5483          ! check for common case first: everything lines up.
5484!         btst      7, %o0              ! done already
5485          bne       1f
5486           .empty
5487          btst      7, %o1
5488          be,a      Lkcopy_doubles
5489           dec      8, %o2              ! if all lined up, len -= 8, goto bcopy_doubes
5490
5491          ! If the low bits match, we can make these line up.
54921:
5493          xor       %o0, %o1, %o3       ! t = src ^ dst;
5494          btst      1, %o3              ! if (t & 1) {
5495          be,a      1f
5496           btst     1, %o0              ! [delay slot: if (src & 1)]
5497
5498          ! low bits do not match, must copy by bytes.
54990:
5500          ldsb      [%o0], %o4          !         do {
5501          inc       %o0                 !                   *dst++ = *src++;
5502          stb       %o4, [%o1]
5503          deccc     %o2
5504          bnz       0b                  !         } while (--len != 0);
5505           inc      %o1
5506          st        %g1, [%o5 + PCB_ONFAULT]      ! restore onfault
5507          retl
5508           mov      0, %o0              ! delay slot: return success
5509          /* NOTREACHED */
5510
5511          ! lowest bit matches, so we can copy by words, if nothing else
55121:
5513          be,a      1f                  ! if (src & 1) {
5514           btst     2, %o3              ! [delay slot: if (t & 2)]
5515
5516          ! although low bits match, both are 1: must copy 1 byte to align
5517          ldsb      [%o0], %o4          !         *dst++ = *src++;
5518          inc       %o0
5519          stb       %o4, [%o1]
5520          dec       %o2                 !         len--;
5521          inc       %o1
5522          btst      2, %o3              ! } [if (t & 2)]
55231:
5524          be,a      1f                  ! if (t & 2) {
5525           btst     2, %o0              ! [delay slot: if (src & 2)]
5526          dec       2, %o2              !         len -= 2;
55270:
5528          ldsh      [%o0], %o4          !         do {
5529          inc       2, %o0              !                   dst += 2, src += 2;
5530          sth       %o4, [%o1]          !                   *(short *)dst = *(short *)src;
5531          deccc     2, %o2              !         } while ((len -= 2) >= 0);
5532          bge       0b
5533           inc      2, %o1
5534          b         Lkcopy_mopb         !         goto mop_up_byte;
5535           btst     1, %o2              ! } [delay slot: if (len & 1)]
5536          /* NOTREACHED */
5537
5538          ! low two bits match, so we can copy by longwords
55391:
5540          be,a      1f                  ! if (src & 2) {
5541           btst     4, %o3              ! [delay slot: if (t & 4)]
5542
5543          ! although low 2 bits match, they are 10: must copy one short to align
5544          ldsh      [%o0], %o4          !         (*short *)dst = *(short *)src;
5545          inc       2, %o0              !         dst += 2;
5546          sth       %o4, [%o1]
5547          dec       2, %o2              !         len -= 2;
5548          inc       2, %o1              !         src += 2;
5549          btst      4, %o3              ! } [if (t & 4)]
55501:
5551          be,a      1f                  ! if (t & 4) {
5552           btst     4, %o0              ! [delay slot: if (src & 4)]
5553          dec       4, %o2              !         len -= 4;
55540:
5555          ld        [%o0], %o4          !         do {
5556          inc       4, %o0              !                   dst += 4, src += 4;
5557          st        %o4, [%o1]          !                   *(int *)dst = *(int *)src;
5558          deccc     4, %o2              !         } while ((len -= 4) >= 0);
5559          bge       0b
5560           inc      4, %o1
5561          b         Lkcopy_mopw         !         goto mop_up_word_and_byte;
5562           btst     2, %o2              ! } [delay slot: if (len & 2)]
5563          /* NOTREACHED */
5564
5565          ! low three bits match, so we can copy by doublewords
55661:
5567          be        1f                  ! if (src & 4) {
5568           dec      8, %o2              ! [delay slot: len -= 8]
5569          ld        [%o0], %o4          !         *(int *)dst = *(int *)src;
5570          inc       4, %o0              !         dst += 4, src += 4, len -= 4;
5571          st        %o4, [%o1]
5572          dec       4, %o2              ! }
5573          inc       4, %o1
55741:
5575Lkcopy_doubles:
5576          ! swap %o4 with %o2 during doubles copy, since %o5 is verboten
5577          mov     %o2, %o4
5578Lkcopy_doubles2:
5579          ldd       [%o0], %o2          ! do {
5580          inc       8, %o0              !         dst += 8, src += 8;
5581          std       %o2, [%o1]          !         *(double *)dst = *(double *)src;
5582          deccc     8, %o4              ! } while ((len -= 8) >= 0);
5583          bge       Lkcopy_doubles2
5584           inc      8, %o1
5585          mov       %o4, %o2  ! restore len
5586
5587          ! check for a usual case again (save work)
5588          btst      7, %o2              ! if ((len & 7) == 0)
5589          be        Lkcopy_done         !         goto bcopy_done;
5590
5591           btst     4, %o2              ! if ((len & 4)) == 0)
5592          be,a      Lkcopy_mopw         !         goto mop_up_word_and_byte;
5593           btst     2, %o2              ! [delay slot: if (len & 2)]
5594          ld        [%o0], %o4          !         *(int *)dst = *(int *)src;
5595          inc       4, %o0              !         dst += 4;
5596          st        %o4, [%o1]
5597          inc       4, %o1              !         src += 4;
5598          btst      2, %o2              ! } [if (len & 2)]
5599
56001:
5601          ! mop up trailing word (if present) and byte (if present).
5602Lkcopy_mopw:
5603          be        Lkcopy_mopb         ! no word, go mop up byte
5604           btst     1, %o2              ! [delay slot: if (len & 1)]
5605          ldsh      [%o0], %o4          ! *(short *)dst = *(short *)src;
5606          be        Lkcopy_done         ! if ((len & 1) == 0) goto done;
5607           sth      %o4, [%o1]
5608          ldsb      [%o0 + 2], %o4      ! dst[2] = src[2];
5609          stb       %o4, [%o1 + 2]
5610          st        %g1, [%o5 + PCB_ONFAULT]! restore onfault
5611          retl
5612           mov      0, %o0              ! delay slot: return success
5613          /* NOTREACHED */
5614
5615          ! mop up trailing byte (if present).
5616Lkcopy_mopb:
5617          bne,a     1f
5618           ldsb     [%o0], %o4
5619
5620Lkcopy_done:
5621          st        %g1, [%o5 + PCB_ONFAULT]      ! restore onfault
5622          retl
5623           mov      0, %o0              ! delay slot: return success
5624          /* NOTREACHED */
5625
56261:
5627          stb       %o4, [%o1]
5628          st        %g1, [%o5 + PCB_ONFAULT]      ! restore onfault
5629          retl
5630           mov      0, %o0              ! delay slot: return success
5631          /* NOTREACHED */
5632
5633Lkcerr:
5634          retl
5635           st       %g1, [%o5 + PCB_ONFAULT]      ! restore onfault
5636          /* NOTREACHED */
5637
5638/*
5639 * savefpstate(struct fpstate *f);
5640 * ipi_savefpstate(struct fpstate *f);
5641 *
5642 * Store the current FPU state.  The first `st %fsr' may cause a trap;
5643 * our trap handler knows how to recover (by `returning' to savefpcont).
5644 *
5645 * The IPI version just deals with updating event counters first.
5646 */
5647ENTRY(ipi_savefpstate)
5648          sethi     %hi(CPUINFO_VA+CPUINFO_SAVEFPSTATE), %o5
5649          ldd       [%o5 + %lo(CPUINFO_VA+CPUINFO_SAVEFPSTATE)], %o2
5650          inccc   %o3
5651          addx    %o2, 0, %o2
5652          std       %o2, [%o5 + CPUINFO_SAVEFPSTATE]
5653
5654ENTRY(savefpstate)
5655          cmp       %o0, 0
5656          rd        %psr, %o1           ! enable FP before we begin
5657          set       PSR_EF, %o2
5658          or        %o1, %o2, %o1
5659          wr        %o1, 0, %psr
5660          /* do some setup work while we wait for PSR_EF to turn on */
5661          set       FSR_QNE, %o5                  ! QNE = 0x2000, too big for immediate
5662          clr       %o3                           ! qsize = 0;
5663          nop                                     ! (still waiting for PSR_EF)
5664special_fp_store:
5665          st        %fsr, [%o0 + FS_FSR]          ! f->fs_fsr = getfsr();
5666          /*
5667           * Even if the preceding instruction did not trap, the queue
5668           * is not necessarily empty: this state save might be happening
5669           * because user code tried to store %fsr and took the FPU
5670           * from `exception pending' mode to `exception' mode.
5671           * So we still have to check the blasted QNE bit.
5672           * With any luck it will usually not be set.
5673           */
5674          ld        [%o0 + FS_FSR], %o2 ! if (f->fs_fsr & QNE)
5675          btst      %o5, %o2
5676          bnz       Lfp_storeq                    !         goto storeq;
5677           std      %f0, [%o0 + FS_REGS + (4*0)]  ! f->fs_f0 = etc;
5678Lfp_finish:
5679          st        %o3, [%o0 + FS_QSIZE]         ! f->fs_qsize = qsize;
5680          std       %f2, [%o0 + FS_REGS + (4*2)]
5681          std       %f4, [%o0 + FS_REGS + (4*4)]
5682          std       %f6, [%o0 + FS_REGS + (4*6)]
5683          std       %f8, [%o0 + FS_REGS + (4*8)]
5684          std       %f10, [%o0 + FS_REGS + (4*10)]
5685          std       %f12, [%o0 + FS_REGS + (4*12)]
5686          std       %f14, [%o0 + FS_REGS + (4*14)]
5687          std       %f16, [%o0 + FS_REGS + (4*16)]
5688          std       %f18, [%o0 + FS_REGS + (4*18)]
5689          std       %f20, [%o0 + FS_REGS + (4*20)]
5690          std       %f22, [%o0 + FS_REGS + (4*22)]
5691          std       %f24, [%o0 + FS_REGS + (4*24)]
5692          std       %f26, [%o0 + FS_REGS + (4*26)]
5693          std       %f28, [%o0 + FS_REGS + (4*28)]
5694          retl
5695           std      %f30, [%o0 + FS_REGS + (4*30)]
5696
5697/*
5698 * Store the (now known nonempty) FP queue.
5699 * We have to reread the fsr each time in order to get the new QNE bit.
5700 */
5701Lfp_storeq:
5702          add       %o0, FS_QUEUE, %o1  ! q = &f->fs_queue[0];
57031:
5704          std       %fq, [%o1 + %o3]    ! q[qsize++] = fsr_qfront();
5705          st        %fsr, [%o0 + FS_FSR]          ! reread fsr
5706          ld        [%o0 + FS_FSR], %o4 ! if fsr & QNE, loop
5707          btst      %o5, %o4
5708          bnz       1b
5709           inc      8, %o3
5710          st        %o2, [%o0 + FS_FSR] ! fs->fs_fsr = original_fsr
5711          b         Lfp_finish                    ! set qsize and finish storing fregs
5712           srl      %o3, 3, %o3                   ! (but first fix qsize)
5713
5714/*
5715 * The fsr store trapped.  Do it again; this time it will not trap.
5716 * We could just have the trap handler return to the `st %fsr', but
5717 * if for some reason it *does* trap, that would lock us into a tight
5718 * loop.  This way we panic instead.  Whoopee.
5719 */
5720savefpcont:
5721          b         special_fp_store + 4          ! continue
5722           st       %fsr, [%o0 + FS_FSR]          ! but first finish the %fsr store
5723
5724/*
5725 * Load FPU state.
5726 */
5727ENTRY(loadfpstate)
5728          rd        %psr, %o1           ! enable FP before we begin
5729          set       PSR_EF, %o2
5730          or        %o1, %o2, %o1
5731          wr        %o1, 0, %psr
5732          nop; nop; nop                           ! paranoia
5733          ldd       [%o0 + FS_REGS + (4*0)], %f0
5734          ldd       [%o0 + FS_REGS + (4*2)], %f2
5735          ldd       [%o0 + FS_REGS + (4*4)], %f4
5736          ldd       [%o0 + FS_REGS + (4*6)], %f6
5737          ldd       [%o0 + FS_REGS + (4*8)], %f8
5738          ldd       [%o0 + FS_REGS + (4*10)], %f10
5739          ldd       [%o0 + FS_REGS + (4*12)], %f12
5740          ldd       [%o0 + FS_REGS + (4*14)], %f14
5741          ldd       [%o0 + FS_REGS + (4*16)], %f16
5742          ldd       [%o0 + FS_REGS + (4*18)], %f18
5743          ldd       [%o0 + FS_REGS + (4*20)], %f20
5744          ldd       [%o0 + FS_REGS + (4*22)], %f22
5745          ldd       [%o0 + FS_REGS + (4*24)], %f24
5746          ldd       [%o0 + FS_REGS + (4*26)], %f26
5747          ldd       [%o0 + FS_REGS + (4*28)], %f28
5748          ldd       [%o0 + FS_REGS + (4*30)], %f30
5749          retl
5750           ld       [%o0 + FS_FSR], %fsr          ! setfsr(f->fs_fsr);
5751
5752/*
5753 * ienab_bis(bis) int bis;
5754 * ienab_bic(bic) int bic;
5755 *
5756 * Set and clear bits in the sun4/sun4c interrupt register.
5757 */
5758
5759#if defined(SUN4) || defined(SUN4C)
5760/*
5761 * Since there are no read-modify-write instructions for this,
5762 * and one of the interrupts is nonmaskable, we must disable traps.
5763 */
5764ENTRY(ienab_bis)
5765          ! %o0 = bits to set
5766          rd        %psr, %o2
5767          wr        %o2, PSR_ET, %psr   ! disable traps
5768          nop; nop                      ! 3-instr delay until ET turns off
5769          sethi     %hi(INTRREG_VA), %o3
5770          ldub      [%o3 + %lo(INTRREG_VA)], %o4
5771          or        %o4, %o0, %o4                 ! *INTRREG_VA |= bis;
5772          stb       %o4, [%o3 + %lo(INTRREG_VA)]
5773          wr        %o2, 0, %psr                  ! reenable traps
5774          nop
5775          retl
5776           nop
5777
5778ENTRY(ienab_bic)
5779          ! %o0 = bits to clear
5780          rd        %psr, %o2
5781          wr        %o2, PSR_ET, %psr   ! disable traps
5782          nop; nop
5783          sethi     %hi(INTRREG_VA), %o3
5784          ldub      [%o3 + %lo(INTRREG_VA)], %o4
5785          andn      %o4, %o0, %o4                 ! *INTRREG_VA &=~ bic;
5786          stb       %o4, [%o3 + %lo(INTRREG_VA)]
5787          wr        %o2, 0, %psr                  ! reenable traps
5788          nop
5789          retl
5790           nop
5791#endif    /* SUN4 || SUN4C */
5792
5793#if defined(SUN4M)
5794/*
5795 * raise(cpu, level)
5796 */
5797ENTRY(raise)
5798#if !defined(MSIIEP) /* normal suns */
5799          ! *(ICR_PI_SET + cpu*_MAXNBPG) = PINTR_SINTRLEV(level)
5800          sethi     %hi(1 << 16), %o2
5801          sll       %o2, %o1, %o2
5802          set       ICR_PI_SET, %o1
5803          set       _MAXNBPG, %o3
58041:
5805          subcc     %o0, 1, %o0
5806          bpos,a    1b
5807           add      %o1, %o3, %o1
5808          retl
5809           st       %o2, [%o1]
5810#else /* MSIIEP - ignore %o0, only one CPU ever */
5811          mov       1, %o2
5812          xor       %o1, 8, %o1         ! change 'endianness' of the shift distance
5813          sethi     %hi(MSIIEP_PCIC_VA), %o0
5814          sll       %o2, %o1, %o2
5815          retl
5816           sth      %o2, [%o0 + PCIC_SOFT_INTR_SET_REG]
5817#endif
5818
5819/*
5820 * Read Synchronous Fault Status registers.
5821 * On entry: %l1 == PC, %l3 == fault type, %l4 == storage, %l7 == return address
5822 * Only use %l5 and %l6.
5823 * Note: not C callable.
5824 */
5825_ENTRY(_C_LABEL(srmmu_get_syncflt))
5826_ENTRY(_C_LABEL(hypersparc_get_syncflt))
5827          set       SRMMU_SFAR, %l5
5828          lda       [%l5] ASI_SRMMU, %l5          ! sync virt addr; must be read first
5829          st        %l5, [%l4 + 4]                ! => dump.sfva
5830          set       SRMMU_SFSR, %l5
5831          lda       [%l5] ASI_SRMMU, %l5          ! get sync fault status register
5832          jmp       %l7 + 8                       ! return to caller
5833           st       %l5, [%l4]                    ! => dump.sfsr
5834
5835_ENTRY(_C_LABEL(viking_get_syncflt))
5836_ENTRY(_C_LABEL(ms1_get_syncflt))
5837_ENTRY(_C_LABEL(swift_get_syncflt))
5838_ENTRY(_C_LABEL(turbosparc_get_syncflt))
5839_ENTRY(_C_LABEL(cypress_get_syncflt))
5840          cmp       %l3, T_TEXTFAULT
5841          be,a      1f
5842           mov      %l1, %l5            ! use PC if type == T_TEXTFAULT
5843
5844          set       SRMMU_SFAR, %l5
5845          lda       [%l5] ASI_SRMMU, %l5          ! sync virt addr; must be read first
58461:
5847          st        %l5, [%l4 + 4]                ! => dump.sfva
5848
5849          set       SRMMU_SFSR, %l5
5850          lda       [%l5] ASI_SRMMU, %l5          ! get sync fault status register
5851          jmp       %l7 + 8                       ! return to caller
5852           st       %l5, [%l4]                    ! => dump.sfsr
5853
5854#if defined(MULTIPROCESSOR) && 0 /* notyet */
5855/*
5856 * Read Synchronous Fault Status registers.
5857 * On entry: %o0 == &sfsr, %o1 == &sfar
5858 */
5859_ENTRY(_C_LABEL(smp_get_syncflt))
5860          save    %sp, -CCFSZ, %sp
5861
5862          sethi     %hi(CPUINFO_VA+CPUINFO_GETSYNCFLT), %o4
5863          ld        [%l4 + %lo(CPUINFO_VA+CPUINFO_GETSYNCFLT)], %o5
5864          clr       %l1
5865          clr       %l3
5866          sethi     %hi(CPUINFO_VA+CPUINFO_SYNCFLTDUMP), %o4
5867          jmpl      %o5, %l7
5868           or       %o4, %lo(CPUINFO_VA+CPUINFO_SYNCFLTDUMP), %l4
5869
5870          ! load values out of the dump
5871          sethi     %hi(CPUINFO_VA+CPUINFO_SYNCFLTDUMP), %o4
5872          ld        [%o4 + %lo(CPUINFO_VA+CPUINFO_SYNCFLTDUMP)], %o5
5873          st        %o5, [%i0]
5874          sethi     %hi(CPUINFO_VA+CPUINFO_SYNCFLTDUMP+4), %o4
5875          ld        [%o4 + %lo(CPUINFO_VA+CPUINFO_SYNCFLTDUMP+4)], %o5
5876          st        %o5, [%i1]
5877          ret
5878           restore
5879#endif /* MULTIPROCESSOR */
5880
5881/*
5882 * Read Asynchronous Fault Status registers.
5883 * On entry: %o0 == &afsr, %o1 == &afar
5884 * Return 0 if async register are present.
5885 */
5886_ENTRY(_C_LABEL(srmmu_get_asyncflt))
5887          set       SRMMU_AFAR, %o4
5888          lda       [%o4] ASI_SRMMU, %o4          ! get async fault address
5889          set       SRMMU_AFSR, %o3     !
5890          st        %o4, [%o1]
5891          lda       [%o3] ASI_SRMMU, %o3          ! get async fault status
5892          st        %o3, [%o0]
5893          retl
5894           clr      %o0                           ! return value
5895
5896_ENTRY(_C_LABEL(cypress_get_asyncflt))
5897_ENTRY(_C_LABEL(hypersparc_get_asyncflt))
5898          set       SRMMU_AFSR, %o3               ! must read status before fault on HS
5899          lda       [%o3] ASI_SRMMU, %o3          ! get async fault status
5900          st        %o3, [%o0]
5901          btst      AFSR_AFO, %o3                 ! and only read fault address
5902          bz        1f                            ! if valid.
5903          set       SRMMU_AFAR, %o4
5904          lda       [%o4] ASI_SRMMU, %o4          ! get async fault address
5905          clr       %o0                           ! return value
5906          retl
5907           st       %o4, [%o1]
59081:
5909          retl
5910           clr      %o0                           ! return value
5911
5912_ENTRY(_C_LABEL(no_asyncflt_regs))
5913          retl
5914           mov      1, %o0                        ! return value
5915
5916_ENTRY(_C_LABEL(hypersparc_pure_vcache_flush))
5917          /*
5918           * Flush entire on-chip instruction cache, which is
5919           * a pure vitually-indexed/virtually-tagged cache.
5920           */
5921          retl
5922           sta      %g0, [%g0] ASI_HICACHECLR
5923
5924#endif /* SUN4M */
5925
5926
5927/*
5928 * delay function
5929 *
5930 * void delay(N)  -- delay N microseconds
5931 *
5932 * Register usage: %o0 = "N" number of usecs to go (counts down to zero)
5933 *                     %o1 = "timerblurb" (stays constant)
5934 *                     %o2 = counter for 1 usec (counts down from %o1 to zero)
5935 *
5936 */
5937
5938ENTRY(delay)                            ! %o0 = n
5939          subcc     %o0, %g0, %g0
5940          be        2f
5941
5942          sethi     %hi(_C_LABEL(timerblurb)), %o1
5943          ld        [%o1 + %lo(_C_LABEL(timerblurb))], %o1  ! %o1 = timerblurb
5944
5945           addcc    %o1, %g0, %o2                 ! %o2 = cntr (start @ %o1), clear CCs
5946                                                  ! first time through only
5947
5948                                                  ! delay 1 usec
59491:        bne       1b                            ! come back here if not done
5950           subcc    %o2, 1, %o2                   ! %o2 = %o2 - 1 [delay slot]
5951
5952          subcc     %o0, 1, %o0                   ! %o0 = %o0 - 1
5953          bne       1b                            ! done yet?
5954           addcc    %o1, %g0, %o2                 ! reinit %o2 and CCs  [delay slot]
5955                                                  ! harmless if not branching
59562:
5957          retl                                    ! return
5958           nop                                    ! [delay slot]
5959
5960
5961/*
5962 * void __cpu_simple_lock(__cpu_simple_lock_t *alp)
5963 */
5964ENTRY_NOPROFILE(__cpu_simple_lock)
59650:
5966          ldstub    [%o0], %o1
5967          tst       %o1
5968          bnz,a     2f
5969           ldub     [%o0], %o1
59701:
5971          retl
5972           .empty
59732:
5974          set       0x1000000, %o2      ! set spinout counter
59753:
5976          tst       %o1
5977          bz        0b                  ! lock has been released; try again
5978          deccc     %o2
5979          bcc,a     3b                  ! repeat until counter < 0
5980           ldub     [%o0], %o1
5981
5982          ! spun out; check if already panicking
5983          sethi     %hi(_C_LABEL(panicstr)), %o2
5984          ld        [%o2 + %lo(_C_LABEL(panicstr))], %o1
5985          tst       %o1
5986          ! if so, just take the lock and return on the assumption that
5987          ! in panic mode we're running on a single CPU anyway.
5988          bnz,a     1b
5989           ldstub   [%o0], %g0
5990
5991          ! set up stack frame and call panic
5992          save      %sp, -CCFSZ, %sp
5993          sethi     %hi(CPUINFO_VA + CPUINFO_CPUNO), %o0
5994          ld        [%o0 + %lo(CPUINFO_VA + CPUINFO_CPUNO)], %o1
5995          mov       %i0, %o2
5996          sethi     %hi(Lpanic_spunout), %o0
5997          call      _C_LABEL(panic)
5998          or        %o0, %lo(Lpanic_spunout), %o0
5999
6000Lpanic_spunout:
6001          .asciz    "cpu%d: stuck on lock@%x"
6002          _ALIGN
6003
6004#if defined(KGDB) || defined(DDB) || defined(DIAGNOSTIC)
6005/*
6006 * Write all windows (user or otherwise), except the current one.
6007 *
6008 * THIS COULD BE DONE IN USER CODE
6009 */
6010ENTRY(write_all_windows)
6011          /*
6012           * g2 = g1 = nwindows - 1;
6013           * while (--g1 > 0) save();
6014           * while (--g2 > 0) restore();
6015           */
6016          sethi     %hi(_C_LABEL(nwindows)), %g1
6017          ld        [%g1 + %lo(_C_LABEL(nwindows))], %g1
6018          dec       %g1
6019          mov       %g1, %g2
6020
60211:        deccc     %g1
6022          bg,a      1b
6023           save     %sp, -64, %sp
6024
60252:        deccc     %g2
6026          bg,a      2b
6027           restore
6028
6029          retl
6030          nop
6031#endif /* KGDB */
6032
6033ENTRY(setjmp)
6034          st        %sp, [%o0+0]        ! stack pointer
6035          st        %o7, [%o0+4]        ! return pc
6036          st        %fp, [%o0+8]        ! frame pointer
6037          retl
6038           clr      %o0
6039
6040Lpanic_ljmp:
6041          .asciz    "longjmp botch"
6042          _ALIGN
6043
6044ENTRY(longjmp)
6045          mov       %o0, %g1  ! save a in a global register
6046          ld        [%g1+8], %g7        /* get caller's frame */
60471:
6048          cmp       %fp, %g7  ! compare against desired frame
6049          bl,a      1b                  ! if below,
6050           restore            !    pop frame and loop
6051          ld        [%g1+0], %o2        ! fetch return %sp
6052          be,a      2f                  ! we're there, get out
6053           ld       [%g1+4], %o3        ! fetch return pc
6054
6055Llongjmpbotch:
6056                                        ! otherwise, went too far; bomb out
6057          save      %sp, -CCFSZ, %sp    /* preserve current window */
6058          sethi     %hi(Lpanic_ljmp), %o0
6059          call      _C_LABEL(panic)
6060          or %o0, %lo(Lpanic_ljmp), %o0;
6061          unimp     0
6062
60632:
6064          cmp       %o2, %sp  ! %sp must not decrease
6065          bge,a     3f
6066           mov      %o2, %sp  ! it is OK, put it in place
6067          b,a       Llongjmpbotch
60683:
6069          jmp       %o3 + 8             ! success, return 1
6070           mov      1, %o0
6071
6072          .data
6073          .globl    _C_LABEL(kernel_top)
6074_C_LABEL(kernel_top):
6075          .word     0
6076          .globl    _C_LABEL(bootinfo)
6077_C_LABEL(bootinfo):
6078          .word     0
6079
6080          .comm     _C_LABEL(nwindows), 4
6081          .comm     _C_LABEL(romp), 4
6082