1/*        $NetBSD: locore.s,v 1.435 2025/04/29 14:53:54 martin Exp $  */
2
3/*
4 * Copyright (c) 2006-2010 Matthew R. Green
5 * Copyright (c) 1996-2002 Eduardo Horvath
6 * Copyright (c) 1996 Paul Kranenburg
7 * Copyright (c) 1996
8 *        The President and Fellows of Harvard College.
9 *        All rights reserved.
10 * Copyright (c) 1992, 1993
11 *        The Regents of the University of California.
12 *        All rights reserved.
13 *
14 * This software was developed by the Computer Systems Engineering group
15 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
16 * contributed to Berkeley.
17 *
18 * All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 *        This product includes software developed by the University of
21 *        California, Lawrence Berkeley Laboratory.
22 *        This product includes software developed by Harvard University.
23 *
24 * Redistribution and use in source and binary forms, with or without
25 * modification, are permitted provided that the following conditions
26 * are met:
27 * 1. Redistributions of source code must retain the above copyright
28 *    notice, this list of conditions and the following disclaimer.
29 * 2. Redistributions in binary form must reproduce the above copyright
30 *    notice, this list of conditions and the following disclaimer in the
31 *    documentation and/or other materials provided with the
32 *    distribution.
33 * 3. All advertising materials mentioning features or use of this
34 *    software must display the following acknowledgement:
35 *        This product includes software developed by the University of
36 *        California, Berkeley and its contributors.
37 *        This product includes software developed by Harvard University.
38 *        This product includes software developed by Paul Kranenburg.
39 * 4. Neither the name of the University nor the names of its
40 *    contributors may be used to endorse or promote products derived
41 *    from this software without specific prior written permission.
42 *
43 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS''
44 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
45 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
46 * PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR
47 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
48 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
49 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
50 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
51 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
52 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
53 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
54 * DAMAGE.
55 *
56 *        @(#)locore.s        8.4 (Berkeley) 12/10/93
57 */
58
59#undef    PARANOID            /* Extremely expensive consistency checks */
60#undef    NO_VCACHE           /* Map w/D$ disabled */
61#undef    TRAPSTATS           /* Count traps */
62#undef    TRAPS_USE_IG                  /* Use Interrupt Globals for all traps */
63#define   HWREF                         /* Track ref/mod bits in trap handlers */
64#undef    DCACHE_BUG                    /* Flush D$ around ASI_PHYS accesses */
65#undef    NO_TSB                        /* Don't use TSB */
66#define   BB_ERRATA_1                   /* writes to TICK_CMPR may fail */
67#undef    TLB_FLUSH_LOWVA               /* also flush 32-bit entries from the MMU */
68
69#include "opt_ddb.h"
70#include "opt_kgdb.h"
71#include "opt_multiprocessor.h"
72#include "opt_compat_netbsd.h"
73#include "opt_compat_netbsd32.h"
74#include "opt_lockdebug.h"
75
76#include "assym.h"
77#include <machine/param.h>
78#include <machine/types.h>
79#include <sparc64/sparc64/intreg.h>
80#include <sparc64/sparc64/timerreg.h>
81#include <machine/ctlreg.h>
82#include <machine/psl.h>
83#include <machine/signal.h>
84#include <machine/trap.h>
85#include <machine/frame.h>
86#include <machine/pmap.h>
87#include <machine/intr.h>
88#include <machine/asm.h>
89#include <machine/locore.h>
90#ifdef SUN4V
91#include <machine/hypervisor.h>
92#endif
93#include <sys/syscall.h>
94
95#define BLOCK_SIZE SPARC64_BLOCK_SIZE
96#define BLOCK_ALIGN SPARC64_BLOCK_ALIGN
97
98#ifdef SUN4V
99#define SUN4V_N_REG_WINDOWS    8  /* As per UA2005 spec */
100#define SUN4V_NWINDOWS           (SUN4V_N_REG_WINDOWS-1) /* This is an index number, so subtract one */
101#endif
102
103#include "ksyms.h"
104
105          /* Misc. macros */
106
107          .macro    GET_MAXCWP reg
108#ifdef SUN4V
109          sethi     %hi(cputyp), \reg
110          ld        [\reg + %lo(cputyp)], \reg
111          cmp       \reg, CPU_SUN4V
112          bne,pt    %icc, 2f
113           nop
114          /* sun4v */
115          ba        3f
116           mov      SUN4V_NWINDOWS, \reg
1172:
118#endif
119          /* sun4u */
120          rdpr      %ver, \reg
121          and       \reg, CWP, \reg
1223:
123          .endm
124
125          .macro    SET_MMU_CONTEXTID_SUN4U ctxid,ctx
126          stxa      \ctxid, [\ctx] ASI_DMMU;
127          .endm
128
129#ifdef SUN4V
130          .macro    SET_MMU_CONTEXTID_SUN4V ctxid,ctx
131          stxa      \ctxid, [\ctx] ASI_MMU_CONTEXTID;
132          .endm
133#endif
134
135          .macro    SET_MMU_CONTEXTID ctxid,ctx,scratch
136#ifdef SUN4V
137          sethi     %hi(cputyp), \scratch
138          ld        [\scratch + %lo(cputyp)], \scratch
139          cmp       \scratch, CPU_SUN4V
140          bne,pt    %icc, 2f
141           nop
142          /* sun4v */
143          SET_MMU_CONTEXTID_SUN4V \ctxid,\ctx
144          ba        3f
145           nop
1462:
147#endif
148          /* sun4u */
149          SET_MMU_CONTEXTID_SUN4U \ctxid,\ctx
1503:
151          .endm
152
153          .macro    GET_MMU_CONTEXTID_SUN4U ctxid,ctx
154          ldxa      [\ctx] ASI_DMMU, \ctxid
155          .endm
156
157#ifdef SUN4V
158          .macro    GET_MMU_CONTEXTID_SUN4V ctxid,ctx
159          ldxa      [\ctx] ASI_MMU_CONTEXTID, \ctxid
160          .endm
161#endif
162
163          .macro    GET_MMU_CONTEXTID ctxid,ctx,scratch
164#ifdef SUN4V
165          sethi     %hi(cputyp), \scratch
166          ld        [\scratch + %lo(cputyp)], \scratch
167          cmp       \scratch, CPU_SUN4V
168          bne,pt    %icc, 2f
169           nop
170          /* sun4v */
171          GET_MMU_CONTEXTID_SUN4V \ctxid,\ctx
172          ba        3f
173           nop
1742:
175#endif
176          /* sun4u */
177          GET_MMU_CONTEXTID_SUN4U \ctxid,\ctx
1783:
179          .endm
180
181#ifdef SUN4V
182          .macro    NORMAL_GLOBALS_SUN4V
183           wrpr     %g0, 0, %gl                                       ! Set globals to level 0
184          .endm
185#endif
186          .macro    NORMAL_GLOBALS_SUN4U
187          wrpr      %g0, PSTATE_KERN, %pstate               ! Alternate Globals (AG) bit set to zero
188          .endm
189
190#ifdef SUN4V
191          .macro    ALTERNATE_GLOBALS_SUN4V
192           wrpr     %g0, 1, %gl                                       ! Set globals to level 1
193          .endm
194#endif
195          .macro    ALTERNATE_GLOBALS_SUN4U
196           wrpr    %g0, PSTATE_KERN|PSTATE_AG, %pstate      ! Alternate Globals (AG) bit set to one
197          .endm
198
199          .macro    ENABLE_INTERRUPTS scratch
200          rdpr       %pstate, \scratch
201          or        \scratch, PSTATE_IE, \scratch ! Interrupt Enable (IE) bit set to one
202          wrpr      %g0, \scratch, %pstate
203          .endm
204
205          .macro    DISABLE_INTERRUPTS scratch
206          rdpr       %pstate, \scratch
207          and       \scratch, ~PSTATE_IE, \scratch          ! Interrupt Enable (IE) bit set to zero
208          wrpr      %g0, \scratch, %pstate
209          .endm
210
211
212#ifdef SUN4V
213          /* Misc. sun4v macros */
214
215          .macro    GET_MMFSA reg
216          sethi     %hi(CPUINFO_VA + CI_MMUFSA), \reg
217          LDPTR     [\reg + %lo(CPUINFO_VA + CI_MMUFSA)], \reg
218          .endm
219
220          .macro    GET_CTXBUSY reg
221          sethi     %hi(CPUINFO_VA + CI_CTXBUSY), \reg
222          LDPTR     [\reg + %lo(CPUINFO_VA + CI_CTXBUSY)], \reg
223          .endm
224
225          .macro    GET_TSB_DMMU reg
226          sethi     %hi(CPUINFO_VA + CI_TSB_DMMU), \reg
227          LDPTR     [\reg + %lo(CPUINFO_VA + CI_TSB_DMMU)], \reg
228          .endm
229
230          .macro sun4v_tl1_uspill_normal
231          ba,a,pt   %xcc, spill_normal_to_user_stack
232           nop
233          .align 128
234          .endm
235
236          .macro sun4v_tl1_uspill_other
237          ba,a,pt   %xcc, pcbspill_other
238           nop
239          .align 128
240          .endm
241
242#endif
243
244#if 1
245/*
246 * Try to issue an elf note to ask the Solaris
247 * bootloader to align the kernel properly.
248 */
249          .section  .note
250          .word     0x0d
251          .word     4                   ! Dunno why
252          .word     1
2530:        .asciz    "SUNW Solaris"
2541:
255          .align    4
256          .word     0x0400000
257#endif
258
259          .register %g2,#scratch
260          .register %g3,#scratch
261
262
263          .data
264          .globl    _C_LABEL(data_start)
265_C_LABEL(data_start):                                                 ! Start of data segment
266
267#ifdef KGDB
268/*
269 * Another item that must be aligned, easiest to put it here.
270 */
271KGDB_STACK_SIZE = 2048
272          .globl    _C_LABEL(kgdb_stack)
273_C_LABEL(kgdb_stack):
274          .space    KGDB_STACK_SIZE               ! hope this is enough
275#endif
276
277#ifdef NOTDEF_DEBUG
278/*
279 * This stack is used when we detect kernel stack corruption.
280 */
281          .space    USPACE
282          .align    16
283panicstack:
284#endif
285
286/*
287 * romp is the prom entry pointer
288 * romtba is the prom trap table base address
289 */
290          .globl    romp
291romp:     POINTER   0
292          .globl    romtba
293romtba:   POINTER   0
294
295          .globl    cputyp
296cputyp:   .word     CPU_SUN4U ! Default to sun4u
297
298          _ALIGN
299          .text
300
301/*
302 * The v9 trap frame is stored in the special trap registers.  The
303 * register window is only modified on window overflow, underflow,
304 * and clean window traps, where it points to the register window
305 * needing service.  Traps have space for 8 instructions, except for
306 * the window overflow, underflow, and clean window traps which are
307 * 32 instructions long, large enough to in-line.
308 *
309 * The spitfire CPU (Ultra I) has 4 different sets of global registers.
310 * (blah blah...)
311 *
312 * I used to generate these numbers by address arithmetic, but gas's
313 * expression evaluator has about as much sense as your average slug
314 * (oddly enough, the code looks about as slimy too).  Thus, all the
315 * trap numbers are given as arguments to the trap macros.  This means
316 * there is one line per trap.  Sigh.
317 *
318 * Hardware interrupt vectors can be `linked'---the linkage is to regular
319 * C code---or rewired to fast in-window handlers.  The latter are good
320 * for unbuffered hardware like the Zilog serial chip and the AMD audio
321 * chip, where many interrupts can be handled trivially with pseudo-DMA
322 * or similar.  Only one `fast' interrupt can be used per level, however,
323 * and direct and `fast' interrupts are incompatible.  Routines in intr.c
324 * handle setting these, with optional paranoia.
325 */
326
327/*
328 *        TA8 -- trap align for 8 instruction traps
329 *        TA32 -- trap align for 32 instruction traps
330 */
331#define TA8         .align 32
332#define TA32        .align 128
333
334/*
335 * v9 trap macros:
336 *
337 *        We have a problem with v9 traps; we have no registers to put the
338 *        trap type into.  But we do have a %tt register which already has
339 *        that information.  Trap types in these macros are all dummys.
340 */
341          /* regular vectored traps */
342
343#define   VTRAP(type, label) \
344          ba,a,pt   %icc,label; nop; NOTREACHED; TA8
345
346          /* hardware interrupts (can be linked or made `fast') */
347#define   HARDINT4U(lev) \
348          VTRAP(lev, _C_LABEL(sparc_interrupt))
349#ifdef SUN4V
350#define HARDINT4V(lev) HARDINT4U(lev)
351#endif
352
353          /* software interrupts (may not be made direct, sorry---but you
354             should not be using them trivially anyway) */
355#define   SOFTINT4U(lev, bit) \
356          HARDINT4U(lev)
357
358          /* traps that just call trap() */
359#define   TRAP(type)          VTRAP(type, slowtrap)
360
361          /* architecturally undefined traps (cause panic) */
362#ifndef DEBUG
363#define   UTRAP(type)         sir; VTRAP(type, slowtrap)
364#else
365#define   UTRAP(type)         VTRAP(type, slowtrap)
366#endif
367
368          /* software undefined traps (may be replaced) */
369#define   STRAP(type)         VTRAP(type, slowtrap)
370
371/* breakpoint acts differently under kgdb */
372#ifdef KGDB
373#define   BPT                 VTRAP(T_BREAKPOINT, bpt)
374#define   BPT_KGDB_EXEC       VTRAP(T_KGDB_EXEC, bpt)
375#else
376#define   BPT                 TRAP(T_BREAKPOINT)
377#define   BPT_KGDB_EXEC       TRAP(T_KGDB_EXEC)
378#endif
379
380#define   SYSCALL             VTRAP(0x100, syscall_setup)
381#ifdef notyet
382#define   ZS_INTERRUPT        ba,a,pt %icc, zshard; nop; TA8
383#else
384#define   ZS_INTERRUPT4U      HARDINT4U(12)
385#endif
386
387
388/*
389 * Macro to clear %tt so we don't get confused with old traps.
390 */
391#ifdef DEBUG
392#define CLRTT       wrpr      %g0,0x1ff,%tt
393#else
394#define CLRTT
395#endif
396
397
398/*
399 * Some macros to load and store a register window
400 */
401
402          .macro    SPILL storer,base,size,asi
403
404          .irpc n,01234567
405                    \storer %l\n, [\base + (\n * \size)] \asi
406          .endr
407          .irpc n,01234567
408                    \storer %i\n, [\base + ((8+\n) * \size)] \asi
409          .endr
410
411          .endm
412
413
414          .macro FILL loader, base, size, asi
415
416          .irpc n,01234567
417                    \loader [\base + (\n * \size)] \asi, %l\n
418          .endr
419
420          .irpc n,01234567
421                    \loader [\base + ((8+\n) * \size)] \asi, %i\n
422          .endr
423
424          .endm
425
426/*
427 * Here are some oft repeated traps as macros.
428 */
429
430          /* spill a 64-bit register window */
431#define SPILL64(label,as) \
432label:    \
433          wr        %g0, as, %asi; \
434          stxa      %l0, [%sp+BIAS+0x00]%asi; \
435          stxa      %l1, [%sp+BIAS+0x08]%asi; \
436          stxa      %l2, [%sp+BIAS+0x10]%asi; \
437          stxa      %l3, [%sp+BIAS+0x18]%asi; \
438          stxa      %l4, [%sp+BIAS+0x20]%asi; \
439          stxa      %l5, [%sp+BIAS+0x28]%asi; \
440          stxa      %l6, [%sp+BIAS+0x30]%asi; \
441          \
442          stxa      %l7, [%sp+BIAS+0x38]%asi; \
443          stxa      %i0, [%sp+BIAS+0x40]%asi; \
444          stxa      %i1, [%sp+BIAS+0x48]%asi; \
445          stxa      %i2, [%sp+BIAS+0x50]%asi; \
446          stxa      %i3, [%sp+BIAS+0x58]%asi; \
447          stxa      %i4, [%sp+BIAS+0x60]%asi; \
448          stxa      %i5, [%sp+BIAS+0x68]%asi; \
449          stxa      %i6, [%sp+BIAS+0x70]%asi; \
450          \
451          stxa      %i7, [%sp+BIAS+0x78]%asi; \
452          saved; \
453          CLRTT; \
454          retry; \
455          NOTREACHED; \
456          TA32
457
458          /* spill a 32-bit register window */
459#define SPILL32(label,as) \
460label:    \
461          wr        %g0, as, %asi; \
462          srl       %sp, 0, %sp; /* fixup 32-bit pointers */ \
463          stwa      %l0, [%sp+0x00]%asi; \
464          stwa      %l1, [%sp+0x04]%asi; \
465          stwa      %l2, [%sp+0x08]%asi; \
466          stwa      %l3, [%sp+0x0c]%asi; \
467          stwa      %l4, [%sp+0x10]%asi; \
468          stwa      %l5, [%sp+0x14]%asi; \
469          \
470          stwa      %l6, [%sp+0x18]%asi; \
471          stwa      %l7, [%sp+0x1c]%asi; \
472          stwa      %i0, [%sp+0x20]%asi; \
473          stwa      %i1, [%sp+0x24]%asi; \
474          stwa      %i2, [%sp+0x28]%asi; \
475          stwa      %i3, [%sp+0x2c]%asi; \
476          stwa      %i4, [%sp+0x30]%asi; \
477          stwa      %i5, [%sp+0x34]%asi; \
478          \
479          stwa      %i6, [%sp+0x38]%asi; \
480          stwa      %i7, [%sp+0x3c]%asi; \
481          saved; \
482          CLRTT; \
483          retry; \
484          NOTREACHED; \
485          TA32
486
487          /* Spill either 32-bit or 64-bit register window. */
488#define SPILLBOTH(label64,label32,as) \
489          andcc     %sp, 1, %g0; \
490          bnz,pt    %xcc, label64+4;    /* Is it a v9 or v8 stack? */ \
491           wr       %g0, as, %asi; \
492          ba,pt     %xcc, label32+8; \
493           srl      %sp, 0, %sp; /* fixup 32-bit pointers */ \
494          NOTREACHED; \
495          TA32
496
497          /* fill a 64-bit register window */
498#define FILL64(label,as) \
499label: \
500          wr        %g0, as, %asi; \
501          ldxa      [%sp+BIAS+0x00]%asi, %l0; \
502          ldxa      [%sp+BIAS+0x08]%asi, %l1; \
503          ldxa      [%sp+BIAS+0x10]%asi, %l2; \
504          ldxa      [%sp+BIAS+0x18]%asi, %l3; \
505          ldxa      [%sp+BIAS+0x20]%asi, %l4; \
506          ldxa      [%sp+BIAS+0x28]%asi, %l5; \
507          ldxa      [%sp+BIAS+0x30]%asi, %l6; \
508          \
509          ldxa      [%sp+BIAS+0x38]%asi, %l7; \
510          ldxa      [%sp+BIAS+0x40]%asi, %i0; \
511          ldxa      [%sp+BIAS+0x48]%asi, %i1; \
512          ldxa      [%sp+BIAS+0x50]%asi, %i2; \
513          ldxa      [%sp+BIAS+0x58]%asi, %i3; \
514          ldxa      [%sp+BIAS+0x60]%asi, %i4; \
515          ldxa      [%sp+BIAS+0x68]%asi, %i5; \
516          ldxa      [%sp+BIAS+0x70]%asi, %i6; \
517          \
518          ldxa      [%sp+BIAS+0x78]%asi, %i7; \
519          restored; \
520          CLRTT; \
521          retry; \
522          NOTREACHED; \
523          TA32
524
525          /* fill a 32-bit register window */
526#define FILL32(label,as) \
527label:    \
528          wr        %g0, as, %asi; \
529          srl       %sp, 0, %sp; /* fixup 32-bit pointers */ \
530          lda       [%sp+0x00]%asi, %l0; \
531          lda       [%sp+0x04]%asi, %l1; \
532          lda       [%sp+0x08]%asi, %l2; \
533          lda       [%sp+0x0c]%asi, %l3; \
534          lda       [%sp+0x10]%asi, %l4; \
535          lda       [%sp+0x14]%asi, %l5; \
536          \
537          lda       [%sp+0x18]%asi, %l6; \
538          lda       [%sp+0x1c]%asi, %l7; \
539          lda       [%sp+0x20]%asi, %i0; \
540          lda       [%sp+0x24]%asi, %i1; \
541          lda       [%sp+0x28]%asi, %i2; \
542          lda       [%sp+0x2c]%asi, %i3; \
543          lda       [%sp+0x30]%asi, %i4; \
544          lda       [%sp+0x34]%asi, %i5; \
545          \
546          lda       [%sp+0x38]%asi, %i6; \
547          lda       [%sp+0x3c]%asi, %i7; \
548          restored; \
549          CLRTT; \
550          retry; \
551          NOTREACHED; \
552          TA32
553
554          /* fill either 32-bit or 64-bit register window. */
555#define FILLBOTH(label64,label32,as) \
556          andcc     %sp, 1, %i0; \
557          bnz       (label64)+4; /* See if it's a v9 stack or v8 */ \
558           wr       %g0, as, %asi; \
559          ba        (label32)+8; \
560           srl      %sp, 0, %sp; /* fixup 32-bit pointers */ \
561          NOTREACHED; \
562          TA32
563
564          /* handle clean window trap when trap level = 0 */
565          .macro CLEANWIN0
566          rdpr %cleanwin, %o7
567          inc %o7                                 !         This handler is in-lined and cannot fault
568#ifdef DEBUG
569          set       0xbadcafe, %l0                ! DEBUG -- compiler should not rely on zero-ed registers.
570#else
571          clr       %l0
572#endif
573          wrpr %g0, %o7, %cleanwin      !       Nucleus (trap&IRQ) code does not need clean windows
574
575          mov %l0,%l1; mov %l0,%l2      !         Clear out %l0-%l8 and %o0-%o8 and inc %cleanwin and done
576          mov %l0,%l3; mov %l0,%l4
577#if 0
578#ifdef DIAGNOSTIC
579          !!
580          !! Check the sp redzone
581          !!
582          !! Since we can't spill the current window, we'll just keep
583          !! track of the frame pointer.  Problems occur when the routine
584          !! allocates and uses stack storage.
585          !!
586!         rdpr      %wstate, %l5        ! User stack?
587!         cmp       %l5, WSTATE_KERN
588!         bne,pt    %icc, 7f
589           sethi    %hi(CPCB), %l5
590          LDPTR     [%l5 + %lo(CPCB)], %l5        ! If pcb < fp < pcb+sizeof(pcb)
591          inc       PCB_SIZE, %l5                 ! then we have a stack overflow
592          btst      %fp, 1                        ! 64-bit stack?
593          sub       %fp, %l5, %l7
594          bnz,a,pt  %icc, 1f
595           inc      BIAS, %l7           ! Remove BIAS
5961:
597          cmp       %l7, PCB_SIZE
598          blu       %xcc, cleanwin_overflow
599#endif
600#endif
601          mov %l0, %l5
602          mov %l0, %l6; mov %l0, %l7; mov %l0, %o0; mov %l0, %o1
603
604          mov %l0, %o2; mov %l0, %o3; mov %l0, %o4; mov %l0, %o5;
605          mov %l0, %o6; mov %l0, %o7
606          CLRTT
607          retry; nop; NOTREACHED; TA32
608          .endm
609
610          /* handle clean window trap when trap level = 1 */
611          .macro CLEANWIN1
612          clr       %l0
613#ifdef DEBUG
614          set       0xbadbeef, %l0                ! DEBUG
615#endif
616          mov %l0, %l1; mov %l0, %l2
617          rdpr %cleanwin, %o7           !         This handler is in-lined and cannot fault
618          inc %o7; mov %l0, %l3                   !       Nucleus (trap&IRQ) code does not need clean windows
619          wrpr %g0, %o7, %cleanwin      !         Clear out %l0-%l8 and %o0-%o8 and inc %cleanwin and done
620#ifdef NOT_DEBUG
621          !!
622          !! Check the sp redzone
623          !!
624          rdpr      %wstate, t1
625          cmp       t1, WSTATE_KERN
626          bne,pt    icc, 7f
627           sethi    %hi(_C_LABEL(redzone)), t1
628          ldx       [t1 + %lo(_C_LABEL(redzone))], t2
629          cmp       %sp, t2                       ! if sp >= t2, not in red zone
630          blu       panic_red           ! and can continue normally
6317:
632#endif
633          mov %l0, %l4; mov %l0, %l5; mov %l0, %l6; mov %l0, %l7
634          mov %l0, %o0; mov %l0, %o1; mov %l0, %o2; mov %l0, %o3
635
636          mov %l0, %o4; mov %l0, %o5; mov %l0, %o6; mov %l0, %o7
637          CLRTT
638          retry; nop; TA32
639          .endm
640
641          .globl    start, _C_LABEL(kernel_text)
642          _C_LABEL(kernel_text) = kernel_start              ! for kvm_mkdb(8)
643kernel_start:
644          /* Traps from TL=0 -- traps from user mode */
645#ifdef __STDC__
646#define TABLE(name) user_ ## name
647#else
648#define   TABLE(name)         user_/**/name
649#endif
650          .globl    _C_LABEL(trapbase)
651_C_LABEL(trapbase):
652          b dostart; nop; TA8 ! 000 = reserved -- Use it to boot
653          /* We should not get the next 5 traps */
654          UTRAP(0x001)                  ! 001 = POR Reset -- ROM should get this
655          UTRAP(0x002)                  ! 002 = WDR -- ROM should get this
656          UTRAP(0x003)                  ! 003 = XIR -- ROM should get this
657          UTRAP(0x004)                  ! 004 = SIR -- ROM should get this
658          UTRAP(0x005)                  ! 005 = RED state exception
659          UTRAP(0x006); UTRAP(0x007)
660          VTRAP(T_INST_EXCEPT, textfault)         ! 008 = instr. access except
661          VTRAP(T_TEXTFAULT, textfault) ! 009 = instr access MMU miss
662          VTRAP(T_INST_ERROR, textfault)          ! 00a = instr. access err
663          UTRAP(0x00b); UTRAP(0x00c); UTRAP(0x00d); UTRAP(0x00e); UTRAP(0x00f)
664          TRAP(T_ILLINST)                         ! 010 = illegal instruction
665          TRAP(T_PRIVINST)              ! 011 = privileged instruction
666          UTRAP(0x012)                            ! 012 = unimplemented LDD
667          UTRAP(0x013)                            ! 013 = unimplemented STD
668          UTRAP(0x014); UTRAP(0x015); UTRAP(0x016); UTRAP(0x017); UTRAP(0x018)
669          UTRAP(0x019); UTRAP(0x01a); UTRAP(0x01b); UTRAP(0x01c); UTRAP(0x01d)
670          UTRAP(0x01e); UTRAP(0x01f)
671          TRAP(T_FPDISABLED)            ! 020 = fp instr, but EF bit off in psr
672          TRAP(T_FP_IEEE_754)           ! 021 = ieee 754 exception
673          TRAP(T_FP_OTHER)              ! 022 = other fp exception
674          TRAP(T_TAGOF)                           ! 023 = tag overflow
675          CLEANWIN0                     ! 024-027 = clean window trap
676          TRAP(T_DIV0)                            ! 028 = divide by zero
677          UTRAP(0x029)                            ! 029 = internal processor error
678          UTRAP(0x02a); UTRAP(0x02b); UTRAP(0x02c); UTRAP(0x02d); UTRAP(0x02e); UTRAP(0x02f)
679          VTRAP(T_DATAFAULT, winfault)  ! 030 = data fetch fault
680          UTRAP(0x031)                            ! 031 = data MMU miss -- no MMU
681          VTRAP(T_DATA_ERROR, winfault) ! 032 = data access error
682          VTRAP(T_DATA_PROT, winfault)  ! 033 = data protection fault
683          TRAP(T_ALIGN)                           ! 034 = address alignment error -- we could fix it inline...
684          TRAP(T_LDDF_ALIGN)            ! 035 = LDDF address alignment error -- we could fix it inline...
685          TRAP(T_STDF_ALIGN)            ! 036 = STDF address alignment error -- we could fix it inline...
686          TRAP(T_PRIVACT)                         ! 037 = privileged action
687          UTRAP(0x038); UTRAP(0x039); UTRAP(0x03a); UTRAP(0x03b); UTRAP(0x03c);
688          UTRAP(0x03d); UTRAP(0x03e); UTRAP(0x03f);
689          VTRAP(T_ASYNC_ERROR, winfault)          ! 040 = data fetch fault
690          SOFTINT4U(1, IE_L1)           ! 041 = level 1 interrupt
691          HARDINT4U(2)                            ! 042 = level 2 interrupt
692          HARDINT4U(3)                            ! 043 = level 3 interrupt
693          SOFTINT4U(4, IE_L4)           ! 044 = level 4 interrupt
694          HARDINT4U(5)                            ! 045 = level 5 interrupt
695          SOFTINT4U(6, IE_L6)           ! 046 = level 6 interrupt
696          HARDINT4U(7)                            ! 047 = level 7 interrupt
697          HARDINT4U(8)                            ! 048 = level 8 interrupt
698          HARDINT4U(9)                            ! 049 = level 9 interrupt
699          HARDINT4U(10)                           ! 04a = level 10 interrupt
700          HARDINT4U(11)                           ! 04b = level 11 interrupt
701          ZS_INTERRUPT4U                          ! 04c = level 12 (zs) interrupt
702          HARDINT4U(13)                           ! 04d = level 13 interrupt
703          HARDINT4U(14)                           ! 04e = level 14 interrupt
704          HARDINT4U(15)                           ! 04f = nonmaskable interrupt
705          UTRAP(0x050); UTRAP(0x051); UTRAP(0x052); UTRAP(0x053); UTRAP(0x054); UTRAP(0x055)
706          UTRAP(0x056); UTRAP(0x057); UTRAP(0x058); UTRAP(0x059); UTRAP(0x05a); UTRAP(0x05b)
707          UTRAP(0x05c); UTRAP(0x05d); UTRAP(0x05e); UTRAP(0x05f)
708          VTRAP(0x060, interrupt_vector); ! 060 = interrupt vector
709          TRAP(T_PA_WATCHPT)            ! 061 = physical address data watchpoint
710          TRAP(T_VA_WATCHPT)            ! 062 = virtual address data watchpoint
711          TRAP(T_ECCERR)                          ! 063 = corrected ECC error
712ufast_IMMU_miss:                        ! 064 = fast instr access MMU miss
713          ldxa      [%g0] ASI_IMMU_8KPTR, %g2 ! Load IMMU 8K TSB pointer
714#ifdef NO_TSB
715          ba,a      %icc, instr_miss
716#endif
717          ldxa      [%g0] ASI_IMMU, %g1 ! Load IMMU tag target register
718          ldda      [%g2] ASI_NUCLEUS_QUAD_LDD, %g4         ! Load TSB tag:data into %g4:%g5
719          brgez,pn %g5, instr_miss      ! Entry invalid?  Punt
720           cmp      %g1, %g4            ! Compare TLB tags
721          bne,pn %xcc, instr_miss                 ! Got right tag?
722           nop
723          CLRTT
724          stxa      %g5, [%g0] ASI_IMMU_DATA_IN ! Enter new mapping
725          retry                                   ! Try new mapping
7261:
727          sir
728          TA32
729ufast_DMMU_miss:                        ! 068 = fast data access MMU miss
730          ldxa      [%g0] ASI_DMMU_8KPTR, %g2! Load DMMU 8K TSB pointer
731#ifdef NO_TSB
732          ba,a      %icc, data_miss
733#endif
734          ldxa      [%g0] ASI_DMMU, %g1 ! Load DMMU tag target register
735          ldda      [%g2] ASI_NUCLEUS_QUAD_LDD, %g4         ! Load TSB tag and data into %g4 and %g5
736          brgez,pn %g5, data_miss                 ! Entry invalid?  Punt
737           cmp      %g1, %g4            ! Compare TLB tags
738          bnz,pn    %xcc, data_miss               ! Got right tag?
739           nop
740          CLRTT
741#ifdef TRAPSTATS
742          sethi     %hi(_C_LABEL(udhit)), %g1
743          lduw      [%g1+%lo(_C_LABEL(udhit))], %g2
744          inc       %g2
745          stw       %g2, [%g1+%lo(_C_LABEL(udhit))]
746#endif
747          stxa      %g5, [%g0] ASI_DMMU_DATA_IN ! Enter new mapping
748          retry                                   ! Try new mapping
7491:
750          sir
751          TA32
752ufast_DMMU_protection:                            ! 06c = fast data access MMU protection
753#ifdef TRAPSTATS
754          sethi     %hi(_C_LABEL(udprot)), %g1
755          lduw      [%g1+%lo(_C_LABEL(udprot))], %g2
756          inc       %g2
757          stw       %g2, [%g1+%lo(_C_LABEL(udprot))]
758#endif
759#ifdef HWREF
760          ba,a,pt   %xcc, dmmu_write_fault
761#else
762          ba,a,pt   %xcc, winfault
763#endif
764          nop
765          TA32
766          TRAP(0x070)                             ! 0x070 fast_ECC_error
767                                                  ! Implementation dependent traps
768          UTRAP(0x071); UTRAP(0x072); UTRAP(0x073); UTRAP(0x074); UTRAP(0x075); UTRAP(0x076)
769          UTRAP(0x077); UTRAP(0x078); UTRAP(0x079); UTRAP(0x07a); UTRAP(0x07b); UTRAP(0x07c)
770          UTRAP(0x07d); UTRAP(0x07e); UTRAP(0x07f)
771TABLE(uspill):
772          SPILL64(uspill8,ASI_AIUS)     ! 0x080 spill_0_normal -- used to save user windows in user mode
773          SPILL32(uspill4,ASI_AIUS)     ! 0x084 spill_1_normal
774          SPILLBOTH(uspill8,uspill4,ASI_AIUS)      ! 0x088 spill_2_normal
775          UTRAP(0x08c); TA32            ! 0x08c spill_3_normal
776TABLE(kspill):
777          SPILL64(kspill8,ASI_N)                  ! 0x090 spill_4_normal -- used to save supervisor windows
778          SPILL32(kspill4,ASI_N)                  ! 0x094 spill_5_normal
779          SPILLBOTH(kspill8,kspill4,ASI_N) ! 0x098 spill_6_normal
780          UTRAP(0x09c); TA32            ! 0x09c spill_7_normal
781TABLE(uspillk):
782          SPILL64(uspillk8,ASI_AIUS)    ! 0x0a0 spill_0_other -- used to save user windows in supervisor mode
783          SPILL32(uspillk4,ASI_AIUS)    ! 0x0a4 spill_1_other
784          SPILLBOTH(uspillk8,uspillk4,ASI_AIUS) ! 0x0a8 spill_2_other
785          UTRAP(0x0ac); TA32            ! 0x0ac spill_3_other
786          UTRAP(0x0b0); TA32            ! 0x0b0 spill_4_other
787          UTRAP(0x0b4); TA32            ! 0x0b4 spill_5_other
788          UTRAP(0x0b8); TA32            ! 0x0b8 spill_6_other
789          UTRAP(0x0bc); TA32            ! 0x0bc spill_7_other
790TABLE(ufill):
791          FILL64(ufill8,ASI_AIUS)                 ! 0x0c0 fill_0_normal -- used to fill windows when running user mode
792          FILL32(ufill4,ASI_AIUS)                 ! 0x0c4 fill_1_normal
793          FILLBOTH(ufill8,ufill4,ASI_AIUS) ! 0x0c8 fill_2_normal
794          UTRAP(0x0cc); TA32            ! 0x0cc fill_3_normal
795TABLE(kfill):
796          FILL64(kfill8,ASI_N)                    ! 0x0d0 fill_4_normal -- used to fill windows when running supervisor mode
797          FILL32(kfill4,ASI_N)                    ! 0x0d4 fill_5_normal
798          FILLBOTH(kfill8,kfill4,ASI_N) ! 0x0d8 fill_6_normal
799          UTRAP(0x0dc); TA32            ! 0x0dc fill_7_normal
800TABLE(ufillk):
801          FILL64(ufillk8,ASI_AIUS)      ! 0x0e0 fill_0_other
802          FILL32(ufillk4,ASI_AIUS)      ! 0x0e4 fill_1_other
803          FILLBOTH(ufillk8,ufillk4,ASI_AIUS) ! 0x0e8 fill_2_other
804          UTRAP(0x0ec); TA32            ! 0x0ec fill_3_other
805          UTRAP(0x0f0); TA32            ! 0x0f0 fill_4_other
806          UTRAP(0x0f4); TA32            ! 0x0f4 fill_5_other
807          UTRAP(0x0f8); TA32            ! 0x0f8 fill_6_other
808          UTRAP(0x0fc); TA32            ! 0x0fc fill_7_other
809TABLE(syscall):
810          SYSCALL                                 ! 0x100 = sun syscall
811          BPT                                     ! 0x101 = pseudo breakpoint instruction
812          STRAP(0x102); STRAP(0x103); STRAP(0x104); STRAP(0x105); STRAP(0x106); STRAP(0x107)
813          SYSCALL                                 ! 0x108 = svr4 syscall
814          SYSCALL                                 ! 0x109 = bsd syscall
815          BPT_KGDB_EXEC                           ! 0x10a = enter kernel gdb on kernel startup
816          STRAP(0x10b); STRAP(0x10c); STRAP(0x10d); STRAP(0x10e); STRAP(0x10f);
817          STRAP(0x110); STRAP(0x111); STRAP(0x112); STRAP(0x113); STRAP(0x114); STRAP(0x115); STRAP(0x116); STRAP(0x117)
818          STRAP(0x118); STRAP(0x119); STRAP(0x11a); STRAP(0x11b); STRAP(0x11c); STRAP(0x11d); STRAP(0x11e); STRAP(0x11f)
819          STRAP(0x120); STRAP(0x121); STRAP(0x122); STRAP(0x123); STRAP(0x124); STRAP(0x125); STRAP(0x126); STRAP(0x127)
820          STRAP(0x128); STRAP(0x129); STRAP(0x12a); STRAP(0x12b); STRAP(0x12c); STRAP(0x12d); STRAP(0x12e); STRAP(0x12f)
821          STRAP(0x130); STRAP(0x131); STRAP(0x132); STRAP(0x133); STRAP(0x134); STRAP(0x135); STRAP(0x136); STRAP(0x137)
822          STRAP(0x138); STRAP(0x139); STRAP(0x13a); STRAP(0x13b); STRAP(0x13c); STRAP(0x13d); STRAP(0x13e); STRAP(0x13f)
823          SYSCALL                                 ! 0x140 SVID syscall (Solaris 2.7)
824          SYSCALL                                 ! 0x141 SPARC International syscall
825          SYSCALL                                 ! 0x142   OS Vendor syscall
826          SYSCALL                                 ! 0x143 HW OEM syscall
827          STRAP(0x144); STRAP(0x145); STRAP(0x146); STRAP(0x147)
828          STRAP(0x148); STRAP(0x149); STRAP(0x14a); STRAP(0x14b); STRAP(0x14c); STRAP(0x14d); STRAP(0x14e); STRAP(0x14f)
829          STRAP(0x150); STRAP(0x151); STRAP(0x152); STRAP(0x153); STRAP(0x154); STRAP(0x155); STRAP(0x156); STRAP(0x157)
830          STRAP(0x158); STRAP(0x159); STRAP(0x15a); STRAP(0x15b); STRAP(0x15c); STRAP(0x15d); STRAP(0x15e); STRAP(0x15f)
831          STRAP(0x160); STRAP(0x161); STRAP(0x162); STRAP(0x163); STRAP(0x164); STRAP(0x165); STRAP(0x166); STRAP(0x167)
832          STRAP(0x168); STRAP(0x169); STRAP(0x16a); STRAP(0x16b); STRAP(0x16c); STRAP(0x16d); STRAP(0x16e); STRAP(0x16f)
833          STRAP(0x170); STRAP(0x171); STRAP(0x172); STRAP(0x173); STRAP(0x174); STRAP(0x175); STRAP(0x176); STRAP(0x177)
834          STRAP(0x178); STRAP(0x179); STRAP(0x17a); STRAP(0x17b); STRAP(0x17c); STRAP(0x17d); STRAP(0x17e); STRAP(0x17f)
835          ! Traps beyond 0x17f are reserved
836          UTRAP(0x180); UTRAP(0x181); UTRAP(0x182); UTRAP(0x183); UTRAP(0x184); UTRAP(0x185); UTRAP(0x186); UTRAP(0x187)
837          UTRAP(0x188); UTRAP(0x189); UTRAP(0x18a); UTRAP(0x18b); UTRAP(0x18c); UTRAP(0x18d); UTRAP(0x18e); UTRAP(0x18f)
838          UTRAP(0x190); UTRAP(0x191); UTRAP(0x192); UTRAP(0x193); UTRAP(0x194); UTRAP(0x195); UTRAP(0x196); UTRAP(0x197)
839          UTRAP(0x198); UTRAP(0x199); UTRAP(0x19a); UTRAP(0x19b); UTRAP(0x19c); UTRAP(0x19d); UTRAP(0x19e); UTRAP(0x19f)
840          UTRAP(0x1a0); UTRAP(0x1a1); UTRAP(0x1a2); UTRAP(0x1a3); UTRAP(0x1a4); UTRAP(0x1a5); UTRAP(0x1a6); UTRAP(0x1a7)
841          UTRAP(0x1a8); UTRAP(0x1a9); UTRAP(0x1aa); UTRAP(0x1ab); UTRAP(0x1ac); UTRAP(0x1ad); UTRAP(0x1ae); UTRAP(0x1af)
842          UTRAP(0x1b0); UTRAP(0x1b1); UTRAP(0x1b2); UTRAP(0x1b3); UTRAP(0x1b4); UTRAP(0x1b5); UTRAP(0x1b6); UTRAP(0x1b7)
843          UTRAP(0x1b8); UTRAP(0x1b9); UTRAP(0x1ba); UTRAP(0x1bb); UTRAP(0x1bc); UTRAP(0x1bd); UTRAP(0x1be); UTRAP(0x1bf)
844          UTRAP(0x1c0); UTRAP(0x1c1); UTRAP(0x1c2); UTRAP(0x1c3); UTRAP(0x1c4); UTRAP(0x1c5); UTRAP(0x1c6); UTRAP(0x1c7)
845          UTRAP(0x1c8); UTRAP(0x1c9); UTRAP(0x1ca); UTRAP(0x1cb); UTRAP(0x1cc); UTRAP(0x1cd); UTRAP(0x1ce); UTRAP(0x1cf)
846          UTRAP(0x1d0); UTRAP(0x1d1); UTRAP(0x1d2); UTRAP(0x1d3); UTRAP(0x1d4); UTRAP(0x1d5); UTRAP(0x1d6); UTRAP(0x1d7)
847          UTRAP(0x1d8); UTRAP(0x1d9); UTRAP(0x1da); UTRAP(0x1db); UTRAP(0x1dc); UTRAP(0x1dd); UTRAP(0x1de); UTRAP(0x1df)
848          UTRAP(0x1e0); UTRAP(0x1e1); UTRAP(0x1e2); UTRAP(0x1e3); UTRAP(0x1e4); UTRAP(0x1e5); UTRAP(0x1e6); UTRAP(0x1e7)
849          UTRAP(0x1e8); UTRAP(0x1e9); UTRAP(0x1ea); UTRAP(0x1eb); UTRAP(0x1ec); UTRAP(0x1ed); UTRAP(0x1ee); UTRAP(0x1ef)
850          UTRAP(0x1f0); UTRAP(0x1f1); UTRAP(0x1f2); UTRAP(0x1f3); UTRAP(0x1f4); UTRAP(0x1f5); UTRAP(0x1f6); UTRAP(0x1f7)
851          UTRAP(0x1f8); UTRAP(0x1f9); UTRAP(0x1fa); UTRAP(0x1fb); UTRAP(0x1fc); UTRAP(0x1fd); UTRAP(0x1fe); UTRAP(0x1ff)
852
853          /* Traps from TL>0 -- traps from supervisor mode */
854#undef TABLE
855#ifdef __STDC__
856#define   TABLE(name)         nucleus_ ## name
857#else
858#define   TABLE(name)         nucleus_/**/name
859#endif
860trapbase_priv:
861          UTRAP(0x000)                            ! 000 = reserved -- Use it to boot
862          /* We should not get the next 5 traps */
863          UTRAP(0x001)                            ! 001 = POR Reset -- ROM should get this
864          UTRAP(0x002)                            ! 002 = WDR Watchdog -- ROM should get this
865          UTRAP(0x003)                            ! 003 = XIR -- ROM should get this
866          UTRAP(0x004)                            ! 004 = SIR -- ROM should get this
867          UTRAP(0x005)                            ! 005 = RED state exception
868          UTRAP(0x006); UTRAP(0x007)
869ktextfault:
870          VTRAP(T_INST_EXCEPT, textfault)         ! 008 = instr. access except
871          VTRAP(T_TEXTFAULT, textfault) ! 009 = instr access MMU miss -- no MMU
872          VTRAP(T_INST_ERROR, textfault)          ! 00a = instr. access err
873          UTRAP(0x00b); UTRAP(0x00c); UTRAP(0x00d); UTRAP(0x00e); UTRAP(0x00f)
874          TRAP(T_ILLINST)                         ! 010 = illegal instruction
875          TRAP(T_PRIVINST)              ! 011 = privileged instruction
876          UTRAP(0x012)                            ! 012 = unimplemented LDD
877          UTRAP(0x013)                            ! 013 = unimplemented STD
878          UTRAP(0x014); UTRAP(0x015); UTRAP(0x016); UTRAP(0x017); UTRAP(0x018)
879          UTRAP(0x019); UTRAP(0x01a); UTRAP(0x01b); UTRAP(0x01c); UTRAP(0x01d)
880          UTRAP(0x01e); UTRAP(0x01f)
881          TRAP(T_FPDISABLED)            ! 020 = fp instr, but EF bit off in psr
882          TRAP(T_FP_IEEE_754)           ! 021 = ieee 754 exception
883          TRAP(T_FP_OTHER)              ! 022 = other fp exception
884          TRAP(T_TAGOF)                           ! 023 = tag overflow
885          CLEANWIN1                     ! 024-027 = clean window trap
886          TRAP(T_DIV0)                            ! 028 = divide by zero
887          UTRAP(0x029)                            ! 029 = internal processor error
888          UTRAP(0x02a); UTRAP(0x02b); UTRAP(0x02c); UTRAP(0x02d); UTRAP(0x02e); UTRAP(0x02f)
889kdatafault:
890          VTRAP(T_DATAFAULT, winfault)  ! 030 = data fetch fault
891          UTRAP(0x031)                            ! 031 = data MMU miss -- no MMU
892          VTRAP(T_DATA_ERROR, winfault) ! 032 = data fetch fault
893          VTRAP(T_DATA_PROT, winfault)  ! 033 = data fetch fault
894          VTRAP(T_ALIGN, checkalign)    ! 034 = address alignment error -- we could fix it inline...
895          TRAP(T_LDDF_ALIGN)            ! 035 = LDDF address alignment error -- we could fix it inline...
896          TRAP(T_STDF_ALIGN)            ! 036 = STDF address alignment error -- we could fix it inline...
897          TRAP(T_PRIVACT)                         ! 037 = privileged action
898          UTRAP(0x038); UTRAP(0x039); UTRAP(0x03a); UTRAP(0x03b); UTRAP(0x03c);
899          UTRAP(0x03d); UTRAP(0x03e); UTRAP(0x03f);
900          VTRAP(T_ASYNC_ERROR, winfault)          ! 040 = data fetch fault
901          SOFTINT4U(1, IE_L1)           ! 041 = level 1 interrupt
902          HARDINT4U(2)                            ! 042 = level 2 interrupt
903          HARDINT4U(3)                            ! 043 = level 3 interrupt
904          SOFTINT4U(4, IE_L4)           ! 044 = level 4 interrupt
905          HARDINT4U(5)                            ! 045 = level 5 interrupt
906          SOFTINT4U(6, IE_L6)           ! 046 = level 6 interrupt
907          HARDINT4U(7)                            ! 047 = level 7 interrupt
908          HARDINT4U(8)                            ! 048 = level 8 interrupt
909          HARDINT4U(9)                            ! 049 = level 9 interrupt
910          HARDINT4U(10)                           ! 04a = level 10 interrupt
911          HARDINT4U(11)                           ! 04b = level 11 interrupt
912          ZS_INTERRUPT4U                          ! 04c = level 12 (zs) interrupt
913          HARDINT4U(13)                           ! 04d = level 13 interrupt
914          HARDINT4U(14)                           ! 04e = level 14 interrupt
915          HARDINT4U(15)                           ! 04f = nonmaskable interrupt
916          UTRAP(0x050); UTRAP(0x051); UTRAP(0x052); UTRAP(0x053); UTRAP(0x054); UTRAP(0x055)
917          UTRAP(0x056); UTRAP(0x057); UTRAP(0x058); UTRAP(0x059); UTRAP(0x05a); UTRAP(0x05b)
918          UTRAP(0x05c); UTRAP(0x05d); UTRAP(0x05e); UTRAP(0x05f)
919          VTRAP(0x060, interrupt_vector); ! 060 = interrupt vector
920          TRAP(T_PA_WATCHPT)            ! 061 = physical address data watchpoint
921          TRAP(T_VA_WATCHPT)            ! 062 = virtual address data watchpoint
922          TRAP(T_ECCERR)                          ! 063 = corrected ECC error
923kfast_IMMU_miss:                        ! 064 = fast instr access MMU miss
924          ldxa      [%g0] ASI_IMMU_8KPTR, %g2 ! Load IMMU 8K TSB pointer
925#ifdef NO_TSB
926          ba,a      %icc, instr_miss
927#endif
928          ldxa      [%g0] ASI_IMMU, %g1 ! Load IMMU tag target register
929          ldda      [%g2] ASI_NUCLEUS_QUAD_LDD, %g4         ! Load TSB tag:data into %g4:%g5
930          brgez,pn %g5, instr_miss      ! Entry invalid?  Punt
931           cmp      %g1, %g4            ! Compare TLB tags
932          bne,pn %xcc, instr_miss                 ! Got right tag?
933           nop
934          CLRTT
935          stxa      %g5, [%g0] ASI_IMMU_DATA_IN ! Enter new mapping
936          retry                                   ! Try new mapping
9371:
938          sir
939          TA32
940kfast_DMMU_miss:                        ! 068 = fast data access MMU miss
941          ldxa      [%g0] ASI_DMMU_8KPTR, %g2! Load DMMU 8K TSB pointer
942#ifdef NO_TSB
943          ba,a      %icc, data_miss
944#endif
945          ldxa      [%g0] ASI_DMMU, %g1 ! Load DMMU tag target register
946          ldda      [%g2] ASI_NUCLEUS_QUAD_LDD, %g4         ! Load TSB tag and data into %g4 and %g5
947          brgez,pn %g5, data_miss                 ! Entry invalid?  Punt
948           cmp      %g1, %g4            ! Compare TLB tags
949          bnz,pn    %xcc, data_miss               ! Got right tag?
950           nop
951          CLRTT
952#ifdef TRAPSTATS
953          sethi     %hi(_C_LABEL(kdhit)), %g1
954          lduw      [%g1+%lo(_C_LABEL(kdhit))], %g2
955          inc       %g2
956          stw       %g2, [%g1+%lo(_C_LABEL(kdhit))]
957#endif
958          stxa      %g5, [%g0] ASI_DMMU_DATA_IN ! Enter new mapping
959          retry                                   ! Try new mapping
9601:
961          sir
962          TA32
963kfast_DMMU_protection:                            ! 06c = fast data access MMU protection
964#ifdef TRAPSTATS
965          sethi     %hi(_C_LABEL(kdprot)), %g1
966          lduw      [%g1+%lo(_C_LABEL(kdprot))], %g2
967          inc       %g2
968          stw       %g2, [%g1+%lo(_C_LABEL(kdprot))]
969#endif
970#ifdef HWREF
971          ba,a,pt   %xcc, dmmu_write_fault
972#else
973          ba,a,pt   %xcc, winfault
974#endif
975          nop
976          TA32
977          TRAP(0x070)                             ! 0x070 fast_ECC_error
978                                                  ! Implementation dependent traps
979          UTRAP(0x071); UTRAP(0x072); UTRAP(0x073); UTRAP(0x074); UTRAP(0x075); UTRAP(0x076)
980          UTRAP(0x077); UTRAP(0x078); UTRAP(0x079); UTRAP(0x07a); UTRAP(0x07b); UTRAP(0x07c)
981          UTRAP(0x07d); UTRAP(0x07e); UTRAP(0x07f)
982TABLE(uspill):
983          SPILL64(1,ASI_AIUS)           ! 0x080 spill_0_normal -- used to save user windows
984          SPILL32(2,ASI_AIUS)           ! 0x084 spill_1_normal
985          SPILLBOTH(1b,2b,ASI_AIUS)     ! 0x088 spill_2_normal
986          UTRAP(0x08c); TA32            ! 0x08c spill_3_normal
987TABLE(kspill):
988          SPILL64(1,ASI_N)              ! 0x090 spill_4_normal -- used to save supervisor windows
989          SPILL32(2,ASI_N)              ! 0x094 spill_5_normal
990          SPILLBOTH(1b,2b,ASI_N)                  ! 0x098 spill_6_normal
991          UTRAP(0x09c); TA32            ! 0x09c spill_7_normal
992TABLE(uspillk):
993          SPILL64(1,ASI_AIUS)           ! 0x0a0 spill_0_other -- used to save user windows in nucleus mode
994          SPILL32(2,ASI_AIUS)           ! 0x0a4 spill_1_other
995          SPILLBOTH(1b,2b,ASI_AIUS)     ! 0x0a8 spill_2_other
996          UTRAP(0x0ac); TA32            ! 0x0ac spill_3_other
997          UTRAP(0x0b0); TA32            ! 0x0b0 spill_4_other
998          UTRAP(0x0b4); TA32            ! 0x0b4 spill_5_other
999          UTRAP(0x0b8); TA32            ! 0x0b8 spill_6_other
1000          UTRAP(0x0bc); TA32            ! 0x0bc spill_7_other
1001TABLE(ufill):
1002          FILL64(nufill8,ASI_AIUS)      ! 0x0c0 fill_0_normal -- used to fill windows when running nucleus mode from user
1003          FILL32(nufill4,ASI_AIUS)      ! 0x0c4 fill_1_normal
1004          FILLBOTH(nufill8,nufill4,ASI_AIUS) ! 0x0c8 fill_2_normal
1005          UTRAP(0x0cc); TA32            ! 0x0cc fill_3_normal
1006TABLE(sfill):
1007          FILL64(sfill8,ASI_N)                    ! 0x0d0 fill_4_normal -- used to fill windows when running nucleus mode from supervisor
1008          FILL32(sfill4,ASI_N)                    ! 0x0d4 fill_5_normal
1009          FILLBOTH(sfill8,sfill4,ASI_N) ! 0x0d8 fill_6_normal
1010          UTRAP(0x0dc); TA32            ! 0x0dc fill_7_normal
1011TABLE(kfill):
1012          FILL64(nkfill8,ASI_AIUS)      ! 0x0e0 fill_0_other -- used to fill user windows when running nucleus mode -- will we ever use this?
1013          FILL32(nkfill4,ASI_AIUS)      ! 0x0e4 fill_1_other
1014          FILLBOTH(nkfill8,nkfill4,ASI_AIUS)! 0x0e8 fill_2_other
1015          UTRAP(0x0ec); TA32            ! 0x0ec fill_3_other
1016          UTRAP(0x0f0); TA32            ! 0x0f0 fill_4_other
1017          UTRAP(0x0f4); TA32            ! 0x0f4 fill_5_other
1018          UTRAP(0x0f8); TA32            ! 0x0f8 fill_6_other
1019          UTRAP(0x0fc); TA32            ! 0x0fc fill_7_other
1020TABLE(syscall):
1021          SYSCALL                                 ! 0x100 = sun syscall
1022          BPT                                     ! 0x101 = pseudo breakpoint instruction
1023          STRAP(0x102); STRAP(0x103); STRAP(0x104); STRAP(0x105); STRAP(0x106); STRAP(0x107)
1024          SYSCALL                                 ! 0x108 = svr4 syscall
1025          SYSCALL                                 ! 0x109 = bsd syscall
1026          BPT_KGDB_EXEC                           ! 0x10a = enter kernel gdb on kernel startup
1027          STRAP(0x10b); STRAP(0x10c); STRAP(0x10d); STRAP(0x10e); STRAP(0x10f);
1028          STRAP(0x110); STRAP(0x111); STRAP(0x112); STRAP(0x113); STRAP(0x114); STRAP(0x115); STRAP(0x116); STRAP(0x117)
1029          STRAP(0x118); STRAP(0x119); STRAP(0x11a); STRAP(0x11b); STRAP(0x11c); STRAP(0x11d); STRAP(0x11e); STRAP(0x11f)
1030          STRAP(0x120); STRAP(0x121); STRAP(0x122); STRAP(0x123); STRAP(0x124); STRAP(0x125); STRAP(0x126); STRAP(0x127)
1031          STRAP(0x128); STRAP(0x129); STRAP(0x12a); STRAP(0x12b); STRAP(0x12c); STRAP(0x12d); STRAP(0x12e); STRAP(0x12f)
1032          STRAP(0x130); STRAP(0x131); STRAP(0x132); STRAP(0x133); STRAP(0x134); STRAP(0x135); STRAP(0x136); STRAP(0x137)
1033          STRAP(0x138); STRAP(0x139); STRAP(0x13a); STRAP(0x13b); STRAP(0x13c); STRAP(0x13d); STRAP(0x13e); STRAP(0x13f)
1034          STRAP(0x140); STRAP(0x141); STRAP(0x142); STRAP(0x143); STRAP(0x144); STRAP(0x145); STRAP(0x146); STRAP(0x147)
1035          STRAP(0x148); STRAP(0x149); STRAP(0x14a); STRAP(0x14b); STRAP(0x14c); STRAP(0x14d); STRAP(0x14e); STRAP(0x14f)
1036          STRAP(0x150); STRAP(0x151); STRAP(0x152); STRAP(0x153); STRAP(0x154); STRAP(0x155); STRAP(0x156); STRAP(0x157)
1037          STRAP(0x158); STRAP(0x159); STRAP(0x15a); STRAP(0x15b); STRAP(0x15c); STRAP(0x15d); STRAP(0x15e); STRAP(0x15f)
1038          STRAP(0x160); STRAP(0x161); STRAP(0x162); STRAP(0x163); STRAP(0x164); STRAP(0x165); STRAP(0x166); STRAP(0x167)
1039          STRAP(0x168); STRAP(0x169); STRAP(0x16a); STRAP(0x16b); STRAP(0x16c); STRAP(0x16d); STRAP(0x16e); STRAP(0x16f)
1040          STRAP(0x170); STRAP(0x171); STRAP(0x172); STRAP(0x173); STRAP(0x174); STRAP(0x175); STRAP(0x176); STRAP(0x177)
1041          STRAP(0x178); STRAP(0x179); STRAP(0x17a); STRAP(0x17b); STRAP(0x17c); STRAP(0x17d); STRAP(0x17e); STRAP(0x17f)
1042          ! Traps beyond 0x17f are reserved
1043          UTRAP(0x180); UTRAP(0x181); UTRAP(0x182); UTRAP(0x183); UTRAP(0x184); UTRAP(0x185); UTRAP(0x186); UTRAP(0x187)
1044          UTRAP(0x188); UTRAP(0x189); UTRAP(0x18a); UTRAP(0x18b); UTRAP(0x18c); UTRAP(0x18d); UTRAP(0x18e); UTRAP(0x18f)
1045          UTRAP(0x190); UTRAP(0x191); UTRAP(0x192); UTRAP(0x193); UTRAP(0x194); UTRAP(0x195); UTRAP(0x196); UTRAP(0x197)
1046          UTRAP(0x198); UTRAP(0x199); UTRAP(0x19a); UTRAP(0x19b); UTRAP(0x19c); UTRAP(0x19d); UTRAP(0x19e); UTRAP(0x19f)
1047          UTRAP(0x1a0); UTRAP(0x1a1); UTRAP(0x1a2); UTRAP(0x1a3); UTRAP(0x1a4); UTRAP(0x1a5); UTRAP(0x1a6); UTRAP(0x1a7)
1048          UTRAP(0x1a8); UTRAP(0x1a9); UTRAP(0x1aa); UTRAP(0x1ab); UTRAP(0x1ac); UTRAP(0x1ad); UTRAP(0x1ae); UTRAP(0x1af)
1049          UTRAP(0x1b0); UTRAP(0x1b1); UTRAP(0x1b2); UTRAP(0x1b3); UTRAP(0x1b4); UTRAP(0x1b5); UTRAP(0x1b6); UTRAP(0x1b7)
1050          UTRAP(0x1b8); UTRAP(0x1b9); UTRAP(0x1ba); UTRAP(0x1bb); UTRAP(0x1bc); UTRAP(0x1bd); UTRAP(0x1be); UTRAP(0x1bf)
1051          UTRAP(0x1c0); UTRAP(0x1c1); UTRAP(0x1c2); UTRAP(0x1c3); UTRAP(0x1c4); UTRAP(0x1c5); UTRAP(0x1c6); UTRAP(0x1c7)
1052          UTRAP(0x1c8); UTRAP(0x1c9); UTRAP(0x1ca); UTRAP(0x1cb); UTRAP(0x1cc); UTRAP(0x1cd); UTRAP(0x1ce); UTRAP(0x1cf)
1053          UTRAP(0x1d0); UTRAP(0x1d1); UTRAP(0x1d2); UTRAP(0x1d3); UTRAP(0x1d4); UTRAP(0x1d5); UTRAP(0x1d6); UTRAP(0x1d7)
1054          UTRAP(0x1d8); UTRAP(0x1d9); UTRAP(0x1da); UTRAP(0x1db); UTRAP(0x1dc); UTRAP(0x1dd); UTRAP(0x1de); UTRAP(0x1df)
1055          UTRAP(0x1e0); UTRAP(0x1e1); UTRAP(0x1e2); UTRAP(0x1e3); UTRAP(0x1e4); UTRAP(0x1e5); UTRAP(0x1e6); UTRAP(0x1e7)
1056          UTRAP(0x1e8); UTRAP(0x1e9); UTRAP(0x1ea); UTRAP(0x1eb); UTRAP(0x1ec); UTRAP(0x1ed); UTRAP(0x1ee); UTRAP(0x1ef)
1057          UTRAP(0x1f0); UTRAP(0x1f1); UTRAP(0x1f2); UTRAP(0x1f3); UTRAP(0x1f4); UTRAP(0x1f5); UTRAP(0x1f6); UTRAP(0x1f7)
1058          UTRAP(0x1f8); UTRAP(0x1f9); UTRAP(0x1fa); UTRAP(0x1fb); UTRAP(0x1fc); UTRAP(0x1fd); UTRAP(0x1fe); UTRAP(0x1ff)
1059
1060#ifdef SUN4V
1061
1062/* Macros for sun4v traps */
1063
1064          .macro    sun4v_trap_entry count
1065          .rept     \count
1066          ba        slowtrap
1067           nop
1068          .align    32
1069          .endr
1070          .endm
1071
1072          .macro    sun4v_trap_entry_fail count
1073          .rept     \count
1074          sir
1075          .align    32
1076          .endr
1077          .endm
1078
1079          .macro    sun4v_trap_entry_spill_fill_fail count
1080          .rept     \count
1081          sir
1082          .align    128
1083          .endr
1084          .endm
1085
1086/* The actual trap base for sun4v */
1087          .align    0x8000
1088          .globl    _C_LABEL(trapbase_sun4v)
1089_C_LABEL(trapbase_sun4v):
1090          !
1091          ! trap level 0
1092          !
1093          sun4v_trap_entry 8                                          ! 0x000-0x007
1094          VTRAP(T_INST_EXCEPT, sun4v_tl0_itsb_miss)                   ! 0x008 - inst except
1095          VTRAP(T_TEXTFAULT, sun4v_tl0_itsb_miss)                     ! 0x009 - inst MMU miss
1096          sun4v_trap_entry 26                                         ! 0x00a-0x023
1097          CLEANWIN0                                                   ! 0x24-0x27 = clean window
1098          sun4v_trap_entry 9                                          ! 0x028-0x030
1099          VTRAP(T_DATA_MMU_MISS, sun4v_dtsb_miss)                     ! 0x031 = data MMU miss
1100          sun4v_trap_entry 2                                          ! 0x032-0x033
1101          TRAP(T_ALIGN)                                                         ! 0x034 = address alignment error
1102          sun4v_trap_entry 12                                         ! 0x035-0x040
1103          HARDINT4V(1)                                                          ! 0x041 = level 1 interrupt
1104          HARDINT4V(2)                                                          ! 0x042 = level 2 interrupt
1105          HARDINT4V(3)                                                          ! 0x043 = level 3 interrupt
1106          HARDINT4V(4)                                                          ! 0x044 = level 4 interrupt
1107          HARDINT4V(5)                                                          ! 0x045 = level 5 interrupt
1108          HARDINT4V(6)                                                          ! 0x046 = level 6 interrupt
1109          HARDINT4V(7)                                                          ! 0x047 = level 7 interrupt
1110          HARDINT4V(8)                                                          ! 0x048 = level 8 interrupt
1111          HARDINT4V(9)                                                          ! 0x049 = level 9 interrupt
1112          HARDINT4V(10)                                                         ! 0x04a = level 10 interrupt
1113          HARDINT4V(11)                                                         ! 0x04b = level 11 interrupt
1114          HARDINT4V(12)                                                         ! 0x04c = level 12 interrupt
1115          HARDINT4V(13)                                                         ! 0x04d = level 13 interrupt
1116          HARDINT4V(14)                                                         ! 0x04e = level 14 interrupt
1117          HARDINT4V(15)                                                         ! 0x04f = level 15 interrupt
1118          sun4v_trap_entry 28                                         ! 0x050-0x06b
1119          VTRAP(T_FDMMU_PROT, sun4v_tl0_dtsb_prot)                    ! 0x06c
1120          sun4v_trap_entry 15                                         ! 0x06d-0x07b
1121          VTRAP(T_CPU_MONDO, sun4v_cpu_mondo)                         ! 0x07c = cpu mondo
1122          VTRAP(T_DEV_MONDO, sun4v_dev_mondo)                         ! 0x07d = dev mondo
1123          sun4v_trap_entry 2                                          ! 0x07e-0x07f
1124          SPILL64(uspill8_sun4vt0,ASI_AIUS)                           ! 0x080 spill_0_normal -- used to save user windows in user mode
1125          SPILL32(uspill4_sun4vt0,ASI_AIUS)                           ! 0x084 spill_1_normal
1126          SPILLBOTH(uspill8_sun4vt0,uspill4_sun4vt0,ASI_AIUS)         ! 0x088 spill_2_normal
1127          sun4v_trap_entry_spill_fill_fail 1                          ! 0x08c spill_3_normal
1128          SPILL64(kspill8_sun4vt0,ASI_N)                                        ! 0x090 spill_4_normal  -- used to save supervisor windows
1129          SPILL32(kspill4_sun4vt0,ASI_N)                                        ! 0x094 spill_5_normal
1130          SPILLBOTH(kspill8_sun4vt0,kspill4_sun4vt0,ASI_N)  ! 0x098 spill_6_normal
1131          sun4v_trap_entry_spill_fill_fail 1                          ! 0x09c spill_7_normal
1132          SPILL64(uspillk8_sun4vt0,ASI_AIUS)                          ! 0x0a0 spill_0_other -- used to save user windows in supervisor mode
1133          SPILL32(uspillk4_sun4vt0,ASI_AIUS)                          ! 0x0a4 spill_1_other
1134          SPILLBOTH(uspillk8_sun4vt0,uspillk4_sun4vt0,ASI_AIUS)       ! 0x0a8 spill_2_other
1135          sun4v_trap_entry_spill_fill_fail 1                          ! 0x0ac spill_3_other
1136          sun4v_trap_entry_spill_fill_fail 1                          ! 0x0b0 spill_4_other
1137          sun4v_trap_entry_spill_fill_fail 1                          ! 0x0b4 spill_5_other
1138          sun4v_trap_entry_spill_fill_fail 1                          ! 0x0b8 spill_6_other
1139          sun4v_trap_entry_spill_fill_fail 1                          ! 0x0bc spill_7_other
1140          FILL64(ufill8_sun4vt0,ASI_AIUS)                                       ! 0x0c0 fill_0_normal -- used to fill windows when running user mode
1141          FILL32(ufill4_sun4vt0,ASI_AIUS)                                       ! 0x0c4 fill_1_normal
1142          FILLBOTH(ufill8_sun4vt0,ufill4_sun4vt0,ASI_AIUS)  ! 0x0c8 fill_2_normal
1143          sun4v_trap_entry_spill_fill_fail 1                          ! 0x0cc fill_3_normal
1144          FILL64(kfill8_sun4vt0,ASI_N)                                ! 0x0d0 fill_4_normal  -- used to fill windows when running supervisor mode
1145          FILL32(kfill4_sun4vt0,ASI_N)                                ! 0x0d4 fill_5_normal
1146          FILLBOTH(kfill8_sun4vt0,kfill4_sun4vt0,ASI_N)               ! 0x0d8 fill_6_normal
1147          sun4v_trap_entry_spill_fill_fail 1                          ! 0x0dc fill_7_normal
1148          FILL64(ufillk8_sun4vt0,ASI_AIUS)                            ! 0x0e0 fill_0_other
1149          FILL32(ufillk4_sun4vt0,ASI_AIUS)                            ! 0x0e4 fill_1_other
1150          FILLBOTH(ufillk8_sun4vt0,ufillk4_sun4vt0,ASI_AIUS)          ! 0x0e8 fill_2_other
1151          sun4v_trap_entry_spill_fill_fail 1                          ! 0x0ec fill_3_other
1152          sun4v_trap_entry_spill_fill_fail 1                          ! 0x0f0 fill_4_other
1153          sun4v_trap_entry_spill_fill_fail 1                          ! 0x0f4 fill_5_other
1154          sun4v_trap_entry_spill_fill_fail 1                          ! 0x0f8 fill_6_other
1155          sun4v_trap_entry_spill_fill_fail 1                          ! 0x0fc fill_7_other
1156          SYSCALL                                                               ! 0x100 = syscall
1157          BPT                                                                   ! 0x101 = pseudo breakpoint instruction
1158          sun4v_trap_entry 254                                                  ! 0x102-0x1ff
1159          !
1160          ! trap level 1
1161          !
1162          sun4v_trap_entry 36                                         ! 0x000-0x023
1163          CLEANWIN1                                                   ! 0x24-0x27 = clean window
1164          sun4v_trap_entry 8                                          ! 0x028-0x02F
1165          VTRAP(T_DATAFAULT, sun4v_tl1_ptbl_miss)                     ! 0x030 = ???
1166          VTRAP(T_DATA_MMU_MISS, sun4v_tl1_dtsb_miss)                 ! 0x031 = data MMU miss
1167          VTRAP(T_DATA_ERROR, sun4v_tl1_ptbl_miss)                    ! 0x032 = ???
1168          VTRAP(T_DATA_PROT, sun4v_tl1_ptbl_miss)                     ! 0x033 = ???
1169          sun4v_trap_entry 56                                         ! 0x034-0x06b
1170          VTRAP(T_FDMMU_PROT, sun4v_tl1_dtsb_prot)                    ! 0x06c
1171          sun4v_trap_entry 19                                         ! 0x06d-0x07f
1172          sun4v_tl1_uspill_normal                                               ! 0x080 spill_0_normal -- save user windows
1173          sun4v_tl1_uspill_normal                                               ! 0x084 spill_1_normal
1174          sun4v_tl1_uspill_normal                                               ! 0x088 spill_2_normal
1175          sun4v_trap_entry_spill_fill_fail 1                          ! 0x08c spill_3_normal
1176          SPILL64(kspill8_sun4vt1,ASI_N)                                        ! 0x090 spill_4_normal -- save supervisor windows
1177          SPILL32(kspill4_sun4vt1,ASI_N)                                        ! 0x094 spill_5_normal
1178          SPILLBOTH(kspill8_sun4vt1,kspill4_sun4vt1,ASI_N)  ! 0x098 spill_6_normal
1179          sun4v_trap_entry_spill_fill_fail 1                          ! 0x09c spill_7_normal
1180          sun4v_tl1_uspill_other                                                ! 0x0a0 spill_0_other -- save user windows in nucleus mode
1181          sun4v_tl1_uspill_other                                                ! 0x0a4 spill_1_other
1182          sun4v_tl1_uspill_other                                                ! 0x0a8 spill_2_other
1183          sun4v_trap_entry_spill_fill_fail 1                          ! 0x0ac spill_3_other
1184          sun4v_trap_entry_spill_fill_fail 1                          ! 0x0b0 spill_4_other
1185          sun4v_trap_entry_spill_fill_fail 1                          ! 0x0b4 spill_5_other
1186          sun4v_trap_entry_spill_fill_fail 1                          ! 0x0b8 spill_6_other
1187          sun4v_trap_entry_spill_fill_fail 1                          ! 0x0bc spill_7_other
1188          FILL64(ufill8_sun4vt1,ASI_AIUS)                                       ! 0x0c0 fill_0_normal -- fill windows when running nucleus mode from user
1189          FILL32(ufill4_sun4vt1,ASI_AIUS)                                       ! 0x0c4 fill_1_normal
1190          FILLBOTH(ufill8_sun4vt1,ufill4_sun4vt1,ASI_AIUS)  ! 0x0c8 fill_2_normal
1191          sun4v_trap_entry_spill_fill_fail 1                          ! 0x0cc fill_3_normal
1192          FILL64(kfill8_sun4vt1,ASI_N)                                ! 0x0d0 fill_4_normal -- fill windows when running nucleus mode from supervisor
1193          FILL32(kfill4_sun4vt1,ASI_N)                                ! 0x0d4 fill_5_normal
1194          FILLBOTH(kfill8_sun4vt1,kfill4_sun4vt1,ASI_N)               ! 0x0d8 fill_6_normal
1195          sun4v_trap_entry_spill_fill_fail 1                          ! 0x0dc fill_7_normal
1196          FILL64(ufillk8_sun4vt1,ASI_AIUS)                            ! 0x0e0 fill_0_other -- fill user windows when running nucleus mode -- will we ever use this?
1197          FILL32(ufillk4_sun4vt1,ASI_AIUS)                            ! 0x0e4 fill_1_other
1198          FILLBOTH(ufillk8_sun4vt1,ufillk4_sun4vt1,ASI_AIUS)          ! 0x0e8 fill_2_other
1199          sun4v_trap_entry_spill_fill_fail 1                          ! 0x0ec fill_3_other
1200          sun4v_trap_entry_spill_fill_fail 1                          ! 0x0f0 fill_4_other
1201          sun4v_trap_entry_spill_fill_fail 1                          ! 0x0f4 fill_5_other
1202          sun4v_trap_entry_spill_fill_fail 1                          ! 0x0f8 fill_6_other
1203          sun4v_trap_entry_spill_fill_fail 1                          ! 0x0fc fill_7_other
1204          sun4v_trap_entry_fail 256                                   ! 0x100-0x1ff
1205
1206#endif
1207
1208#if 0
1209/*
1210 * If the cleanwin trap handler detects an overflow we come here.
1211 * We need to fix up the window registers, switch to the interrupt
1212 * stack, and then trap to the debugger.
1213 */
1214cleanwin_overflow:
1215          !! We've already incremented %cleanwin
1216          !! So restore %cwp
1217          rdpr      %cwp, %l0
1218          dec       %l0
1219          wrpr      %l0, %g0, %cwp
1220          set       EINTSTACK-STKB-CC64FSZ, %l0
1221          save      %l0, 0, %sp
1222
1223          ta        1                   ! Enter debugger
1224          sethi     %hi(1f), %o0
1225          call      _C_LABEL(panic)
1226           or       %o0, %lo(1f), %o0
1227          restore
1228          retry
1229          .data
12301:
1231          .asciz    "Kernel stack overflow!"
1232          _ALIGN
1233          .text
1234#endif
1235
1236#ifdef NOTDEF_DEBUG
1237/*
1238 * A hardware red zone is impossible.  We simulate one in software by
1239 * keeping a `red zone' pointer; if %sp becomes less than this, we panic.
1240 * This is expensive and is only enabled when debugging.
1241 */
1242#define   REDSIZE   (PCB_SIZE)          /* Mark used portion of pcb structure out of bounds */
1243#define   REDSTACK 2048                 /* size of `panic: stack overflow' region */
1244          .data
1245          _ALIGN
1246redzone:
1247          .xword    _C_LABEL(XXX) + REDSIZE
1248redstack:
1249          .space    REDSTACK
1250eredstack:
1251Lpanic_red:
1252          .asciz    "kernel stack overflow"
1253          _ALIGN
1254          .text
1255
1256          /* set stack pointer redzone to base+minstack; alters base */
1257#define   SET_SP_REDZONE(base, tmp) \
1258          add       base, REDSIZE, base; \
1259          sethi     %hi(_C_LABEL(redzone)), tmp; \
1260          stx       base, [tmp + %lo(_C_LABEL(redzone))]
1261
1262          /* variant with a constant */
1263#define   SET_SP_REDZONE_CONST(const, tmp1, tmp2) \
1264          set       (const) + REDSIZE, tmp1; \
1265          sethi     %hi(_C_LABEL(redzone)), tmp2; \
1266          stx       tmp1, [tmp2 + %lo(_C_LABEL(redzone))]
1267
1268          /* check stack pointer against redzone (uses two temps) */
1269#define   CHECK_SP_REDZONE(t1, t2) \
1270          sethi     KERNBASE, t1;       \
1271          cmp       %sp, t1;  \
1272          blu,pt    %xcc, 7f; \
1273           sethi    %hi(_C_LABEL(redzone)), t1; \
1274          ldx       [t1 + %lo(_C_LABEL(redzone))], t2; \
1275          cmp       %sp, t2;  /* if sp >= t2, not in red zone */ \
1276          blu       panic_red; nop;     /* and can continue normally */ \
12777:
1278
1279panic_red:
1280          /* move to panic stack */
1281          stx       %g0, [t1 + %lo(_C_LABEL(redzone))];
1282          set       eredstack - BIAS, %sp;
1283          /* prevent panic() from lowering ipl */
1284          sethi     %hi(_C_LABEL(panicstr)), t2;
1285          set       Lpanic_red, t2;
1286          st        t2, [t1 + %lo(_C_LABEL(panicstr))];
1287          wrpr      g0, 15, %pil                  /* t1 = splhigh() */
1288          save      %sp, -CCF64SZ, %sp; /* preserve current window */
1289          sethi     %hi(Lpanic_red), %o0;
1290          call      _C_LABEL(panic);
1291           or %o0, %lo(Lpanic_red), %o0;
1292
1293
1294#else
1295
1296#define   SET_SP_REDZONE(base, tmp)
1297#define   SET_SP_REDZONE_CONST(const, t1, t2)
1298#define   CHECK_SP_REDZONE(t1, t2)
1299#endif
1300
1301#define TRACESIZ    0x01000
1302          .globl    _C_LABEL(trap_trace)
1303          .globl    _C_LABEL(trap_trace_ptr)
1304          .globl    _C_LABEL(trap_trace_end)
1305          .globl    _C_LABEL(trap_trace_dis)
1306          .data
1307_C_LABEL(trap_trace_dis):
1308          .word     1, 1                ! Starts disabled.  DDB turns it on.
1309_C_LABEL(trap_trace_ptr):
1310          .word     0, 0, 0, 0
1311_C_LABEL(trap_trace):
1312          .space    TRACESIZ
1313_C_LABEL(trap_trace_end):
1314          .space    0x20                ! safety margin
1315
1316
1317/*
1318 * v9 machines do not have a trap window.
1319 *
1320 * When we take a trap the trap state is pushed on to the stack of trap
1321 * registers, interrupts are disabled, then we switch to an alternate set
1322 * of global registers.
1323 *
1324 * The trap handling code needs to allocate a trap frame on the kernel, or
1325 * for interrupts, the interrupt stack, save the out registers to the trap
1326 * frame, then switch to the normal globals and save them to the trap frame
1327 * too.
1328 *
1329 * XXX it would be good to save the interrupt stack frame to the kernel
1330 * stack so we wouldn't have to copy it later if we needed to handle a AST.
1331 *
1332 * Since kernel stacks are all on one page and the interrupt stack is entirely
1333 * within the locked TLB, we can use physical addressing to save out our
1334 * trap frame so we don't trap during the TRAP_SETUP() operation.  There
1335 * is unfortunately no supportable method for issuing a non-trapping save.
1336 *
1337 * However, if we use physical addresses to save our trapframe, we will need
1338 * to clear out the data cache before continuing much further.
1339 *
1340 * In short, what we need to do is:
1341 *
1342 *        all preliminary processing is done using the alternate globals
1343 *
1344 *        When we allocate our trap windows we must give up our globals because
1345 *        their state may have changed during the save operation
1346 *
1347 *        we need to save our normal globals as soon as we have a stack
1348 *
1349 * Finally, we may now call C code.
1350 *
1351 * This macro will destroy %g5-%g7.  %g0-%g4 remain unchanged.
1352 *
1353 * In order to properly handle nested traps without lossage, alternate
1354 * global %g6 is used as a kernel stack pointer.  It is set to the last
1355 * allocated stack pointer (trapframe) and the old value is stored in
1356 * tf_kstack.  It is restored when returning from a trap.  It is cleared
1357 * on entering user mode.
1358 */
1359
1360 /*
1361  * Other misc. design criteria:
1362  *
1363  * When taking an address fault, fault info is in the sfsr, sfar,
1364  * TLB_TAG_ACCESS registers.  If we take another address fault
1365  * while trying to handle the first fault then that information,
1366  * the only information that tells us what address we trapped on,
1367  * can potentially be lost.  This trap can be caused when allocating
1368  * a register window with which to handle the trap because the save
1369  * may try to store or restore a register window that corresponds
1370  * to part of the stack that is not mapped.  Preventing this trap,
1371  * while possible, is much too complicated to do in a trap handler,
1372  * and then we will need to do just as much work to restore the processor
1373  * window state.
1374  *
1375  * Possible solutions to the problem:
1376  *
1377  * Since we have separate AG, MG, and IG, we could have all traps
1378  * above level-1 preserve AG and use other registers.  This causes
1379  * a problem for the return from trap code which is coded to use
1380  * alternate globals only.
1381  *
1382  * We could store the trapframe and trap address info to the stack
1383  * using physical addresses.  Then we need to read it back using
1384  * physical addressing, or flush the D$.
1385  *
1386  * We could identify certain registers to hold address fault info.
1387  * this means that these registers need to be preserved across all
1388  * fault handling.  But since we only have 7 useable globals, that
1389  * really puts a cramp in our style.
1390  *
1391  * Finally, there is the issue of returning from kernel mode to user
1392  * mode.  If we need to issue a restore of a user window in kernel
1393  * mode, we need the window control registers in a user mode setup.
1394  * If the trap handlers notice the register windows are in user mode,
1395  * they will allocate a trapframe at the bottom of the kernel stack,
1396  * overwriting the frame we were trying to return to.  This means that
1397  * we must complete the restoration of all registers *before* switching
1398  * to a user-mode window configuration.
1399  *
1400  * Essentially we need to be able to write re-entrant code w/no stack.
1401  */
1402          .data
1403trap_setup_msg:
1404          .asciz    "TRAP_SETUP: tt=%x osp=%x nsp=%x tl=%x tpc=%x\n"
1405          _ALIGN
1406intr_setup_msg:
1407          .asciz    "INTR_SETUP: tt=%x osp=%x nsp=%x tl=%x tpc=%x\n"
1408          _ALIGN
1409          .text
1410
1411#ifdef DEBUG
1412          /* Only save a snapshot of locals and ins in DEBUG kernels */
1413#define   SAVE_LOCALS_INS     \
1414          /* Save local registers to trap frame */ \
1415          stx       %l0, [%g6 + CC64FSZ + STKB + TF_L + (0*8)]; \
1416          stx       %l1, [%g6 + CC64FSZ + STKB + TF_L + (1*8)]; \
1417          stx       %l2, [%g6 + CC64FSZ + STKB + TF_L + (2*8)]; \
1418          stx       %l3, [%g6 + CC64FSZ + STKB + TF_L + (3*8)]; \
1419          stx       %l4, [%g6 + CC64FSZ + STKB + TF_L + (4*8)]; \
1420          stx       %l5, [%g6 + CC64FSZ + STKB + TF_L + (5*8)]; \
1421          stx       %l6, [%g6 + CC64FSZ + STKB + TF_L + (6*8)]; \
1422          stx       %l7, [%g6 + CC64FSZ + STKB + TF_L + (7*8)]; \
1423\
1424          /* Save in registers to trap frame */ \
1425          stx       %i0, [%g6 + CC64FSZ + STKB + TF_I + (0*8)]; \
1426          stx       %i1, [%g6 + CC64FSZ + STKB + TF_I + (1*8)]; \
1427          stx       %i2, [%g6 + CC64FSZ + STKB + TF_I + (2*8)]; \
1428          stx       %i3, [%g6 + CC64FSZ + STKB + TF_I + (3*8)]; \
1429          stx       %i4, [%g6 + CC64FSZ + STKB + TF_I + (4*8)]; \
1430          stx       %i5, [%g6 + CC64FSZ + STKB + TF_I + (5*8)]; \
1431          stx       %i6, [%g6 + CC64FSZ + STKB + TF_I + (6*8)]; \
1432          stx       %i7, [%g6 + CC64FSZ + STKB + TF_I + (7*8)]; \
1433\
1434          stx       %g1, [%g6 + CC64FSZ + STKB + TF_FAULT];
1435#else
1436#define   SAVE_LOCALS_INS
1437#endif
1438
1439#ifdef _LP64
1440#define   FIXUP_TRAP_STACK \
1441          btst      1, %g6;                                                     /* Fixup 64-bit stack if necessary */ \
1442          bnz,pt    %icc, 1f; \
1443           add      %g6, %g5, %g6;                                              /* Allocate a stack frame */ \
1444          inc       -BIAS, %g6; \
14451:
1446#else
1447#define   FIXUP_TRAP_STACK \
1448          srl       %g6, 0, %g6;                                                /* truncate at 32-bits */ \
1449          btst      1, %g6;                                                     /* Fixup 64-bit stack if necessary */ \
1450          add       %g6, %g5, %g6;                                              /* Allocate a stack frame */ \
1451          add       %g6, BIAS, %g5; \
1452          movne     %icc, %g5, %g6;
1453#endif
1454
1455#ifdef _LP64
1456#define   TRAP_SETUP(stackspace) \
1457          sethi     %hi(CPCB), %g6; \
1458          sethi     %hi((stackspace)), %g5; \
1459          LDPTR     [%g6 + %lo(CPCB)], %g6; \
1460          sethi     %hi(USPACE), %g7;                                 /* Always multiple of page size */ \
1461          or        %g5, %lo((stackspace)), %g5; \
1462          add       %g6, %g7, %g6; \
1463          rdpr      %wstate, %g7;                                               /* Find if we're from user mode */ \
1464          sra       %g5, 0, %g5;                                                /* Sign extend the damn thing */ \
1465          \
1466          sub       %g7, WSTATE_KERN, %g7;                                      /* Compare & leave in register */ \
1467          movrz     %g7, %sp, %g6;                                              /* Select old (kernel) stack or base of kernel stack */ \
1468          FIXUP_TRAP_STACK \
1469          SAVE_LOCALS_INS     \
1470          save      %g6, 0, %sp;                                                /* If we fault we should come right back here */ \
1471          stx       %i0, [%sp + CC64FSZ + BIAS + TF_O + (0*8)];                 /* Save out registers to trap frame */ \
1472          stx       %i1, [%sp + CC64FSZ + BIAS + TF_O + (1*8)]; \
1473          stx       %i2, [%sp + CC64FSZ + BIAS + TF_O + (2*8)]; \
1474          stx       %i3, [%sp + CC64FSZ + BIAS + TF_O + (3*8)]; \
1475          stx       %i4, [%sp + CC64FSZ + BIAS + TF_O + (4*8)]; \
1476          stx       %i5, [%sp + CC64FSZ + BIAS + TF_O + (5*8)]; \
1477\
1478          stx       %i6, [%sp + CC64FSZ + BIAS + TF_O + (6*8)]; \
1479          brz,pt    %g7, 1f;                                          /* If we were in kernel mode start saving globals */ \
1480           stx      %i7, [%sp + CC64FSZ + BIAS + TF_O + (7*8)]; \
1481          mov       CTX_PRIMARY, %g7; \
1482          /* came from user mode -- switch to kernel mode stack */ \
1483          rdpr      %canrestore, %g5;                                 /* Fixup register window state registers */ \
1484          wrpr      %g0, 0, %canrestore; \
1485          wrpr      %g0, %g5, %otherwin; \
1486          wrpr      %g0, WSTATE_KERN, %wstate;                        /* Enable kernel mode window traps -- now we can trap again */ \
1487\
1488          SET_MMU_CONTEXTID %g0, %g7,%g5;                             /* Switch MMU to kernel primary context */ \
1489          sethi     %hi(KERNBASE), %g5; \
1490          flush     %g5;                                                        /* Some convenient address that won't trap */ \
14911:
1492
1493/*
1494 * Interrupt setup is almost exactly like trap setup, but we need to
1495 * go to the interrupt stack if (a) we came from user mode or (b) we
1496 * came from kernel mode on the kernel stack.
1497 *
1498 * We don't guarantee any registers are preserved during this operation.
1499 * So we can be more efficient.
1500 */
1501#define   INTR_SETUP(stackspace) \
1502          rdpr      %wstate, %g7;                                               /* Find if we're from user mode */ \
1503          \
1504          sethi     %hi(EINTSTACK-BIAS), %g6; \
1505          sethi     %hi(EINTSTACK-INTSTACK), %g4; \
1506          \
1507          or        %g6, %lo(EINTSTACK-BIAS), %g6;                              /* Base of interrupt stack */ \
1508          dec       %g4;                                                        /* Make it into a mask */ \
1509          \
1510          sub       %g6, %sp, %g1;                                              /* Offset from interrupt stack */ \
1511          sethi     %hi((stackspace)), %g5; \
1512          \
1513          or        %g5, %lo((stackspace)), %g5; \
1514\
1515          andn      %g1, %g4, %g4;                                              /* Are we out of the interrupt stack range? */ \
1516          xor       %g7, WSTATE_KERN, %g3;                                      /* Are we on the user stack ? */ \
1517          \
1518          sra       %g5, 0, %g5;                                                /* Sign extend the damn thing */ \
1519          orcc      %g3, %g4, %g0;                                              /* Definitely not off the interrupt stack */ \
1520          \
1521          sethi     %hi(CPUINFO_VA + CI_EINTSTACK), %g4; \
1522          bz,a,pt   %xcc, 1f; \
1523           mov      %sp, %g6; \
1524          \
1525          ldx       [%g4 + %lo(CPUINFO_VA + CI_EINTSTACK)], %g4; \
1526          movrnz    %g4, %g4, %g6;                                              /* Use saved intr stack if exists */ \
1527          \
15281:        add       %g6, %g5, %g5;                                              /* Allocate a stack frame */ \
1529          btst      1, %g6; \
1530          bnz,pt    %icc, 1f; \
1531\
1532           mov      %g5, %g6; \
1533          \
1534          add       %g5, -BIAS, %g6; \
1535          \
15361:        SAVE_LOCALS_INS     \
1537          save      %g6, 0, %sp;                                                /* If we fault we should come right back here */ \
1538          stx       %i0, [%sp + CC64FSZ + BIAS + TF_O + (0*8)];                 /* Save out registers to trap frame */ \
1539          stx       %i1, [%sp + CC64FSZ + BIAS + TF_O + (1*8)]; \
1540          stx       %i2, [%sp + CC64FSZ + BIAS + TF_O + (2*8)]; \
1541          stx       %i3, [%sp + CC64FSZ + BIAS + TF_O + (3*8)]; \
1542          stx       %i4, [%sp + CC64FSZ + BIAS + TF_O + (4*8)]; \
1543\
1544          stx       %i5, [%sp + CC64FSZ + BIAS + TF_O + (5*8)]; \
1545          stx       %i6, [%sp + CC64FSZ + BIAS + TF_O + (6*8)]; \
1546          stx       %i6, [%sp + CC64FSZ + BIAS + TF_G + (0*8)];                 /* Save fp in clockframe->cf_fp */ \
1547          brz,pt    %g3, 1f;                                          /* If we were in kernel mode start saving globals */ \
1548           stx      %i7, [%sp + CC64FSZ + BIAS + TF_O + (7*8)]; \
1549          /* came from user mode -- switch to kernel mode stack */ \
1550           rdpr     %otherwin, %g5;                                             /* Has this already been done? */ \
1551          \
1552          brnz,pn   %g5, 1f;                                          /* Don't set this twice */ \
1553          \
1554           rdpr     %canrestore, %g5;                                 /* Fixup register window state registers */ \
1555\
1556          wrpr      %g0, 0, %canrestore; \
1557          \
1558          wrpr      %g0, %g5, %otherwin; \
1559          \
1560          mov       CTX_PRIMARY, %g7; \
1561          \
1562          wrpr      %g0, WSTATE_KERN, %wstate;                        /* Enable kernel mode window traps -- now we can trap again */ \
1563          \
1564          SET_MMU_CONTEXTID %g0, %g7, %g5;                            /* Switch MMU to kernel primary context */ \
1565          \
1566          sethi     %hi(KERNBASE), %g5; \
1567          flush     %g5;                                                        /* Some convenient address that won't trap */ \
15681:
1569
1570#else /* _LP64 */
1571
1572#define   TRAP_SETUP(stackspace) \
1573          sethi     %hi(CPCB), %g6; \
1574          sethi     %hi((stackspace)), %g5; \
1575          LDPTR     [%g6 + %lo(CPCB)], %g6; \
1576          sethi     %hi(USPACE), %g7; \
1577          or        %g5, %lo((stackspace)), %g5; \
1578          add       %g6, %g7, %g6; \
1579          rdpr      %wstate, %g7;                                               /* Find if we're from user mode */ \
1580          \
1581          sra       %g5, 0, %g5;                                                /* Sign extend the damn thing */ \
1582          subcc     %g7, WSTATE_KERN, %g7;                                      /* Compare & leave in register */ \
1583          movz      %icc, %sp, %g6;                                             /* Select old (kernel) stack or base of kernel stack */ \
1584          FIXUP_TRAP_STACK \
1585          SAVE_LOCALS_INS \
1586          save      %g6, 0, %sp;                                                /* If we fault we should come right back here */ \
1587          stx       %i0, [%sp + CC64FSZ + STKB + TF_O + (0*8)];                 /* Save out registers to trap frame */ \
1588          stx       %i1, [%sp + CC64FSZ + STKB + TF_O + (1*8)]; \
1589          stx       %i2, [%sp + CC64FSZ + STKB + TF_O + (2*8)]; \
1590          stx       %i3, [%sp + CC64FSZ + STKB + TF_O + (3*8)]; \
1591          stx       %i4, [%sp + CC64FSZ + STKB + TF_O + (4*8)]; \
1592          stx       %i5, [%sp + CC64FSZ + STKB + TF_O + (5*8)]; \
1593          \
1594          stx       %i6, [%sp + CC64FSZ + STKB + TF_O + (6*8)]; \
1595          brz,pn    %g7, 1f;                                          /* If we were in kernel mode start saving globals */ \
1596           stx      %i7, [%sp + CC64FSZ + STKB + TF_O + (7*8)]; \
1597          mov       CTX_PRIMARY, %g7; \
1598          /* came from user mode -- switch to kernel mode stack */ \
1599          rdpr      %canrestore, %g5;                                 /* Fixup register window state registers */ \
1600          wrpr      %g0, 0, %canrestore; \
1601          wrpr      %g0, %g5, %otherwin; \
1602          wrpr      %g0, WSTATE_KERN, %wstate;                        /* Enable kernel mode window traps -- now we can trap again */ \
1603          \
1604          SET_MMU_CONTEXTID %g0, %g7, %g5;                            /* Switch MMU to kernel primary context */ \
1605          sethi     %hi(KERNBASE), %g5; \
1606          flush     %g5;                                                        /* Some convenient address that won't trap */ \
16071:
1608
1609/*
1610 * Interrupt setup is almost exactly like trap setup, but we need to
1611 * go to the interrupt stack if (a) we came from user mode or (b) we
1612 * came from kernel mode on the kernel stack.
1613 *
1614 * We don't guarantee any registers are preserved during this operation.
1615 */
1616#define   INTR_SETUP(stackspace) \
1617          sethi     %hi(EINTSTACK), %g1; \
1618          sethi     %hi((stackspace)), %g5; \
1619          btst      1, %sp; \
1620          add       %sp, BIAS, %g6; \
1621          movz      %icc, %sp, %g6; \
1622          or        %g1, %lo(EINTSTACK), %g1; \
1623          srl       %g6, 0, %g6;                                                /* truncate at 32-bits */ \
1624          set       (EINTSTACK-INTSTACK), %g7; \
1625          or        %g5, %lo((stackspace)), %g5; \
1626          sub       %g1, %g6, %g2;                                              /* Determine if we need to switch to intr stack or not */ \
1627          dec       %g7;                                                        /* Make it into a mask */ \
1628          sethi     %hi(CPUINFO_VA + CI_EINTSTACK), %g3; \
1629          andncc    %g2, %g7, %g0;                                              /* XXXXXXXXXX This assumes kernel addresses are unique from user addresses */ \
1630          LDPTR     [%g3 + %lo(CPUINFO_VA + CI_EINTSTACK)], %g3; \
1631          rdpr      %wstate, %g7;                                               /* Find if we're from user mode */ \
1632          movrnz    %g3, %g3, %g1;                                              /* Use saved intr stack if exists */ \
1633          sra       %g5, 0, %g5;                                                /* Sign extend the damn thing */ \
1634          movnz     %xcc, %g1, %g6;                                             /* Stay on interrupt stack? */ \
1635          cmp       %g7, WSTATE_KERN;                                 /* User or kernel sp? */ \
1636          movnz     %icc, %g1, %g6;                                             /* Stay on interrupt stack? */ \
1637          add       %g6, %g5, %g6;                                              /* Allocate a stack frame */ \
1638          \
1639          SAVE_LOCALS_INS \
1640          save      %g6, 0, %sp;                                                /* If we fault we should come right back here */ \
1641          stx       %i0, [%sp + CC64FSZ + STKB + TF_O + (0*8)];                 /* Save out registers to trap frame */ \
1642          stx       %i1, [%sp + CC64FSZ + STKB + TF_O + (1*8)]; \
1643          stx       %i2, [%sp + CC64FSZ + STKB + TF_O + (2*8)]; \
1644          stx       %i3, [%sp + CC64FSZ + STKB + TF_O + (3*8)]; \
1645          stx       %i4, [%sp + CC64FSZ + STKB + TF_O + (4*8)]; \
1646          stx       %i5, [%sp + CC64FSZ + STKB + TF_O + (5*8)]; \
1647          stx       %i6, [%sp + CC64FSZ + STKB + TF_O + (6*8)]; \
1648          stx       %i6, [%sp + CC64FSZ + STKB + TF_G + (0*8)];                 /* Save fp in clockframe->cf_fp */ \
1649          rdpr      %wstate, %g7;                                               /* Find if we're from user mode */ \
1650          stx       %i7, [%sp + CC64FSZ + STKB + TF_O + (7*8)]; \
1651          cmp       %g7, WSTATE_KERN;                                 /* Compare & leave in register */ \
1652          be,pn     %icc, 1f;                                         /* If we were in kernel mode start saving globals */ \
1653          /* came from user mode -- switch to kernel mode stack */ \
1654           rdpr     %otherwin, %g5;                                             /* Has this already been done? */ \
1655          tst       %g5; tnz %xcc, 1; nop; /* DEBUG -- this should _NEVER_ happen */ \
1656          brnz,pn   %g5, 1f;                                          /* Don't set this twice */ \
1657           rdpr     %canrestore, %g5;                                 /* Fixup register window state registers */ \
1658          wrpr      %g0, 0, %canrestore; \
1659          mov       CTX_PRIMARY, %g7; \
1660          wrpr      %g0, %g5, %otherwin; \
1661          wrpr      %g0, WSTATE_KERN, %wstate;                        /* Enable kernel mode window traps -- now we can trap again */ \
1662          SET_MMU_CONTEXTID %g0, %g7, %g5;                            /* Switch MMU to kernel primary context */ \
1663          sethi     %hi(KERNBASE), %g5; \
1664          flush     %g5;                                                        /* Some convenient address that won't trap */ \
16651:
1666#endif /* _LP64 */
1667
1668#ifdef DEBUG
1669
1670          /* Look up kpte to test algorithm */
1671          .globl    asmptechk
1672asmptechk:
1673          mov       %o0, %g4  ! pmap->pm_segs
1674          mov       %o1, %g3  ! Addr to lookup -- mind the context
1675
1676          srax      %g3, HOLESHIFT, %g5                     ! Check for valid address
1677          brz,pt    %g5, 0f                                           ! Should be zero or -1
1678           inc      %g5                                               ! Make -1 -> 0
1679          brnz,pn   %g5, 1f                                           ! Error!
16800:
1681           srlx     %g3, STSHIFT, %g5
1682          and       %g5, STMASK, %g5
1683          sll       %g5, 3, %g5
1684          add       %g4, %g5, %g4
1685          DLFLUSH(%g4,%g5)
1686          ldxa      [%g4] ASI_PHYS_CACHED, %g4              ! Remember -- UNSIGNED
1687          DLFLUSH2(%g5)
1688          brz,pn    %g4, 1f                                           ! NULL entry? check somewhere else
1689
1690           srlx     %g3, PDSHIFT, %g5
1691          and       %g5, PDMASK, %g5
1692          sll       %g5, 3, %g5
1693          add       %g4, %g5, %g4
1694          DLFLUSH(%g4,%g5)
1695          ldxa      [%g4] ASI_PHYS_CACHED, %g4              ! Remember -- UNSIGNED
1696          DLFLUSH2(%g5)
1697          brz,pn    %g4, 1f                                           ! NULL entry? check somewhere else
1698
1699           srlx     %g3, PTSHIFT, %g5                       ! Convert to ptab offset
1700          and       %g5, PTMASK, %g5
1701          sll       %g5, 3, %g5
1702          add       %g4, %g5, %g4
1703          DLFLUSH(%g4,%g5)
1704          ldxa      [%g4] ASI_PHYS_CACHED, %g6
1705          DLFLUSH2(%g5)
1706          brgez,pn %g6, 1f                                  ! Entry invalid?  Punt
1707           srlx     %g6, 32, %o0
1708          retl
1709           srl      %g6, 0, %o1
17101:
1711          mov       %g0, %o1
1712          retl
1713           mov      %g0, %o0
1714
1715          .data
17162:
1717          .asciz    "asmptechk: %x %x %x %x:%x\n"
1718          _ALIGN
1719          .text
1720#endif
1721
1722/*
1723 * This is the MMU protection handler.  It's too big to fit
1724 * in the trap table so I moved it here.  It's relatively simple.
1725 * It looks up the page mapping in the page table associated with
1726 * the trapping context.  It checks to see if the S/W writable bit
1727 * is set.  If so, it sets the H/W write bit, marks the tte modified,
1728 * and enters the mapping into the MMU.  Otherwise it does a regular
1729 * data fault.
1730 */
1731          ICACHE_ALIGN
1732dmmu_write_fault:
1733          mov       TLB_TAG_ACCESS, %g3
1734          sethi     %hi(0x1fff), %g6                        ! 8K context mask
1735          ldxa      [%g3] ASI_DMMU, %g3                     ! Get fault addr from Tag Target
1736          sethi     %hi(CPUINFO_VA+CI_CTXBUSY), %g4
1737          or        %g6, %lo(0x1fff), %g6
1738          LDPTR     [%g4 + %lo(CPUINFO_VA+CI_CTXBUSY)], %g4
1739          srax      %g3, HOLESHIFT, %g5                     ! Check for valid address
1740          and       %g3, %g6, %g6                                     ! Isolate context
1741
1742          inc       %g5                                               ! (0 or -1) -> (1 or 0)
1743          sllx      %g6, 3, %g6                                       ! Make it into an offset into ctxbusy
1744          ldx       [%g4+%g6], %g4                                    ! Load up our page table.
1745          srlx      %g3, STSHIFT, %g6
1746          cmp       %g5, 1
1747          bgu,pn %xcc, winfix                               ! Error!
1748           srlx     %g3, PDSHIFT, %g5
1749          and       %g6, STMASK, %g6
1750          sll       %g6, 3, %g6
1751
1752          and       %g5, PDMASK, %g5
1753          sll       %g5, 3, %g5
1754          add       %g6, %g4, %g4
1755          DLFLUSH(%g4,%g6)
1756          ldxa      [%g4] ASI_PHYS_CACHED, %g4
1757          DLFLUSH2(%g6)
1758          srlx      %g3, PTSHIFT, %g6                       ! Convert to ptab offset
1759          and       %g6, PTMASK, %g6
1760          add       %g5, %g4, %g5
1761          brz,pn    %g4, winfix                                       ! NULL entry? check somewhere else
1762           nop
1763
1764          ldxa      [%g5] ASI_PHYS_CACHED, %g4
1765          sll       %g6, 3, %g6
1766          brz,pn    %g4, winfix                                       ! NULL entry? check somewhere else
1767           add      %g6, %g4, %g6
17681:
1769          ldxa      [%g6] ASI_PHYS_CACHED, %g4
1770          brgez,pn %g4, winfix                                        ! Entry invalid?  Punt
1771           or       %g4, SUN4U_TTE_MODIFY|SUN4U_TTE_ACCESS|SUN4U_TTE_W, %g7     ! Update the modified bit
1772
1773          btst      SUN4U_TTE_REAL_W|SUN4U_TTE_W, %g4                           ! Is it a ref fault?
1774          bz,pn     %xcc, winfix                                      ! No -- really fault
1775#ifdef DEBUG
1776          /* Make sure we don't try to replace a kernel translation */
1777          /* This should not be necessary */
1778          sllx      %g3, 64-13, %g2                                   ! Isolate context bits
1779          sethi     %hi(KERNBASE), %g5                      ! Don't need %lo
1780          brnz,pt   %g2, 0f                                           ! Ignore context != 0
1781           set      0x0800000, %g2                                    ! 8MB
1782          sub       %g3, %g5, %g5
1783          cmp       %g5, %g2
1784          tlu       %xcc, 1; nop
1785          blu,pn    %xcc, winfix                                      ! Next insn in delay slot is unimportant
17860:
1787#endif
1788          /* Need to check for and handle large pages. */
1789           srlx     %g4, 61, %g5                                      ! Isolate the size bits
1790          ldxa      [%g0] ASI_DMMU_8KPTR, %g2               ! Load DMMU 8K TSB pointer
1791          andcc     %g5, 0x3, %g5                                     ! 8K?
1792          bnz,pn    %icc, winfix                                      ! We punt to the pmap code since we can't handle policy
1793           ldxa     [%g0] ASI_DMMU, %g1                     ! Load DMMU tag target register
1794          casxa     [%g6] ASI_PHYS_CACHED, %g4, %g7                   !  and write it out
1795          membar    #StoreLoad
1796          cmp       %g4, %g7
1797          bne,pn    %xcc, 1b
1798           or       %g4, SUN4U_TTE_MODIFY|SUN4U_TTE_ACCESS|SUN4U_TTE_W, %g4     ! Update the modified bit
1799          stx       %g1, [%g2]                                        ! Update TSB entry tag
1800          mov       SFSR, %g7
1801          stx       %g4, [%g2+8]                                      ! Update TSB entry data
1802          nop
1803
1804#ifdef TRAPSTATS
1805          sethi     %hi(_C_LABEL(protfix)), %g1
1806          lduw      [%g1+%lo(_C_LABEL(protfix))], %g2
1807          inc       %g2
1808          stw       %g2, [%g1+%lo(_C_LABEL(protfix))]
1809#endif
1810          mov       DEMAP_PAGE_SECONDARY, %g1               ! Secondary flush
1811          mov       DEMAP_PAGE_NUCLEUS, %g5                           ! Nucleus flush
1812          stxa      %g0, [%g7] ASI_DMMU                     ! clear out the fault
1813          sllx      %g3, (64-13), %g7                       ! Need to demap old entry first
1814          andn      %g3, 0xfff, %g6
1815          movrz     %g7, %g5, %g1                                     ! Pick one
1816          or        %g6, %g1, %g6
1817          membar    #Sync
1818          stxa      %g6, [%g6] ASI_DMMU_DEMAP               ! Do the demap
1819          membar    #Sync
1820
1821          stxa      %g4, [%g0] ASI_DMMU_DATA_IN             ! Enter new mapping
1822          membar    #Sync
1823          retry
1824
1825/*
1826 * Each memory data access fault from a fast access miss handler comes here.
1827 * We will quickly check if this is an original prom mapping before going
1828 * to the generic fault handler
1829 *
1830 * We will assume that %pil is not lost so we won't bother to save it
1831 * unless we're in an interrupt handler.
1832 *
1833 * On entry:
1834 *        We are on one of the alternate set of globals
1835 *        %g1 = MMU tag target
1836 *        %g2 = 8Kptr
1837 *        %g3 = TLB TAG ACCESS
1838 *
1839 * On return:
1840 *
1841 */
1842          ICACHE_ALIGN
1843data_miss:
1844#ifdef TRAPSTATS
1845          set       _C_LABEL(kdmiss), %g3
1846          set       _C_LABEL(udmiss), %g4
1847          rdpr      %tl, %g6
1848          dec       %g6
1849          movrz     %g6, %g4, %g3
1850          lduw      [%g3], %g4
1851          inc       %g4
1852          stw       %g4, [%g3]
1853#endif
1854          mov       TLB_TAG_ACCESS, %g3                     ! Get real fault page
1855          sethi     %hi(0x1fff), %g6                        ! 8K context mask
1856          ldxa      [%g3] ASI_DMMU, %g3                     ! from tag access register
1857          sethi     %hi(CPUINFO_VA+CI_CTXBUSY), %g4
1858          or        %g6, %lo(0x1fff), %g6
1859          LDPTR     [%g4 + %lo(CPUINFO_VA+CI_CTXBUSY)], %g4
1860          srax      %g3, HOLESHIFT, %g5                     ! Check for valid address
1861          and       %g3, %g6, %g6                                     ! Isolate context
1862
1863          inc       %g5                                               ! (0 or -1) -> (1 or 0)
1864          sllx      %g6, 3, %g6                                       ! Make it into an offset into ctxbusy
1865          ldx       [%g4+%g6], %g4                                    ! Load up our page table.
1866#ifdef DEBUG
1867          /* Make sure we don't try to replace a kernel translation */
1868          /* This should not be necessary */
1869          brnz,pt   %g6, 1f                       ! If user context continue miss
1870          sethi     %hi(KERNBASE), %g7                      ! Don't need %lo
1871          set       0x0800000, %g6                                    ! 8MB
1872          sub       %g3, %g7, %g7
1873          cmp       %g7, %g6
1874          tlu       %xcc, 1; nop
18751:
1876#endif
1877          srlx      %g3, STSHIFT, %g6
1878          cmp       %g5, 1
1879          bgu,pn %xcc, winfix                               ! Error!
1880           srlx     %g3, PDSHIFT, %g5
1881          and       %g6, STMASK, %g6
1882
1883          sll       %g6, 3, %g6
1884          and       %g5, PDMASK, %g5
1885          sll       %g5, 3, %g5
1886          add       %g6, %g4, %g4
1887          ldxa      [%g4] ASI_PHYS_CACHED, %g4
1888          srlx      %g3, PTSHIFT, %g6                       ! Convert to ptab offset
1889          and       %g6, PTMASK, %g6
1890          add       %g5, %g4, %g5
1891          brz,pn    %g4, data_nfo                                     ! NULL entry? check somewhere else
1892
1893           nop
1894          ldxa      [%g5] ASI_PHYS_CACHED, %g4
1895          sll       %g6, 3, %g6
1896          brz,pn    %g4, data_nfo                                     ! NULL entry? check somewhere else
1897           add      %g6, %g4, %g6
1898
18991:
1900          ldxa      [%g6] ASI_PHYS_CACHED, %g4
1901          brgez,pn %g4, data_nfo                                      ! Entry invalid?  Punt
1902           or       %g4, SUN4U_TTE_ACCESS, %g7                        ! Update the access bit
1903
1904          btst      SUN4U_TTE_ACCESS, %g4                                       ! Need to update access git?
1905          bne,pt    %xcc, 1f
1906           nop
1907          casxa     [%g6] ASI_PHYS_CACHED, %g4, %g7                   !  and write it out
1908          cmp       %g4, %g7
1909          bne,pn    %xcc, 1b
1910           or       %g4, SUN4U_TTE_ACCESS, %g4                        ! Update the access bit
1911
19121:
1913          stx       %g1, [%g2]                                        ! Update TSB entry tag
1914          stx       %g4, [%g2+8]                                      ! Update TSB entry data
1915          stxa      %g4, [%g0] ASI_DMMU_DATA_IN             ! Enter new mapping
1916          membar    #Sync
1917          CLRTT
1918          retry
1919          NOTREACHED
1920/*
1921 * We had a data miss but did not find a mapping.  Insert
1922 * a NFO mapping to satisfy speculative loads and return.
1923 * If this had been a real load, it will re-execute and
1924 * result in a data fault or protection fault rather than
1925 * a TLB miss.  We insert an 8K TTE with the valid and NFO
1926 * bits set.  All others should zero.  The TTE looks like this:
1927 *
1928 *        0x9000000000000000
1929 *
1930 */
1931data_nfo:
1932          sethi     %hi(0x90000000), %g4                              ! V(0x8)|NFO(0x1)
1933          sllx      %g4, 32, %g4
1934          stxa      %g4, [%g0] ASI_DMMU_DATA_IN             ! Enter new mapping
1935          membar    #Sync
1936          CLRTT
1937          retry
1938
1939/*
1940 * Handler for making the trap window shiny clean.
1941 *
1942 * If the store that trapped was to a kernel address, panic.
1943 *
1944 * If the store that trapped was to a user address, stick it in the PCB.
1945 * Since we don't want to force user code to use the standard register
1946 * convention if we don't have to, we will not assume that %fp points to
1947 * anything valid.
1948 *
1949 * On entry:
1950 *        We are on one of the alternate set of globals
1951 *        %g1 = %tl - 1, tstate[tl-1], scratch    - local
1952 *        %g2 = %tl                               - local
1953 *        %g3 = MMU tag access                              - in
1954 *        %g4 = %cwp                                        - local
1955 *        %g5 = scratch                                     - local
1956 *        %g6 = cpcb                                        - local
1957 *        %g7 = scratch                                     - local
1958 *
1959 * On return:
1960 *
1961 * NB:     remove most of this from main codepath & cleanup I$
1962 */
1963winfault:
1964          mov       TLB_TAG_ACCESS, %g3 ! Get real fault page from tag access register
1965          ldxa      [%g3] ASI_DMMU, %g3 ! And put it into the non-MMU alternate regs
1966winfix:
1967          rdpr      %tl, %g2
1968          subcc     %g2, 1, %g1
1969          ble,pt    %icc, datafault               ! Don't go below trap level 1
1970           sethi    %hi(CPCB), %g6                ! get current pcb
1971
1972
1973          wrpr      %g1, 0, %tl                   ! Pop a trap level
1974          rdpr      %tt, %g7            ! Read type of prev. trap
1975          rdpr      %tstate, %g4                  ! Try to restore prev %cwp if we were executing a restore
1976          andn      %g7, 0x3f, %g5                !   window fill traps are all 0b 0000 11xx xxxx
1977
1978#if 1
1979          cmp       %g7, 0x30           ! If we took a datafault just before this trap
1980          bne,pt    %icc, winfixfill    ! our stack's probably bad so we need to switch somewhere else
1981           nop
1982
1983          !!
1984          !! Double data fault -- bad stack?
1985          !!
1986          wrpr      %g2, %tl            ! Restore trap level.
1987          sir                                     ! Just issue a reset and don't try to recover.
1988          mov       %fp, %l6            ! Save the frame pointer
1989          set       EINTSTACK+USPACE+CC64FSZ-STKB, %fp ! Set the frame pointer to the middle of the idle stack
1990          add       %fp, -CC64FSZ, %sp  ! Create a stackframe
1991          wrpr      %g0, 15, %pil                 ! Disable interrupts, too
1992          wrpr      %g0, %g0, %canrestore         ! Our stack is hozed and our PCB
1993          wrpr      %g0, 7, %cansave    !  probably is too, so blow away
1994          ba        slowtrap            !  all our register windows.
1995           wrpr     %g0, 0x101, %tt
1996#endif
1997
1998winfixfill:
1999          cmp       %g5, 0x0c0                    !   so we mask lower bits & compare to 0b 0000 1100 0000
2000          bne,pt    %icc, winfixspill   ! Dump our trap frame -- we will retry the fill when the page is loaded
2001           cmp      %g5, 0x080                    !   window spill traps are all 0b 0000 10xx xxxx
2002
2003          !!
2004          !! This was a fill
2005          !!
2006#ifdef TRAPSTATS
2007          set       _C_LABEL(wfill), %g1
2008          lduw      [%g1], %g5
2009          inc       %g5
2010          stw       %g5, [%g1]
2011#endif
2012          btst      TSTATE_PRIV, %g4    ! User mode?
2013          and       %g4, CWP, %g5                 ! %g4 = %cwp of trap
2014          wrpr      %g7, 0, %tt
2015          bz,a,pt   %icc, datafault               ! We were in user mode -- normal fault
2016           wrpr     %g5, %cwp           ! Restore cwp from before fill trap -- regs should now be consistent
2017
2018          /*
2019           * We're in a pickle here.  We were trying to return to user mode
2020           * and the restore of the user window failed, so now we have one valid
2021           * kernel window and a user window state.  If we do a TRAP_SETUP() now,
2022           * our kernel window will be considered a user window and cause a
2023           * fault when we try to save it later due to an invalid user address.
2024           * If we return to where we faulted, our window state will not be valid
2025           * and we will fault trying to enter user with our primary context of zero.
2026           *
2027           * What we'll do is arrange to have us return to return_from_trap so we will
2028           * start the whole business over again.  But first, switch to a kernel window
2029           * setup.  Let's see, canrestore and otherwin are zero.  Set WSTATE_KERN and
2030           * make sure we're in kernel context and we're done.
2031           */
2032
2033#ifdef TRAPSTATS
2034          set       _C_LABEL(kwfill), %g4
2035          lduw      [%g4], %g7
2036          inc       %g7
2037          stw       %g7, [%g4]
2038#endif
2039#if 0 /* Need to switch over to new stuff to fix WDR bug */
2040          wrpr      %g5, %cwp                               ! Restore cwp from before fill trap -- regs should now be consistent
2041          wrpr      %g2, %g0, %tl                                     ! Restore trap level -- we need to reuse it
2042          set       return_from_trap, %g4                             ! XXX - need to set %g1 to tstate
2043          set       CTX_PRIMARY, %g7
2044          wrpr      %g4, 0, %tpc
2045          stxa      %g0, [%g7] ASI_DMMU
2046          inc       4, %g4
2047          membar    #Sync
2048          flush     %g4                                               ! Isn't this convenient?
2049          wrpr      %g0, WSTATE_KERN, %wstate
2050          wrpr      %g0, 0, %canrestore                     ! These should be zero but
2051          wrpr      %g0, 0, %otherwin                       ! clear them just in case
2052          rdpr      %ver, %g5
2053          and       %g5, CWP, %g5
2054          wrpr      %g0, 0, %cleanwin
2055          dec       1, %g5                                            ! NWINDOWS-1-1
2056          wrpr      %g5, 0, %cansave                        ! Invalidate all windows
2057!         flushw                                                      ! DEBUG
2058          ba,pt     %icc, datafault
2059           wrpr     %g4, 0, %tnpc
2060#else
2061          wrpr      %g2, %g0, %tl                                     ! Restore trap level
2062          cmp       %g2, 3
2063          tne       %icc, 1
2064          rdpr      %tt, %g5
2065          wrpr      %g0, 1, %tl                                       ! Revert to TL==1 XXX what if this wasn't in rft_user? Oh well.
2066          wrpr      %g5, %g0, %tt                                     ! Set trap type correctly
2067/*
2068 * Here we need to implement the beginning of datafault.
2069 * TRAP_SETUP expects to come from either kernel mode or
2070 * user mode with at least one valid register window.  It
2071 * will allocate a trap frame, save the out registers, and
2072 * fix the window registers to think we have one user
2073 * register window.
2074 *
2075 * However, under these circumstances we don't have any
2076 * valid register windows, so we need to clean up the window
2077 * registers to prevent garbage from being saved to either
2078 * the user stack or the PCB before calling the datafault
2079 * handler.
2080 *
2081 * We could simply jump to datafault if we could somehow
2082 * make the handler issue a `saved' instruction immediately
2083 * after creating the trapframe.
2084 *
2085 * The following is duplicated from datafault:
2086 */
2087#ifdef TRAPS_USE_IG
2088          wrpr      %g0, PSTATE_KERN|PSTATE_IG, %pstate     ! We need to save volatile stuff to interrupt globals
2089#else
2090          wrpr      %g0, PSTATE_KERN|PSTATE_AG, %pstate     ! We need to save volatile stuff to alternate globals
2091#endif
2092          wr        %g0, ASI_DMMU, %asi                     ! We need to re-load trap info
2093          ldxa      [%g0 + TLB_TAG_ACCESS] %asi, %g1        ! Get fault address from tag access register
2094          ldxa      [SFAR] %asi, %g2                        ! sync virt addr; must be read first
2095          ldxa      [SFSR] %asi, %g3                        ! get sync fault status register
2096          stxa      %g0, [SFSR] %asi                        ! Clear out fault now
2097
2098          TRAP_SETUP(-CC64FSZ-TF_SIZE)
2099          saved                                                       ! Blow away that one register window we didn't ever use.
2100          ba,a,pt   %icc, Ldatafault_internal               ! Now we should return directly to user mode
2101           nop
2102#endif
2103winfixspill:
2104          bne,a,pt  %xcc, datafault                         ! Was not a spill -- handle it normally
2105           wrpr     %g2, 0, %tl                                       ! Restore trap level for now XXXX
2106
2107          !!
2108          !! This was a spill
2109          !!
2110#if 1
2111          btst      TSTATE_PRIV, %g4    ! From user mode?
2112          wrpr      %g2, 0, %tl                   ! We need to load the fault type so we can
2113          rdpr      %tt, %g5            ! overwrite the lower trap and get it to the fault handler
2114          wrpr      %g1, 0, %tl
2115          wrpr      %g5, 0, %tt                   ! Copy over trap type for the fault handler
2116          and       %g4, CWP, %g5                 ! find %cwp from trap
2117          be,a,pt   %xcc, datafault               ! Let's do a regular datafault.  When we try a save in datafault we'll
2118           wrpr     %g5, 0, %cwp                  !  return here and write out all dirty windows.
2119#endif
2120          wrpr      %g2, 0, %tl                                       ! Restore trap level for now XXXX
2121          LDPTR     [%g6 + %lo(CPCB)], %g6        ! This is in the locked TLB and should not fault
2122#ifdef TRAPSTATS
2123          set       _C_LABEL(wspill), %g7
2124          lduw      [%g7], %g5
2125          inc       %g5
2126          stw       %g5, [%g7]
2127#endif
2128
2129          /*
2130           * Traverse kernel map to find paddr of cpcb and only us ASI_PHYS_CACHED to
2131           * prevent any faults while saving the windows.  BTW if it isn't mapped, we
2132           * will trap and hopefully panic.
2133           */
2134
2135!         ba        0f                                                ! DEBUG -- don't use phys addresses
2136           wr       %g0, ASI_NUCLEUS, %asi                            ! In case of problems finding PA
2137          sethi     %hi(CPUINFO_VA+CI_CTXBUSY), %g1
2138          LDPTR     [%g1 + %lo(CPUINFO_VA+CI_CTXBUSY)], %g1 ! Load start of ctxbusy
2139#ifdef DEBUG
2140          srax      %g6, HOLESHIFT, %g7                     ! Check for valid address
2141          brz,pt    %g7, 1f                                           ! Should be zero or -1
2142           addcc    %g7, 1, %g7                                                 ! Make -1 -> 0
2143          tnz       %xcc, 1                                           ! Invalid address??? How did this happen?
21441:
2145#endif
2146          srlx      %g6, STSHIFT, %g7
2147          ldx       [%g1], %g1                                        ! Load pointer to kernel_pmap
2148          and       %g7, STMASK, %g7
2149          sll       %g7, 3, %g7
2150          add       %g7, %g1, %g1
2151          DLFLUSH(%g1,%g7)
2152          ldxa      [%g1] ASI_PHYS_CACHED, %g1              ! Load pointer to directory
2153          DLFLUSH2(%g7)
2154
2155          srlx      %g6, PDSHIFT, %g7                       ! Do page directory
2156          and       %g7, PDMASK, %g7
2157          sll       %g7, 3, %g7
2158          brz,pn    %g1, 0f
2159           add      %g7, %g1, %g1
2160          DLFLUSH(%g1,%g7)
2161          ldxa      [%g1] ASI_PHYS_CACHED, %g1
2162          DLFLUSH2(%g7)
2163
2164          srlx      %g6, PTSHIFT, %g7                       ! Convert to ptab offset
2165          and       %g7, PTMASK, %g7
2166          brz       %g1, 0f
2167           sll      %g7, 3, %g7
2168          add       %g1, %g7, %g7
2169          DLFLUSH(%g7,%g1)
2170          ldxa      [%g7] ASI_PHYS_CACHED, %g7              ! This one is not
2171          DLFLUSH2(%g1)
2172          brgez     %g7, 0f
2173           srlx     %g7, PGSHIFT, %g7                       ! Isolate PA part
2174          sll       %g6, 32-PGSHIFT, %g6                              ! And offset
2175          sllx      %g7, PGSHIFT+23, %g7                              ! There are 23 bits to the left of the PA in the TTE
2176          srl       %g6, 32-PGSHIFT, %g6
2177          srax      %g7, 23, %g7
2178          or        %g7, %g6, %g6                                     ! Then combine them to form PA
2179
2180          wr        %g0, ASI_PHYS_CACHED, %asi              ! Use ASI_PHYS_CACHED to prevent possible page faults
21810:
2182          /*
2183           * Now save all user windows to cpcb.
2184           */
2185#ifdef NOTDEF_DEBUG
2186          add       %g6, PCB_NSAVED, %g7
2187          DLFLUSH(%g7,%g5)
2188          lduba     [%g6 + PCB_NSAVED] %asi, %g7            ! make sure that pcb_nsaved
2189          DLFLUSH2(%g5)
2190          brz,pt    %g7, 1f                                           ! is zero, else
2191           nop
2192          wrpr      %g0, 4, %tl
2193          sir                                                         ! Force a watchdog
21941:
2195#endif
2196          rdpr      %otherwin, %g7
2197          brnz,pt   %g7, 1f
2198           rdpr     %canrestore, %g5
2199          rdpr      %cansave, %g1
2200          add       %g5, 1, %g7                                       ! add the %cwp window to the list to save
2201!         movrnz    %g1, %g5, %g7                                     ! If we're issuing a save
2202!         mov       %g5, %g7                                ! DEBUG
2203          wrpr      %g0, 0, %canrestore
2204          wrpr      %g7, 0, %otherwin                       ! Still in user mode -- need to switch to kernel mode
22051:
2206          mov       %g7, %g1
2207          add       %g6, PCB_NSAVED, %g7
2208          DLFLUSH(%g7,%g5)
2209          lduba     [%g6 + PCB_NSAVED] %asi, %g7            ! Start incrementing pcb_nsaved
2210          DLFLUSH2(%g5)
2211
2212#ifdef DEBUG
2213          wrpr      %g0, 5, %tl
2214#endif
2215          mov       %g6, %g5
2216          brz,pt    %g7, winfixsave                                   ! If it's in use, panic
2217           saved                                                      ! frob window registers
2218
2219          /* PANIC */
2220!         sir                                                         ! Force a watchdog
2221#ifdef DEBUG
2222          wrpr      %g2, 0, %tl
2223#endif
2224          mov       %g7, %o2
2225          rdpr      %ver, %o1
2226          sethi     %hi(2f), %o0
2227          and       %o1, CWP, %o1
2228          wrpr      %g0, %o1, %cleanwin
2229          dec       1, %o1
2230          wrpr      %g0, %o1, %cansave                      ! kludge away any more window problems
2231          wrpr      %g0, 0, %canrestore
2232          wrpr      %g0, 0, %otherwin
2233          or        %lo(2f), %o0, %o0
2234          wrpr      %g0, WSTATE_KERN, %wstate
2235          set       PANICSTACK-CC64FSZ-STKB, %sp
2236          ta        1; nop                                            ! This helps out traptrace.
2237          call      _C_LABEL(panic)                                   ! This needs to be fixed properly but we should panic here
2238           mov      %g1, %o1
2239          NOTREACHED
2240          .data
22412:
2242          .asciz    "winfault: double invalid window at %p, nsaved=%d"
2243          _ALIGN
2244          .text
22453:
2246          saved
2247          save
2248winfixsave:
2249          stxa      %l0, [%g5 + PCB_RW + ( 0*8)] %asi       ! Save the window in the pcb, we can schedule other stuff in here
2250          stxa      %l1, [%g5 + PCB_RW + ( 1*8)] %asi
2251          stxa      %l2, [%g5 + PCB_RW + ( 2*8)] %asi
2252          stxa      %l3, [%g5 + PCB_RW + ( 3*8)] %asi
2253          stxa      %l4, [%g5 + PCB_RW + ( 4*8)] %asi
2254          stxa      %l5, [%g5 + PCB_RW + ( 5*8)] %asi
2255          stxa      %l6, [%g5 + PCB_RW + ( 6*8)] %asi
2256          stxa      %l7, [%g5 + PCB_RW + ( 7*8)] %asi
2257
2258          stxa      %i0, [%g5 + PCB_RW + ( 8*8)] %asi
2259          stxa      %i1, [%g5 + PCB_RW + ( 9*8)] %asi
2260          stxa      %i2, [%g5 + PCB_RW + (10*8)] %asi
2261          stxa      %i3, [%g5 + PCB_RW + (11*8)] %asi
2262          stxa      %i4, [%g5 + PCB_RW + (12*8)] %asi
2263          stxa      %i5, [%g5 + PCB_RW + (13*8)] %asi
2264          stxa      %i6, [%g5 + PCB_RW + (14*8)] %asi
2265          stxa      %i7, [%g5 + PCB_RW + (15*8)] %asi
2266
2267!         rdpr      %otherwin, %g1      ! Check to see if we's done
2268          dec       %g1
2269          wrpr      %g0, 7, %cleanwin                       ! BUGBUG -- we should not hardcode this, but I have no spare globals
2270          inc       16*8, %g5                               ! Move to next window
2271          inc       %g7                                               ! inc pcb_nsaved
2272          brnz,pt   %g1, 3b
2273           stxa     %o6, [%g5 + PCB_RW + (14*8)] %asi       ! Save %sp so we can write these all out
2274
2275          /* fix up pcb fields */
2276          stba      %g7, [%g6 + PCB_NSAVED] %asi            ! cpcb->pcb_nsaved = n
2277#if 0
2278          mov       %g7, %g5                                ! fixup window registers
22795:
2280          dec       %g5
2281          brgz,a,pt %g5, 5b
2282           restore
2283#ifdef NOT_DEBUG
2284          rdpr      %wstate, %g5                                      ! DEBUG
2285          wrpr      %g0, WSTATE_KERN, %wstate               ! DEBUG
2286          wrpr      %g0, 4, %tl
2287          rdpr      %cansave, %g7
2288          rdpr      %canrestore, %g6
2289          flushw                                                      ! DEBUG
2290          wrpr      %g2, 0, %tl
2291          wrpr      %g5, 0, %wstate                                   ! DEBUG
2292#endif
2293#else
2294          /*
2295           * We just issued a bunch of saves, so %cansave is now 0,
2296           * probably (if we were doing a flushw then we may have
2297           * come in with only partially full register windows and
2298           * it may not be 0).
2299           *
2300           * %g7 contains the count of the windows we just finished
2301           * saving.
2302           *
2303           * What we need to do now is move some of the windows from
2304           * %canrestore to %cansave.  What we should do is take
2305           * min(%canrestore, %g7) and move that over to %cansave.
2306           *
2307           * %g7 is the number of windows we flushed, so we should
2308           * use that as a base.  Clear out %otherwin, set %cansave
2309           * to min(%g7, NWINDOWS - 2), set %cleanwin to %canrestore
2310           * + %cansave and the rest follows:
2311           *
2312           * %otherwin = 0
2313           * %cansave = NWINDOWS - 2 - %canrestore
2314           */
2315          wrpr      %g0, 0, %otherwin
2316          rdpr      %canrestore, %g1
2317          sub       %g1, %g7, %g1                                     ! Calculate %canrestore - %g7
2318          movrlz    %g1, %g0, %g1                                     ! Clamp at zero
2319          wrpr      %g1, 0, %canrestore                     ! This is the new canrestore
2320          rdpr      %ver, %g5
2321          and       %g5, CWP, %g5                                     ! NWINDOWS-1
2322          dec       %g5                                               ! NWINDOWS-2
2323          wrpr      %g5, 0, %cleanwin                       ! Set cleanwin to max, since we're in-kernel
2324          sub       %g5, %g1, %g5                                     ! NWINDOWS-2-%canrestore
2325          wrpr      %g5, 0, %cansave
2326#ifdef NOT_DEBUG
2327          rdpr      %wstate, %g5                                      ! DEBUG
2328          wrpr      %g0, WSTATE_KERN, %wstate               ! DEBUG
2329          wrpr      %g0, 4, %tl
2330          flushw                                                      ! DEBUG
2331          wrpr      %g2, 0, %tl
2332          wrpr      %g5, 0, %wstate                                   ! DEBUG
2333#endif
2334#endif
2335
2336#ifdef NOTDEF_DEBUG
2337          set       panicstack-CC64FSZ, %g1
2338          save      %g1, 0, %sp
2339          GLOBTOLOC
2340          rdpr      %wstate, %l0
2341          wrpr      %g0, WSTATE_KERN, %wstate
2342          set       8f, %o0
2343          mov       %g7, %o1
2344          call      printf
2345           mov      %g5, %o2
2346          wrpr      %l0, 0, %wstate
2347          LOCTOGLOB
2348          restore
2349          .data
23508:
2351          .asciz    "winfix: spill fixup\n"
2352          _ALIGN
2353          .text
2354#endif
2355!         rdpr      %tl, %g2                                ! DEBUG DEBUG -- did we trap somewhere?
2356          sub       %g2, 1, %g1
2357          rdpr      %tt, %g2
2358          wrpr      %g1, 0, %tl                                       ! We will not attempt to re-execute the spill, so dump our trap frame permanently
2359          wrpr      %g2, 0, %tt                                       ! Move trap type from fault frame here, overwriting spill
2360
2361          /* Did we save a user or kernel window ? */
2362!         srax      %g3, 48, %g5                                      ! User or kernel store? (TAG TARGET)
2363          sllx      %g3, (64-13), %g5                       ! User or kernel store? (TAG ACCESS)
2364          sethi     %hi(dcache_size), %g7
2365          ld        [%g7 + %lo(dcache_size)], %g7
2366          sethi     %hi(dcache_line_size), %g6
2367          ld        [%g6 + %lo(dcache_line_size)], %g6
2368          brnz,pt   %g5, 1f                                           ! User fault -- save windows to pcb
2369           sub      %g7, %g6, %g7
2370
2371          and       %g4, CWP, %g4                                     ! %g4 = %cwp of trap
2372          wrpr      %g4, 0, %cwp                                      ! Kernel fault -- restore %cwp and force and trap to debugger
2373          !!
2374          !! Here we managed to fault trying to access a kernel window
2375          !! This is a bug.  Switch to the interrupt stack if we aren't
2376          !! there already and then trap into the debugger or panic.
2377          !!
2378          sethi     %hi(EINTSTACK-BIAS), %g6
2379          btst      1, %sp
2380          bnz,pt    %icc, 0f
2381           mov      %sp, %g1
2382          add       %sp, -BIAS, %g1
23830:
2384          or        %g6, %lo(EINTSTACK-BIAS), %g6
2385          set       (EINTSTACK-INTSTACK), %g7     ! XXXXXXXXXX This assumes kernel addresses are unique from user addresses
2386          sub       %g6, %g1, %g2                                     ! Determine if we need to switch to intr stack or not
2387          dec       %g7                                               ! Make it into a mask
2388          andncc    %g2, %g7, %g0                                     ! XXXXXXXXXX This assumes kernel addresses are unique from user addresses */ \
2389          movz      %xcc, %g1, %g6                                    ! Stay on interrupt stack?
2390          add       %g6, -CCFSZ, %g6                        ! Allocate a stack frame
2391          mov       %sp, %l6                                ! XXXXX Save old stack pointer
2392          mov       %g6, %sp
2393          ta        1; nop                                            ! Enter debugger
2394          NOTREACHED
23951:
2396#if 1
2397          /* Now we need to blast away the D$ to make sure we're in sync */
2398          stxa      %g0, [%g7] ASI_DCACHE_TAG
2399          brnz,pt   %g7, 1b
2400           sub      %g7, %g6, %g7
2401#endif
2402
2403#ifdef NOTDEF_DEBUG
2404          set       panicstack-CC64FSZ, %g5
2405          save      %g5, 0, %sp
2406          GLOBTOLOC
2407          rdpr      %wstate, %l0
2408          wrpr      %g0, WSTATE_KERN, %wstate
2409          set       8f, %o0
2410          call      printf
2411           mov      %fp, %o1
2412          wrpr      %l0, 0, %wstate
2413          LOCTOGLOB
2414          restore
2415          .data
24168:
2417          .asciz    "winfix: kernel spill retry\n"
2418          _ALIGN
2419          .text
2420#endif
2421#ifdef TRAPSTATS
2422          set       _C_LABEL(wspillskip), %g4
2423          lduw      [%g4], %g5
2424          inc       %g5
2425          stw       %g5, [%g4]
2426#endif
2427          /*
2428           * If we had WSTATE_KERN then we had at least one valid kernel window.
2429           * We should re-execute the trapping save.
2430           */
2431          rdpr      %wstate, %g3
2432          mov       %g3, %g3
2433          cmp       %g3, WSTATE_KERN
2434          bne,pt    %icc, 1f
2435           nop
2436          retry                                                       ! Now we can complete the save
24371:
2438          /*
2439           * Since we had a WSTATE_USER, we had no valid kernel windows.  This should
2440           * only happen inside TRAP_SETUP or INTR_SETUP. Emulate
2441           * the instruction, clean up the register windows, then done.
2442           */
2443          rdpr      %cwp, %g1
2444          inc       %g1
2445          rdpr      %tstate, %g2
2446          wrpr      %g1, %cwp
2447          andn      %g2, CWP, %g2
2448          wrpr      %g1, %g2, %tstate
2449#ifdef TRAPS_USE_IG
2450          wrpr      %g0, PSTATE_KERN|PSTATE_IG, %pstate     ! DEBUG
2451#else
2452          wrpr      %g0, PSTATE_KERN|PSTATE_AG, %pstate
2453#endif
2454          mov       %g6, %sp
2455          done
2456
2457/*
2458 * Each memory data access fault, from user or kernel mode,
2459 * comes here.
2460 *
2461 * We will assume that %pil is not lost so we won't bother to save it
2462 * unless we're in an interrupt handler.
2463 *
2464 * On entry:
2465 *        We are on one of the alternate set of globals
2466 *        %g1 = MMU tag target
2467 *        %g2 = %tl
2468 *
2469 * On return:
2470 *
2471 */
2472datafault:
2473#ifdef TRAPS_USE_IG
2474          wrpr      %g0, PSTATE_KERN|PSTATE_IG, %pstate     ! We need to save volatile stuff to interrupt globals
2475#else
2476          wrpr      %g0, PSTATE_KERN|PSTATE_AG, %pstate     ! We need to save volatile stuff to alternate globals
2477#endif
2478          wr        %g0, ASI_DMMU, %asi                     ! We need to re-load trap info
2479          ldxa      [%g0 + TLB_TAG_ACCESS] %asi, %g1        ! Get fault address from tag access register
2480          ldxa      [SFAR] %asi, %g2                        ! sync virt addr; must be read first
2481          ldxa      [SFSR] %asi, %g3                        ! get sync fault status register
2482          stxa      %g0, [SFSR] %asi                        ! Clear out fault now
2483
2484          TRAP_SETUP(-CC64FSZ-TF_SIZE)
2485Ldatafault_internal:
2486          INCR64(CPUINFO_VA+CI_NFAULT)                      ! cnt.v_faults++ (clobbers %o0,%o1)
2487!         ldx       [%sp + CC64FSZ + STKB + TF_FAULT], %g1  ! DEBUG make sure this has not changed
2488          mov       %g1, %o0                                ! Move these to the out regs so we can save the globals
2489          mov       %g2, %o4
2490          mov       %g3, %o5
2491
2492          ldxa      [%g0] ASI_AFAR, %o2                     ! get async fault address
2493          ldxa      [%g0] ASI_AFSR, %o3                     ! get async fault status
2494          mov       -1, %g7
2495          stxa      %g7, [%g0] ASI_AFSR                     ! And clear this out, too
2496
2497          wrpr      %g0, PSTATE_KERN, %pstate               ! Get back to normal globals
2498
2499          stx       %g1, [%sp + CC64FSZ + STKB + TF_G + (1*8)]        ! save g1
2500          rdpr      %tt, %o1                                          ! find out what trap brought us here
2501          stx       %g2, [%sp + CC64FSZ + STKB + TF_G + (2*8)]        ! save g2
2502          rdpr      %tstate, %g1
2503          stx       %g3, [%sp + CC64FSZ + STKB + TF_G + (3*8)]        ! (sneak g3 in here)
2504          rdpr      %tpc, %g2
2505          stx       %g4, [%sp + CC64FSZ + STKB + TF_G + (4*8)]        ! sneak in g4
2506          rdpr      %tnpc, %g3
2507          stx       %g5, [%sp + CC64FSZ + STKB + TF_G + (5*8)]        ! sneak in g5
2508          mov       %g2, %o7                                          ! Make the fault address look like the return address
2509          stx       %g6, [%sp + CC64FSZ + STKB + TF_G + (6*8)]        ! sneak in g6
2510          rd        %y, %g5                                                     ! save y
2511          stx       %g7, [%sp + CC64FSZ + STKB + TF_G + (7*8)]        ! sneak in g7
2512
2513          sth       %o1, [%sp + CC64FSZ + STKB + TF_TT]
2514          stx       %g1, [%sp + CC64FSZ + STKB + TF_TSTATE]           ! set tf.tf_psr, tf.tf_pc
2515          stx       %g2, [%sp + CC64FSZ + STKB + TF_PC]               ! set tf.tf_npc
2516          stx       %g3, [%sp + CC64FSZ + STKB + TF_NPC]
2517
2518          rdpr      %pil, %g4
2519          stb       %g4, [%sp + CC64FSZ + STKB + TF_PIL]
2520          stb       %g4, [%sp + CC64FSZ + STKB + TF_OLDPIL]
2521
2522#if 1
2523          rdpr      %tl, %g7
2524          dec       %g7
2525          movrlz    %g7, %g0, %g7
2526          wrpr      %g0, %g7, %tl                 ! Revert to kernel mode
2527#else
2528          wrpr      %g0, 0, %tl                   ! Revert to kernel mode
2529#endif
2530          /* Finish stackframe, call C trap handler */
2531          flushw                                                      ! Get this clean so we won't take any more user faults
2532#ifdef NOTDEF_DEBUG
2533          set       CPCB, %o7
2534          LDPTR     [%o7], %o7
2535          ldub      [%o7 + PCB_NSAVED], %o7
2536          brz,pt    %o7, 2f
2537           nop
2538          save      %sp, -CC64FSZ, %sp
2539          set       1f, %o0
2540          call printf
2541           mov      %i7, %o1
2542          ta        1; nop
2543           restore
2544          .data
25451:        .asciz    "datafault: nsaved = %d\n"
2546          _ALIGN
2547          .text
25482:
2549#endif
2550          !! In the EMBEDANY memory model %g4 points to the start of the data segment.
2551          !! In our case we need to clear it before calling any C-code
2552          clr       %g4
2553
2554          /*
2555           * Right now the registers have the following values:
2556           *
2557           *        %o0 -- MMU_TAG_ACCESS
2558           *        %o1 -- TT
2559           *        %o2 -- afar
2560           *        %o3 -- afsr
2561           *        %o4 -- sfar
2562           *        %o5 -- sfsr
2563           */
2564
2565          cmp       %o1, T_DATA_ERROR
2566          st        %g5, [%sp + CC64FSZ + STKB + TF_Y]
2567          wr        %g0, ASI_PRIMARY_NOFAULT, %asi          ! Restore default ASI
2568          be,pn     %icc, data_error
2569           wrpr     %g0, PSTATE_INTR, %pstate     ! reenable interrupts
2570
2571          mov       %o0, %o3                      ! (argument: trap address)
2572          mov       %g2, %o2                      ! (argument: trap pc)
2573          call      _C_LABEL(data_access_fault)   ! data_access_fault(&tf, type,
2574                                                            !         pc, addr, sfva, sfsr)
2575           add      %sp, CC64FSZ + STKB, %o0      ! (argument: &tf)
2576
2577data_recover:
2578#ifdef TRAPSTATS
2579          set       _C_LABEL(uintrcnt), %g1
2580          stw       %g0, [%g1]
2581          set       _C_LABEL(iveccnt), %g1
2582          stw       %g0, [%g1]
2583#endif
2584          wrpr      %g0, PSTATE_KERN, %pstate               ! disable interrupts
2585          b         return_from_trap                        ! go return
2586           ldx      [%sp + CC64FSZ + STKB + TF_TSTATE], %g1           ! Load this for return_from_trap
2587          NOTREACHED
2588
2589data_error:
2590          call      _C_LABEL(data_access_error)   ! data_access_error(&tf, type,
2591                                                            !         afva, afsr, sfva, sfsr)
2592           add      %sp, CC64FSZ + STKB, %o0      ! (argument: &tf)
2593          ba        data_recover
2594           nop
2595          NOTREACHED
2596
2597/*
2598 * Each memory instruction access fault from a fast access handler comes here.
2599 * We will quickly check if this is an original prom mapping before going
2600 * to the generic fault handler
2601 *
2602 * We will assume that %pil is not lost so we won't bother to save it
2603 * unless we're in an interrupt handler.
2604 *
2605 * On entry:
2606 *        We are on one of the alternate set of globals
2607 *        %g1 = MMU tag target
2608 *        %g2 = TSB entry ptr
2609 *        %g3 = TLB Tag Access
2610 *
2611 * On return:
2612 *
2613 */
2614
2615          ICACHE_ALIGN
2616instr_miss:
2617#ifdef TRAPSTATS
2618          set       _C_LABEL(ktmiss), %g3
2619          set       _C_LABEL(utmiss), %g4
2620          rdpr      %tl, %g6
2621          dec       %g6
2622          movrz     %g6, %g4, %g3
2623          lduw      [%g3], %g4
2624          inc       %g4
2625          stw       %g4, [%g3]
2626#endif
2627          mov       TLB_TAG_ACCESS, %g3                     ! Get real fault page
2628          sethi     %hi(0x1fff), %g7                        ! 8K context mask
2629          ldxa      [%g3] ASI_IMMU, %g3                     ! from tag access register
2630          sethi     %hi(CPUINFO_VA+CI_CTXBUSY), %g4
2631          or        %g7, %lo(0x1fff), %g7
2632          LDPTR     [%g4 + %lo(CPUINFO_VA+CI_CTXBUSY)], %g4
2633          srax      %g3, HOLESHIFT, %g5                     ! Check for valid address
2634          and       %g3, %g7, %g6                                     ! Isolate context
2635          sllx      %g6, 3, %g6                                       ! Make it into an offset into ctxbusy
2636          inc       %g5                                               ! (0 or -1) -> (1 or 0)
2637          ldx       [%g4+%g6], %g4                                    ! Load up our page table.
2638#ifdef DEBUG
2639          /* Make sure we don't try to replace a kernel translation */
2640          /* This should not be necessary */
2641          brnz,pt   %g6, 1f                                           ! If user context continue miss
2642          sethi     %hi(KERNBASE), %g7                      ! Don't need %lo
2643          set       0x0800000, %g6                                    ! 8MB
2644          sub       %g3, %g7, %g7
2645          cmp       %g7, %g6
2646          tlu       %xcc, 1; nop
26471:
2648#endif
2649          srlx      %g3, STSHIFT, %g6
2650          cmp       %g5, 1
2651          bgu,pn %xcc, textfault                                      ! Error!
2652           srlx     %g3, PDSHIFT, %g5
2653          and       %g6, STMASK, %g6
2654          sll       %g6, 3, %g6
2655          and       %g5, PDMASK, %g5
2656          nop
2657
2658          sll       %g5, 3, %g5
2659          add       %g6, %g4, %g4
2660          ldxa      [%g4] ASI_PHYS_CACHED, %g4
2661          srlx      %g3, PTSHIFT, %g6                       ! Convert to ptab offset
2662          and       %g6, PTMASK, %g6
2663          add       %g5, %g4, %g5
2664          brz,pn    %g4, textfault                                    ! NULL entry? check somewhere else
2665           nop
2666
2667          ldxa      [%g5] ASI_PHYS_CACHED, %g4
2668          sll       %g6, 3, %g6
2669          brz,pn    %g4, textfault                                    ! NULL entry? check somewhere else
2670           add      %g6, %g4, %g6
26711:
2672          ldxa      [%g6] ASI_PHYS_CACHED, %g4
2673          brgez,pn %g4, textfault
2674           nop
2675
2676          /* Check if it's an executable mapping. */
2677          andcc     %g4, SUN4U_TTE_EXEC, %g0
2678          bz,pn     %xcc, textfault
2679           nop
2680
2681          or        %g4, SUN4U_TTE_ACCESS, %g7                        ! Update accessed bit
2682          btst      SUN4U_TTE_ACCESS, %g4                                       ! Need to update access git?
2683          bne,pt    %xcc, 1f
2684           nop
2685          casxa     [%g6] ASI_PHYS_CACHED, %g4, %g7                   !  and store it
2686          cmp       %g4, %g7
2687          bne,pn    %xcc, 1b
2688           or       %g4, SUN4U_TTE_ACCESS, %g4                        ! Update accessed bit
26891:
2690          stx       %g1, [%g2]                                        ! Update TSB entry tag
2691          stx       %g4, [%g2+8]                                      ! Update TSB entry data
2692          stxa      %g4, [%g0] ASI_IMMU_DATA_IN             ! Enter new mapping
2693          membar    #Sync
2694          CLRTT
2695          retry
2696          NOTREACHED
2697          !!
2698          !!  Check our prom mappings -- temporary
2699          !!
2700
2701/*
2702 * Each memory text access fault, from user or kernel mode,
2703 * comes here.
2704 *
2705 * We will assume that %pil is not lost so we won't bother to save it
2706 * unless we're in an interrupt handler.
2707 *
2708 * On entry:
2709 *        We are on one of the alternate set of globals
2710 *        %g1 = MMU tag target
2711 *        %g2 = %tl
2712 *        %g3 = %tl - 1
2713 *
2714 * On return:
2715 *
2716 */
2717
2718textfault:
2719#ifdef TRAPS_USE_IG
2720          wrpr      %g0, PSTATE_KERN|PSTATE_IG, %pstate     ! We need to save volatile stuff to interrupt globals
2721#else
2722          wrpr      %g0, PSTATE_KERN|PSTATE_AG, %pstate     ! We need to save volatile stuff to alternate globals
2723#endif
2724          wr        %g0, ASI_IMMU, %asi
2725          ldxa      [%g0 + TLB_TAG_ACCESS] %asi, %g1        ! Get fault address from tag access register
2726          ldxa      [SFSR] %asi, %g3                        ! get sync fault status register
2727          membar    #LoadStore
2728          stxa      %g0, [SFSR] %asi                        ! Clear out old info
2729
2730          TRAP_SETUP(-CC64FSZ-TF_SIZE)
2731          INCR64(CPUINFO_VA+CI_NFAULT)                      ! cnt.v_faults++ (clobbers %o0,%o1)
2732
2733          mov       %g3, %o3
2734
2735          wrpr      %g0, PSTATE_KERN, %pstate               ! Switch to normal globals
2736          ldxa      [%g0] ASI_AFSR, %o4                     ! get async fault status
2737          ldxa      [%g0] ASI_AFAR, %o5                     ! get async fault address
2738          mov       -1, %o0
2739          stxa      %o0, [%g0] ASI_AFSR                     ! Clear this out
2740          stx       %g1, [%sp + CC64FSZ + STKB + TF_G + (1*8)]        ! save g1
2741          stx       %g2, [%sp + CC64FSZ + STKB + TF_G + (2*8)]        ! save g2
2742          stx       %g3, [%sp + CC64FSZ + STKB + TF_G + (3*8)]        ! (sneak g3 in here)
2743          rdpr      %tt, %o1                                          ! Find out what caused this trap
2744          stx       %g4, [%sp + CC64FSZ + STKB + TF_G + (4*8)]        ! sneak in g4
2745          rdpr      %tstate, %g1
2746          stx       %g5, [%sp + CC64FSZ + STKB + TF_G + (5*8)]        ! sneak in g5
2747          rdpr      %tpc, %o2                                         ! sync virt addr; must be read first
2748          stx       %g6, [%sp + CC64FSZ + STKB + TF_G + (6*8)]        ! sneak in g6
2749          rdpr      %tnpc, %g3
2750          stx       %g7, [%sp + CC64FSZ + STKB + TF_G + (7*8)]        ! sneak in g7
2751          rd        %y, %g5                                                     ! save y
2752
2753          /* Finish stackframe, call C trap handler */
2754          stx       %g1, [%sp + CC64FSZ + STKB + TF_TSTATE]           ! set tf.tf_psr, tf.tf_pc
2755          sth       %o1, [%sp + CC64FSZ + STKB + TF_TT]               ! debug
2756
2757          stx       %o2, [%sp + CC64FSZ + STKB + TF_PC]
2758          stx       %g3, [%sp + CC64FSZ + STKB + TF_NPC]              ! set tf.tf_npc
2759
2760          rdpr      %pil, %g4
2761          stb       %g4, [%sp + CC64FSZ + STKB + TF_PIL]
2762          stb       %g4, [%sp + CC64FSZ + STKB + TF_OLDPIL]
2763
2764          rdpr      %tl, %g7
2765          dec       %g7
2766          movrlz    %g7, %g0, %g7
2767          wrpr      %g0, %g7, %tl                 ! Revert to kernel mode
2768
2769          wr        %g0, ASI_PRIMARY_NOFAULT, %asi                    ! Restore default ASI
2770          flushw                                                      ! Get rid of any user windows so we don't deadlock
2771
2772          !! In the EMBEDANY memory model %g4 points to the start of the data segment.
2773          !! In our case we need to clear it before calling any C-code
2774          clr       %g4
2775
2776          /* Use trap type to see what handler to call */
2777          cmp       %o1, T_INST_ERROR
2778          be,pn     %xcc, text_error
2779           st       %g5, [%sp + CC64FSZ + STKB + TF_Y]                ! set tf.tf_y
2780
2781          wrpr      %g0, PSTATE_INTR, %pstate     ! reenable interrupts
2782          call      _C_LABEL(text_access_fault)   ! mem_access_fault(&tf, type, pc, sfsr)
2783           add      %sp, CC64FSZ + STKB, %o0      ! (argument: &tf)
2784text_recover:
2785          wrpr      %g0, PSTATE_KERN, %pstate     ! disable interrupts
2786          b         return_from_trap              ! go return
2787           ldx      [%sp + CC64FSZ + STKB + TF_TSTATE], %g1 ! Load this for return_from_trap
2788          NOTREACHED
2789
2790text_error:
2791          wrpr      %g0, PSTATE_INTR, %pstate     ! reenable interrupts
2792          call      _C_LABEL(text_access_error)   ! mem_access_fault(&tfm type, sfva [pc], sfsr,
2793                                                            !                   afva, afsr);
2794           add      %sp, CC64FSZ + STKB, %o0      ! (argument: &tf)
2795          ba        text_recover
2796           nop
2797          NOTREACHED
2798
2799#ifdef SUN4V
2800
2801/*
2802 * Traps for sun4v.
2803 */
2804
2805sun4v_dtsb_miss:
2806          GET_MMFSA %g1                                     ! MMU Fault status area
2807          add       %g1, 0x48, %g3
2808          LDPTRA    [%g3] ASI_PHYS_CACHED, %g3    ! Data fault address
2809          add       %g1, 0x50, %g6
2810          LDPTRA    [%g6] ASI_PHYS_CACHED, %g6    ! Data fault context
2811
2812          GET_CTXBUSY %g4
2813          sllx      %g6, 3, %g6                             ! Make it into an offset into ctxbusy
2814          LDPTR     [%g4 + %g6], %g4              ! Load up our page table.
2815
2816          srax      %g3, HOLESHIFT, %g5           ! Check for valid address
2817          brz,pt    %g5, 0f                                 ! Should be zero or -1
2818           inc      %g5                                     ! Make -1 -> 0
2819          brnz,pn   %g5, sun4v_datatrap           ! Error! In hole!
28200:
2821          srlx      %g3, STSHIFT, %g6
2822          and       %g6, STMASK, %g6              ! Index into pm_segs
2823          sll       %g6, 3, %g6
2824          add       %g4, %g6, %g4
2825          LDPTRA    [%g4] ASI_PHYS_CACHED, %g4    ! Load page directory pointer
2826          srlx      %g3, PDSHIFT, %g6
2827          and       %g6, PDMASK, %g6
2828          sll       %g6, 3, %g6
2829          brz,pn    %g4, sun4v_datatrap           ! NULL entry? check somewhere else
2830           add      %g4, %g6, %g4
2831          LDPTRA    [%g4] ASI_PHYS_CACHED, %g4    ! Load page table pointer
2832
2833          srlx      %g3, PTSHIFT, %g6             ! Convert to ptab offset
2834          and       %g6, PTMASK, %g6
2835          sll       %g6, 3, %g6
2836          brz,pn    %g4, sun4v_datatrap           ! NULL entry? check somewhere else
2837           add      %g4, %g6, %g6
28381:
2839          LDPTRA    [%g6] ASI_PHYS_CACHED, %g4    ! Fetch TTE
2840          brgez,pn %g4, sun4v_datatrap            ! Entry invalid?  Punt
2841           or       %g4, SUN4V_TLB_ACCESS, %g7    ! Update the access bit
2842
2843          btst      SUN4V_TLB_ACCESS, %g4                   ! Need to update access bit?
2844          bne,pt    %xcc, 2f
2845           nop
2846          casxa     [%g6] ASI_PHYS_CACHED, %g4, %g7         ! and write it out
2847          cmp       %g4, %g7
2848          bne,pn    %xcc, 1b
2849           or       %g4, SUN4V_TLB_ACCESS, %g4    ! Update the access bit
28502:
2851          GET_TSB_DMMU %g2
2852
2853          /* Construct TSB tag word. */
2854          add       %g1, 0x50, %g6
2855          LDPTRA    [%g6] ASI_PHYS_CACHED, %g6    ! Data fault context
2856          mov       %g3, %g1                      ! Data fault address
2857          srlx      %g1, 22, %g1                            ! 63..22 of virt addr
2858          sllx      %g6, 48, %g6                            ! context_id in 63..48
2859          or        %g1, %g6, %g1                           ! construct TTE tag
2860          srlx      %g3, PTSHIFT, %g3
2861          sethi     %hi(_C_LABEL(tsbsize)), %g5
2862          mov       512, %g6
2863          ld        [%g5 + %lo(_C_LABEL(tsbsize))], %g5
2864          sllx      %g6, %g5, %g5                           ! %g5 = 512 << tsbsize = TSBENTS
2865          sub       %g5, 1, %g5                             ! TSBENTS -> offset
2866          and       %g3, %g5, %g3                           ! mask out TTE index
2867          sllx      %g3, 4, %g3                             ! TTE size is 16 bytes
2868          add       %g2, %g3, %g2                           ! location of TTE in ci_tsb_dmmu
2869
2870          membar    #StoreStore
2871
2872          STPTR     %g4, [%g2 + 8]                          ! store TTE data
2873          STPTR     %g1, [%g2]                              ! store TTE tag
2874
2875          retry
2876          NOTREACHED
2877
2878sun4v_tl1_dtsb_miss:
2879          GET_MMFSA %g1                                     ! MMU Fault status area
2880          add       %g1, 0x48, %g3
2881          LDPTRA    [%g3] ASI_PHYS_CACHED, %g3    ! Data fault address
2882          add       %g1, 0x50, %g6
2883          LDPTRA    [%g6] ASI_PHYS_CACHED, %g6    ! Data fault context
2884
2885          GET_CTXBUSY %g4
2886          sllx      %g6, 3, %g6                             ! Make it into an offset into ctxbusy
2887          LDPTR     [%g4 + %g6], %g4              ! Load up our page table.
2888
2889          srax      %g3, HOLESHIFT, %g5           ! Check for valid address
2890          brz,pt    %g5, 0f                                 ! Should be zero or -1
2891           inc      %g5                                     ! Make -1 -> 0
2892          brnz,pn   %g5, sun4v_tl1_ptbl_miss      ! Error! In hole!
28930:
2894          srlx      %g3, STSHIFT, %g6
2895          and       %g6, STMASK, %g6              ! Index into pm_segs
2896          sll       %g6, 3, %g6
2897          add       %g4, %g6, %g4
2898          LDPTRA    [%g4] ASI_PHYS_CACHED, %g4    ! Load page directory pointer
2899          srlx      %g3, PDSHIFT, %g6
2900          and       %g6, PDMASK, %g6
2901          sll       %g6, 3, %g6
2902          brz,pn    %g4, sun4v_tl1_ptbl_miss      ! NULL entry? check somewhere else
2903           add      %g4, %g6, %g4
2904          LDPTRA    [%g4] ASI_PHYS_CACHED, %g4    ! Load page table pointer
2905
2906          srlx      %g3, PTSHIFT, %g6             ! Convert to ptab offset
2907          and       %g6, PTMASK, %g6
2908          sll       %g6, 3, %g6
2909          brz,pn    %g4, sun4v_tl1_ptbl_miss      ! NULL entry? check somewhere else
2910           add      %g4, %g6, %g6
29111:
2912          LDPTRA    [%g6] ASI_PHYS_CACHED, %g4    ! Fetch TTE
2913          brgez,pn %g4, sun4v_tl1_ptbl_miss       ! Entry invalid?  Punt
2914           or       %g4, SUN4V_TLB_ACCESS, %g7    ! Update the access bit
2915
2916          btst      SUN4V_TLB_ACCESS, %g4                   ! Need to update access bit?
2917          bne,pt    %xcc, 2f
2918           nop
2919          casxa     [%g6] ASI_PHYS_CACHED, %g4, %g7         ! and write it out
2920          cmp       %g4, %g7
2921          bne,pn    %xcc, 1b
2922           or       %g4, SUN4V_TLB_ACCESS, %g4    ! Update the access bit
29232:
2924          GET_TSB_DMMU %g2
2925
2926          /* Construct TSB tag word. */
2927          add       %g1, 0x50, %g6
2928          LDPTRA    [%g6] ASI_PHYS_CACHED, %g6    ! Data fault context
2929          mov       %g3, %g1                      ! Data fault address
2930          srlx      %g1, 22, %g1                            ! 63..22 of virt addr
2931          sllx      %g6, 48, %g6                            ! context_id in 63..48
2932          or        %g1, %g6, %g1                           ! construct TTE tag
2933          srlx      %g3, PTSHIFT, %g3
2934          sethi     %hi(_C_LABEL(tsbsize)), %g5
2935          mov       512, %g6
2936          ld        [%g5 + %lo(_C_LABEL(tsbsize))], %g5
2937          sllx      %g6, %g5, %g5                           ! %g5 = 512 << tsbsize = TSBENTS
2938          sub       %g5, 1, %g5                             ! TSBENTS -> offset
2939          and       %g3, %g5, %g3                           ! mask out TTE index
2940          sllx      %g3, 4, %g3                             ! TTE size is 16 bytes
2941          add       %g2, %g3, %g2                           ! location of TTE in ci_tsb_dmmu
2942
2943          membar    #StoreStore
2944
2945          STPTR     %g4, [%g2 + 8]                          ! store TTE data
2946          STPTR     %g1, [%g2]                              ! store TTE tag
2947
2948          retry
2949          NOTREACHED
2950
2951sun4v_datatrap:
2952          GET_MMFSA %g3                                     ! MMU Fault status area
2953          add       %g3, 0x48, %g1
2954          LDPTRA    [%g1] ASI_PHYS_CACHED, %g1    ! Data fault address
2955          add       %g3, 0x50, %g2
2956          LDPTRA    [%g2] ASI_PHYS_CACHED, %g2    ! Data fault context
2957
2958          TRAP_SETUP(-CC64FSZ-TF_SIZE)
2959          or        %g1, %g2, %o3
2960          mov       %g1, %o4
2961
2962          rdpr      %tt, %g4
2963          rdpr      %tstate, %g1
2964          rdpr      %tpc, %g2
2965          rdpr      %tnpc, %g3
2966
2967          stx       %g1, [%sp + CC64FSZ + BIAS + TF_TSTATE]
2968          mov       %g4, %o1            ! (type)
2969          stx       %g2, [%sp + CC64FSZ + BIAS + TF_PC]
2970          rd        %y, %g5
2971          stx       %g3, [%sp + CC64FSZ + BIAS + TF_NPC]
2972          st        %g5, [%sp + CC64FSZ + BIAS + TF_Y]
2973          mov       %g2, %o2            ! (pc)
2974          sth       %o1, [%sp + CC64FSZ + BIAS + TF_TT]! debug
2975
2976          cmp       %o1, T_FDMMU_PROT
2977          bne,pn    %icc, 1f
2978           mov      SFSR_FV, %o5
2979          or        %o5, SFSR_W, %o5
2980
29811:
2982          NORMAL_GLOBALS_SUN4V
2983
2984          stx       %g1, [%sp + CC64FSZ + BIAS + TF_G + (1*8)]
2985          stx       %g2, [%sp + CC64FSZ + BIAS + TF_G + (2*8)]
2986          add       %sp, CC64FSZ + BIAS, %o0                ! (&tf)
2987          stx       %g3, [%sp + CC64FSZ + BIAS + TF_G + (3*8)]
2988          stx       %g4, [%sp + CC64FSZ + BIAS + TF_G + (4*8)]
2989          stx       %g5, [%sp + CC64FSZ + BIAS + TF_G + (5*8)]
2990          rdpr      %pil, %g5
2991          stx       %g6, [%sp + CC64FSZ + BIAS + TF_G + (6*8)]
2992          stx       %g7, [%sp + CC64FSZ + BIAS + TF_G + (7*8)]
2993          stb       %g5, [%sp + CC64FSZ + BIAS + TF_PIL]
2994          stb       %g5, [%sp + CC64FSZ + BIAS + TF_OLDPIL]
2995
2996          /*
2997           * Phew, ready to enable traps and call C code.
2998           */
2999          wrpr      %g0, 0, %tl
3000
3001          wr        %g0, ASI_PRIMARY_NOFAULT, %asi          ! Restore default ASI
3002          wrpr      %g0, PSTATE_INTR, %pstate     ! traps on again
3003          call      _C_LABEL(data_access_fault)   ! data_acces_fault(tf, type, ...)
3004           nop
3005
3006          ba,a,pt   %icc, return_from_trap
3007           nop
3008          NOTREACHED
3009
3010sun4v_tl0_dtsb_prot:
3011          GET_MMFSA %g1                                     ! MMU Fault status area
3012          add       %g1, 0x48, %g3
3013          LDPTRA    [%g3] ASI_PHYS_CACHED, %g3    ! Data fault address
3014          add       %g1, 0x50, %g6
3015          LDPTRA    [%g6] ASI_PHYS_CACHED, %g6    ! Data fault context
3016
3017          GET_CTXBUSY %g4
3018          sllx      %g6, 3, %g6                             ! Make it into an offset into ctxbusy
3019          LDPTR     [%g4 + %g6], %g4              ! Load up our page table.
3020
3021          srax      %g3, HOLESHIFT, %g5           ! Check for valid address
3022          brz,pt    %g5, 0f                                 ! Should be zero or -1
3023           inc      %g5                                     ! Make -1 -> 0
3024          brnz,pn   %g5, sun4v_datatrap           ! Error! In hole!
30250:
3026          srlx      %g3, STSHIFT, %g6
3027          and       %g6, STMASK, %g6              ! Index into pm_segs
3028          sll       %g6, 3, %g6
3029          add       %g4, %g6, %g4
3030          LDPTRA    [%g4] ASI_PHYS_CACHED, %g4    ! Load page directory pointer
3031
3032          srlx      %g3, PDSHIFT, %g6
3033          and       %g6, PDMASK, %g6
3034          sll       %g6, 3, %g6
3035          brz,pn    %g4, sun4v_datatrap           ! NULL entry? check somewhere else
3036           add      %g4, %g6, %g4
3037          LDPTRA    [%g4] ASI_PHYS_CACHED, %g4    ! Load page table pointer
3038
3039          srlx      %g3, PTSHIFT, %g6             ! Convert to ptab offset
3040          and       %g6, PTMASK, %g6
3041          sll       %g6, 3, %g6
3042          brz,pn    %g4, sun4v_datatrap           ! NULL entry? check somewhere else
3043           add      %g4, %g6, %g6
30441:
3045          LDPTRA    [%g6] ASI_PHYS_CACHED, %g4    ! Fetch TTE
3046          brgez,pn %g4, sun4v_datatrap            ! Entry invalid?  Punt
3047           or       %g4, SUN4V_TLB_MODIFY|SUN4V_TLB_ACCESS|SUN4V_TLB_W, %g7 ! Update the modified bit
3048
3049#         btst      SUN4V_TLB_REAL_W|SUN4V_TLB_W, %g4       ! Is it a ref fault?
3050          mov       1, %g2
3051          sllx      %g2, 61, %g2                            ! %g2 is now SUN4V_TLB_REAL_W
3052          or        %g2, SUN4V_TLB_W, %g2
3053          btst      %g2, %g4
3054          bz,pn     %xcc, sun4v_datatrap                              ! No -- really fault
3055           nop
3056          casxa     [%g6] ASI_PHYS_CACHED, %g4, %g7                   !  and write it out
3057          cmp       %g4, %g7
3058          bne,pn    %xcc, 1b
3059           or       %g4, SUN4V_TLB_MODIFY|SUN4V_TLB_ACCESS|SUN4V_TLB_W, %g4 ! Update the modified bit
30602:
3061          GET_TSB_DMMU %g2
3062
3063          mov       %g1, %g7                      ! save MMFSA
3064
3065          /* Construct TSB tag word. */
3066          add       %g1, 0x50, %g6
3067          LDPTRA    [%g6] ASI_PHYS_CACHED, %g6    ! Data fault context
3068          mov       %g3, %g1                      ! Data fault address
3069          srlx      %g1, 22, %g1                            ! 63..22 of virt addr
3070          sllx      %g6, 48, %g6                            ! context_id in 63..48
3071          or        %g1, %g6, %g1                           ! construct TTE tag
3072
3073          srlx      %g3, PTSHIFT, %g3
3074          sethi     %hi(_C_LABEL(tsbsize)), %g5
3075          mov       512, %g6
3076          ld        [%g5 + %lo(_C_LABEL(tsbsize))], %g5
3077          sllx      %g6, %g5, %g5                           ! %g5 = 512 << tsbsize = TSBENTS
3078          sub       %g5, 1, %g5                             ! TSBENTS -> offset
3079          and       %g3, %g5, %g3                           ! mask out TTE index
3080          sllx      %g3, 4, %g3                             ! TTE size is 16 bytes
3081          add       %g2, %g3, %g2                           ! location of TTE in ci_tsb_dmmu
3082
3083          membar    #StoreStore
3084
3085          STPTR     %g4, [%g2 + 8]                ! store TTE data
3086          STPTR     %g1, [%g2]                    ! store TTE tag
3087
3088          mov       %o0, %g1
3089          mov       %o1, %g2
3090          mov       %o2, %g3
3091
3092          add       %g7, 0x48, %o0
3093          ldxa      [%o0] ASI_PHYS_CACHED, %o0    ! Data fault address
3094          add       %g7, 0x50, %o1
3095          ldxa      [%o1] ASI_PHYS_CACHED, %o1    ! Data fault context
3096          mov       MAP_DTLB, %o2
3097          ta        ST_MMU_UNMAP_ADDR
3098
3099          mov       %g1, %o0
3100          mov       %g2, %o1
3101          mov       %g3, %o2
3102
3103          retry
3104          NOTREACHED
3105
3106sun4v_tl0_itsb_miss:
3107          GET_MMFSA %g1                                     ! MMU Fault status area
3108          add       %g1, 0x8, %g3
3109          LDPTRA    [%g3] ASI_PHYS_CACHED, %g3    ! Instruction fault address
3110          add       %g1, 0x10, %g6
3111          LDPTRA    [%g6] ASI_PHYS_CACHED, %g6    ! Data fault context
3112
3113          GET_CTXBUSY %g4
3114          sllx      %g6, 3, %g6                             ! Make it into an offset into ctxbusy
3115          LDPTR     [%g4 + %g6], %g4              ! Load up our page table.
3116
3117          srax      %g3, HOLESHIFT, %g5           ! Check for valid address
3118          brz,pt    %g5, 0f                                 ! Should be zero or -1
3119           inc      %g5                                     ! Make -1 -> 0
3120          brnz,pn   %g5, sun4v_texttrap           ! Error! In hole!
31210:
3122          srlx      %g3, STSHIFT, %g6
3123          and       %g6, STMASK, %g6              ! Index into pm_segs
3124          sll       %g6, 3, %g6
3125          add       %g4, %g6, %g4
3126          LDPTRA    [%g4] ASI_PHYS_CACHED, %g4    ! Load page directory pointer
3127
3128          srlx      %g3, PDSHIFT, %g6
3129          and       %g6, PDMASK, %g6
3130          sll       %g6, 3, %g6
3131          brz,pn    %g4, sun4v_texttrap           ! NULL entry? check somewhere else
3132           add      %g4, %g6, %g4
3133          LDPTRA    [%g4] ASI_PHYS_CACHED, %g4    ! Load page table pointer
3134
3135          srlx      %g3, PTSHIFT, %g6             ! Convert to ptab offset
3136          and       %g6, PTMASK, %g6
3137          sll       %g6, 3, %g6
3138          brz,pn    %g4, sun4v_texttrap           ! NULL entry? check somewhere else
3139           add      %g4, %g6, %g6
31401:
3141          LDPTRA    [%g6] ASI_PHYS_CACHED, %g4    ! Fetch TTE
3142          brgez,pn %g4, sun4v_texttrap            ! Entry invalid?  Punt
3143           or       %g4, SUN4V_TLB_ACCESS, %g7    ! Update the access bit
3144
3145          btst      SUN4V_TLB_EXEC, %g4           ! Need to update exec bit?
3146          bz,pn     %xcc, sun4v_texttrap
3147           nop
3148          btst      SUN4V_TLB_ACCESS, %g4                   ! Need to update access bit?
3149          bne,pt    %xcc, 2f
3150           nop
3151          casxa     [%g6] ASI_PHYS_CACHED, %g4, %g7         ! and write it out
3152          cmp       %g4, %g7
3153          bne,pn    %xcc, 1b
3154           or       %g4, SUN4V_TLB_ACCESS, %g4    ! Update the modified bit
31552:
3156          GET_TSB_DMMU %g2
3157
3158          mov       %g1, %g7
3159          /* Construct TSB tag word. */
3160          add       %g1, 0x10, %g6
3161          LDPTRA    [%g6] ASI_PHYS_CACHED, %g6    ! Instruction fault context
3162          mov       %g3, %g1                      ! Instruction fault address
3163          srlx      %g1, 22, %g1                            ! 63..22 of virt addr
3164          sllx      %g6, 48, %g6                            ! context_id in 63..48
3165          or        %g1, %g6, %g1                           ! construct TTE tag
3166
3167          srlx      %g3, PTSHIFT, %g3
3168          sethi     %hi(_C_LABEL(tsbsize)), %g5
3169          mov       512, %g6
3170          ld        [%g5 + %lo(_C_LABEL(tsbsize))], %g5
3171          sllx      %g6, %g5, %g5                           ! %g5 = 512 << tsbsize = TSBENTS
3172          sub       %g5, 1, %g5                             ! TSBENTS -> offset
3173          and       %g3, %g5, %g3                           ! mask out TTE index
3174          sllx      %g3, 4, %g3                             ! TTE size is 16 bytes
3175          add       %g2, %g3, %g2                           ! location of TTE in ci_tsb_dmmu (FIXME ci_tsb_immu?)
3176
3177          membar    #StoreStore
3178          STPTR     %g4, [%g2 + 8]                          ! store TTE data
3179          stx       %g1, [%g2]                              ! store TTE tag
3180
3181          retry
3182          NOTREACHED
3183
3184sun4v_texttrap:
3185          GET_MMFSA %g3                                     ! MMU Fault status area
3186          add       %g3, 0x08, %g1
3187          LDPTRA    [%g1] ASI_PHYS_CACHED, %g1    ! Instruction fault address
3188          add       %g3, 0x10, %g2
3189          LDPTRA    [%g2] ASI_PHYS_CACHED, %g2    ! Instruction fault context
3190
3191          TRAP_SETUP(-CC64FSZ-TF_SIZE)
3192
3193          or        %g1, %g2, %o2
3194          clr       %o3
3195
3196          rdpr      %tt, %g4
3197          rdpr      %tstate, %g1
3198          rdpr      %tpc, %g2
3199          rdpr      %tnpc, %g3
3200
3201          stx       %g1, [%sp + CC64FSZ + BIAS + TF_TSTATE]
3202          mov       %g4, %o1            ! (type)
3203          stx       %g2, [%sp + CC64FSZ + BIAS + TF_PC]
3204          rd        %y, %g5
3205          stx       %g3, [%sp + CC64FSZ + BIAS + TF_NPC]
3206          st        %g5, [%sp + CC64FSZ + BIAS + TF_Y]
3207          sth       %o1, [%sp + CC64FSZ + BIAS + TF_TT]! debug
3208
3209          ! Get back to normal globals
3210          wrpr      %g0, PSTATE_KERN, %pstate
3211          NORMAL_GLOBALS_SUN4V
3212
3213          stx       %g1, [%sp + CC64FSZ + BIAS + TF_G + (1*8)]
3214          stx       %g2, [%sp + CC64FSZ + BIAS + TF_G + (2*8)]
3215          add       %sp, CC64FSZ + BIAS, %o0                ! (&tf)
3216          stx       %g3, [%sp + CC64FSZ + BIAS + TF_G + (3*8)]
3217          stx       %g4, [%sp + CC64FSZ + BIAS + TF_G + (4*8)]
3218          stx       %g5, [%sp + CC64FSZ + BIAS + TF_G + (5*8)]
3219          rdpr      %pil, %g5
3220          stx       %g6, [%sp + CC64FSZ + BIAS + TF_G + (6*8)]
3221          stx       %g7, [%sp + CC64FSZ + BIAS + TF_G + (7*8)]
3222          stb       %g5, [%sp + CC64FSZ + BIAS + TF_PIL]
3223          stb       %g5, [%sp + CC64FSZ + BIAS + TF_OLDPIL]
3224
3225          /*
3226           * Phew, ready to enable traps and call C code.
3227           */
3228          wrpr      %g0, 0, %tl
3229
3230          wr        %g0, ASI_PRIMARY_NOFAULT, %asi          ! Restore default ASI
3231          wrpr      %g0, PSTATE_INTR, %pstate     ! traps on again
3232          call      _C_LABEL(text_access_fault)   ! text_access_fault(tf, type, ...)
3233           nop
3234
3235          ba,a,pt   %icc, return_from_trap
3236           nop
3237          NOTREACHED
3238
3239sun4v_tl1_dtsb_prot:
3240          GET_MMFSA %g1                                     ! MMU Fault status area
3241          add       %g1, 0x48, %g3
3242          LDPTRA    [%g3] ASI_PHYS_CACHED, %g3    ! Data fault address
3243          add       %g1, 0x50, %g6
3244          LDPTRA    [%g6] ASI_PHYS_CACHED, %g6    ! Data fault context
3245
3246          GET_CTXBUSY %g4
3247          sllx      %g6, 3, %g6                             ! Make it into an offset into ctxbusy
3248          LDPTR     [%g4 + %g6], %g4              ! Load up our page table.
3249
3250          srax      %g3, HOLESHIFT, %g5           ! Check for valid address
3251          brz,pt    %g5, 0f                                 ! Should be zero or -1
3252           inc      %g5                                     ! Make -1 -> 0
3253          brnz,pn   %g5, sun4v_tl1_ptbl_miss      ! Error! In hole!
32540:
3255          srlx      %g3, STSHIFT, %g6
3256          and       %g6, STMASK, %g6              ! Index into pm_segs
3257          sll       %g6, 3, %g6
3258          add       %g4, %g6, %g4
3259          LDPTRA    [%g4] ASI_PHYS_CACHED, %g4    ! Load page directory pointer
3260
3261          srlx      %g3, PDSHIFT, %g6
3262          and       %g6, PDMASK, %g6
3263          sll       %g6, 3, %g6
3264          brz,pn    %g4, sun4v_tl1_ptbl_miss      ! NULL entry? check somewhere else
3265           add      %g4, %g6, %g4
3266          LDPTRA    [%g4] ASI_PHYS_CACHED, %g4    ! Load page table pointer
3267
3268          srlx      %g3, PTSHIFT, %g6             ! Convert to ptab offset
3269          and       %g6, PTMASK, %g6
3270          sll       %g6, 3, %g6
3271          brz,pn    %g4, sun4v_tl1_ptbl_miss      ! NULL entry? check somewhere else
3272           add      %g4, %g6, %g6
32731:
3274          LDPTRA    [%g6] ASI_PHYS_CACHED, %g4    ! Fetch TTE
3275          brgez,pn %g4, sun4v_tl1_ptbl_miss       ! Entry invalid?  Punt
3276           or       %g4, SUN4V_TLB_MODIFY|SUN4V_TLB_ACCESS|SUN4V_TLB_W, %g7 ! Update the modified bit
3277
3278#         btst      SUN4V_TLB_REAL_W|SUN4V_TLB_W, %g4       ! Is it a ref fault?
3279          mov       1, %g2
3280          sllx      %g2, 61, %g2                            ! %g2 is now SUN4V_TLB_REAL_W
3281          or        %g2, SUN4V_TLB_W, %g2
3282          btst      %g2, %g4
3283          bz,pn     %xcc, sun4v_tl1_ptbl_miss               ! No -- really fault
3284           nop
3285          casxa     [%g6] ASI_PHYS_CACHED, %g4, %g7                   !  and write it out
3286          cmp       %g4, %g7
3287          bne,pn    %xcc, 1b
3288           or       %g4, SUN4V_TLB_MODIFY|SUN4V_TLB_ACCESS|SUN4V_TLB_W, %g4 ! Update the modified bit
32892:
3290          GET_TSB_DMMU %g2
3291
3292          mov       %g1, %g7                      ! save MMFSA
3293
3294          /* Construct TSB tag word. */
3295          add       %g1, 0x50, %g6
3296          LDPTRA    [%g6] ASI_PHYS_CACHED, %g6    ! Data fault context
3297          mov       %g3, %g1                      ! Data fault address
3298          srlx      %g1, 22, %g1                            ! 63..22 of virt addr
3299          sllx      %g6, 48, %g6                            ! context_id in 63..48
3300          or        %g1, %g6, %g1                           ! construct TTE tag
3301
3302          srlx      %g3, PTSHIFT, %g3
3303          sethi     %hi(_C_LABEL(tsbsize)), %g5
3304          mov       512, %g6
3305          ld        [%g5 + %lo(_C_LABEL(tsbsize))], %g5
3306          sllx      %g6, %g5, %g5                           ! %g5 = 512 << tsbsize = TSBENTS
3307          sub       %g5, 1, %g5                             ! TSBENTS -> offset
3308          and       %g3, %g5, %g3                           ! mask out TTE index
3309          sllx      %g3, 4, %g3                             ! TTE size is 16 bytes
3310          add       %g2, %g3, %g2                           ! location of TTE in ci_tsb_dmmu
3311
3312          membar    #StoreStore
3313
3314          STPTR     %g4, [%g2 + 8]                ! store TTE data
3315          STPTR     %g1, [%g2]                    ! store TTE tag
3316
3317          mov       %o0, %g1
3318          mov       %o1, %g2
3319          mov       %o2, %g3
3320
3321          add       %g7, 0x48, %o0
3322          ldxa      [%o0] ASI_PHYS_CACHED, %o0    ! Data fault address
3323          add       %g7, 0x50, %o1
3324          ldxa      [%o1] ASI_PHYS_CACHED, %o1    ! Data fault context
3325          mov       MAP_DTLB, %o2
3326          ta        ST_MMU_UNMAP_ADDR
3327
3328          mov       %g1, %o0
3329          mov       %g2, %o1
3330          mov       %g3, %o2
3331
3332          retry
3333          NOTREACHED
3334
3335sun4v_tl1_ptbl_miss:
3336          rdpr      %tpc, %g1
3337
3338          set       rft_user_fault_start, %g2
3339          cmp       %g1, %g2
3340          blu,pt    %xcc, 1f
3341           set      rft_user_fault_end, %g2
3342          cmp       %g1, %g2
3343          bgeu,pt   %xcc, 1f
3344           nop
3345
3346          /* We had a miss inside rtf_user_fault_start/rtf_user_fault_end block (FILL)
3347
3348          /* Fixup %cwp. */
3349          rdpr      %cwp, %g1
3350          inc       %g1
3351          wrpr      %g1, %cwp
3352
3353          rdpr      %tt, %g1
3354          wrpr      1, %tl
3355          wrpr      %g1, %tt
3356          rdpr      %cwp, %g1
3357          set       TSTATE_KERN, %g2
3358          wrpr      %g1, %g2, %tstate
3359          set       return_from_trap, %g1
3360          wrpr      %g1, %tpc
3361          add       %g1, 4, %g1
3362          wrpr      %g1, %tnpc
3363          wrpr      %g0, 1, %gl
3364
3365          ba,pt %xcc, sun4v_datatrap
3366           wrpr     WSTATE_KERN, %wstate
3367
33681:
3369          rdpr      %tstate, %g3
3370          rdpr      %tt, %g4
3371
3372          rdpr      %tl, %g1
3373          dec       %g1
3374          wrpr      %g1, %tl
3375          rdpr      %tt, %g2
3376          inc       %g1
3377          wrpr      %g1, %tl
3378
3379          wrpr      %g0, %g3, %tstate
3380          wrpr      %g0, %g4, %tt
3381
3382          andn      %g2, 0x00f, %g3
3383          cmp       %g3, 0x080
3384          be,pn     %icc, flush_normals
3385           nop
3386          cmp       %g3, 0x0a0
3387          be,pn     %icc, flush_others
3388           nop
3389          cmp       %g3, 0x0c0
3390          be,pn     %icc, ufill_trap
3391           nop
3392
3393          Debugger()
3394          NOTREACHED
3395
3396flush_others:
3397          set       pcbspill_others, %g1
3398          wrpr      %g1, %tnpc
3399          done
3400          NOTREACHED
3401
3402flush_normals:
3403ufill_trap:
3404
3405          /*
3406           * Rearrange our trap state such that it appears as if we got
3407           * this trap directly from user mode.  Then process it at TL = 1.
3408           * We'll take the spill/fill trap again once we return to user mode.
3409           */
3410          rdpr      %tt, %g1
3411          rdpr      %tstate, %g3
3412          wrpr      %g0, 1, %tl
3413          wrpr      %g0, %g1, %tt
3414          rdpr      %tstate, %g2
3415          wrpr      %g0, 2, %tl
3416          and       %g2, TSTATE_CWP, %g2
3417          andn      %g3, TSTATE_CWP, %g3
3418          wrpr      %g2, %g3, %tstate
3419          set       sun4v_datatrap, %g4
3420          wrpr      %g0, %g4, %tnpc
3421          done
3422
3423/*
3424 * Spill user windows into the PCB.
3425 */
3426pcbspill_normals:
3427          ba,pt     %xcc, pcbspill
3428           wrpr     0x80, %tt
3429
3430pcbspill_others:
3431          wrpr      0xa0, %tt
3432
3433pcbspill:
3434          set       CPUINFO_VA, %g6
3435          ldx       [%g6 + CI_CPCB], %g6
3436
3437          GET_CTXBUSY %g1
3438
3439          ldx       [%g1], %g1                                        ! kernel pmap is ctx 0
3440
3441          srlx      %g6, STSHIFT, %g7
3442          and       %g7, STMASK, %g7
3443          sll       %g7, 3, %g7                                       ! byte offset into ctxbusy
3444          add       %g7, %g1, %g1
3445          ldxa      [%g1] ASI_PHYS_CACHED, %g1              ! Load pointer to directory
3446
3447          srlx      %g6, PDSHIFT, %g7                       ! Do page directory
3448          and       %g7, PDMASK, %g7
3449          sll       %g7, 3, %g7
3450          brz,pn    %g1, pcbspill_fail
3451           add      %g7, %g1, %g1
3452          ldxa      [%g1] ASI_PHYS_CACHED, %g1
3453          srlx      %g6, PTSHIFT, %g7                       ! Convert to ptab offset
3454          and       %g7, PTMASK, %g7
3455          brz       %g1, pcbspill_fail
3456           sll      %g7, 3, %g7
3457          add       %g1, %g7, %g7
3458          ldxa      [%g7] ASI_PHYS_CACHED, %g7              ! This one is not
3459          brgez     %g7, pcbspill_fail
3460           srlx     %g7, PGSHIFT, %g7                       ! Isolate PA part
3461          sll       %g6, 32-PGSHIFT, %g6                              ! And offset
3462          sllx      %g7, PGSHIFT+8, %g7                     ! There are 8 bits to the left of the PA in the TTE
3463          srl       %g6, 32-PGSHIFT, %g6
3464          srax      %g7, 8, %g7
3465          or        %g7, %g6, %g6                                     ! Then combine them to form PA
3466
3467          wr        %g0, ASI_PHYS_CACHED, %asi              ! Use ASI_PHYS_CACHED to prevent possible page faults
3468
3469          lduba     [%g6 + PCB_NSAVED] %asi, %g7            ! Fetch current nsaved from the pcb
3470          sllx      %g7, 7, %g5                                       ! 8+8 registers each 8 bytes = 128 bytes (2^7)
3471          add       %g6, %g5, %g5                                     ! Offset into pcb_rw
3472          SPILL     stxa, %g5 + PCB_RW, 8, %asi             ! Store the locals and ins
3473          saved
3474
3475          sllx      %g7, 3, %g5
3476          add       %g6, %g5, %g5
3477
3478          inc       %g7
3479          stba      %g7, [%g6 + PCB_NSAVED] %asi
3480
3481          retry
3482          NOTREACHED
3483
3484pcbspill_fail:
3485          Debugger()
3486          NOTREACHED
3487
3488
3489pcbspill_other:
3490
3491          set       CPUINFO_VA, %g6
3492          ldx       [%g6 + CI_CPCB], %g6
3493
3494          GET_CTXBUSY %g1
3495
3496          ldx       [%g1], %g1                                        ! kernel pmap is ctx 0
3497
3498          srlx      %g6, STSHIFT, %g7
3499          and       %g7, STMASK, %g7
3500          sll       %g7, 3, %g7                                       ! byte offset into ctxbusy
3501          add       %g7, %g1, %g1
3502          ldxa      [%g1] ASI_PHYS_CACHED, %g1              ! Load pointer to directory
3503
3504          srlx      %g6, PDSHIFT, %g7                       ! Do page directory
3505          and       %g7, PDMASK, %g7
3506          sll       %g7, 3, %g7
3507          brz,pn    %g1, pcbspill_other_fail
3508           add      %g7, %g1, %g1
3509          ldxa      [%g1] ASI_PHYS_CACHED, %g1
3510          srlx      %g6, PTSHIFT, %g7                       ! Convert to ptab offset
3511          and       %g7, PTMASK, %g7
3512          brz       %g1, pcbspill_other_fail
3513           sll      %g7, 3, %g7
3514          add       %g1, %g7, %g7
3515          ldxa      [%g7] ASI_PHYS_CACHED, %g7              ! This one is not
3516          brgez     %g7, pcbspill_other_fail
3517           srlx     %g7, PGSHIFT, %g7                       ! Isolate PA part
3518          sll       %g6, 32-PGSHIFT, %g6                              ! And offset
3519          sllx      %g7, PGSHIFT+8, %g7                     ! There are 8 bits to the left of the PA in the TTE
3520          srl       %g6, 32-PGSHIFT, %g6
3521          srax      %g7, 8, %g7
3522          or        %g7, %g6, %g6                                     ! Then combine them to form PA
3523
3524          wr        %g0, ASI_PHYS_CACHED, %asi              ! Use ASI_PHYS_CACHED to prevent possible page faults
3525
3526          lduba     [%g6 + PCB_NSAVED] %asi, %g7            ! Fetch current nsaved from the pcb
3527          sllx      %g7, 7, %g5                                       ! 8+8 registers each 8 bytes = 128 bytes (2^7)
3528          add       %g6, %g5, %g5                                     ! Offset into pcb_rw
35291:
3530          SPILL     stxa, %g5 + PCB_RW, 8, %asi             ! Store the locals and ins
3531
3532          add       %g5, 16*8, %g5                                    ! Next location for saved register windows
3533
3534          stxa      %o6, [%g5 + PCB_RW + (14*8)] %asi       ! Save %sp so we can write these all out
3535
3536          saved                                                       ! Increments %cansave and decrements %otherwin
3537
3538          rdpr      %cwp, %g1                               ! shift register window forward
3539          inc       %g1
3540          wrpr      %g1, %cwp
3541
3542
3543          inc       %g7                                               ! increment number of saved register windows
3544
3545          rdpr      %otherwin, %g1                                    ! Check to see if done spill'ing otherwin
3546          brnz,pt   %g1, 1b
3547           nop
3548
3549          stba      %g7, [%g6 + PCB_NSAVED] %asi
3550
3551          retry
3552          NOTREACHED
3553
3554pcbspill_other_fail:
3555          Debugger()
3556          NOTREACHED
3557
3558
3559spill_normal_to_user_stack:
3560          mov       %sp, %g6                                                    ! calculate virtual address of destination stack
3561          add       %g6, BIAS, %g6
3562
3563          mov       CTX_SECONDARY, %g2                                ! Is this context ok or should it be CTX_PRIMARY? XXX
3564          GET_MMU_CONTEXTID %g3, %g2, %g1
3565          sllx      %g3, 3, %g3                                                 ! Make it into an offset into ctxbusy (see below)
3566
3567          GET_CTXBUSY %g1
3568          ldx       [%g1 + %g3], %g1                                  ! Fetch pmap for current context id
3569
3570          ! Start of code to extract PA
3571          srlx      %g6, STSHIFT, %g7
3572          and       %g7, STMASK, %g7
3573          sll       %g7, 3, %g7                                                           ! byte offset into ctxbusy
3574          add       %g7, %g1, %g1
3575          ldxa      [%g1] ASI_PHYS_CACHED, %g1    ! Load pointer to directory
3576          srlx      %g6, PDSHIFT, %g7                       ! Do page directory
3577          and       %g7, PDMASK, %g7
3578          sll       %g7, 3, %g7
3579          brz,pn    %g1, spill_normal_to_user_stack_fail
3580           add      %g7, %g1, %g1
3581
3582          ldxa      [%g1] ASI_PHYS_CACHED, %g1
3583          srlx      %g6, PTSHIFT, %g7                       ! Convert to ptab offset
3584          and       %g7, PTMASK, %g7
3585          brz       %g1, spill_normal_to_user_stack_fail
3586           sll      %g7, 3, %g7
3587
3588          add       %g1, %g7, %g7
3589          ldxa      [%g7] ASI_PHYS_CACHED, %g7    ! This one is not
3590          brgez     %g7, spill_normal_to_user_stack_fail
3591           srlx     %g7, PGSHIFT, %g7                       ! Isolate PA part
3592
3593          sll       %g6, 32-PGSHIFT, %g6                              ! And offset
3594          sllx      %g7, PGSHIFT+8, %g7                     ! There are 8 bits to the left of the PA in the TTE
3595          srl       %g6, 32-PGSHIFT, %g6
3596          srax      %g7, 8, %g7
3597          or        %g7, %g6, %g6                                               ! Then combine them to form PA
3598          ! End of code to extract PA
3599
3600          wr        %g0, ASI_PHYS_CACHED, %asi              ! Use ASI_PHYS_CACHED to prevent possible page faults
3601          SPILL     stxa, %g6, 8, %asi                      ! Store the locals and ins
3602          saved
3603
3604          retry
3605          NOTREACHED
3606
3607spill_normal_to_user_stack_fail:
3608          sir
3609           nop
3610
3611/*
3612 * End of traps for sun4v.
3613 */
3614
3615#endif
3616
3617/*
3618 * We're here because we took an alignment fault in NUCLEUS context.
3619 * This could be a kernel bug or it could be due to saving a user
3620 * window to an invalid stack pointer.
3621 *
3622 * If the latter is the case, we could try to emulate unaligned accesses,
3623 * but we really don't know where to store the registers since we can't
3624 * determine if there's a stack bias.  Or we could store all the regs
3625 * into the PCB and punt, until the user program uses up all the CPU's
3626 * register windows and we run out of places to store them.  So for
3627 * simplicity we'll just blow them away and enter the trap code which
3628 * will generate a bus error.  Debugging the problem will be a bit
3629 * complicated since lots of register windows will be lost, but what
3630 * can we do?
3631 */
3632checkalign:
3633          rdpr      %tl, %g2
3634          subcc     %g2, 1, %g1
3635          bneg,pn   %icc, slowtrap                ! Huh?
3636           sethi    %hi(CPCB), %g6                ! get current pcb
3637
3638          wrpr      %g1, 0, %tl
3639          rdpr      %tt, %g7
3640          rdpr      %tstate, %g4
3641          andn      %g7, 0x3f, %g5
3642          cmp       %g5, 0x080                    !   window spill traps are all 0b 0000 10xx xxxx
3643          bne,a,pn  %icc, slowtrap
3644           wrpr     %g1, 0, %tl                   ! Revert TL  XXX wrpr in a delay slot...
3645
3646#ifdef DEBUG
3647          cmp       %g7, 0x34           ! If we took a datafault just before this trap
3648          bne,pt    %icc, checkalignspill         ! our stack's probably bad so we need to switch somewhere else
3649           nop
3650
3651          !!
3652          !! Double data fault -- bad stack?
3653          !!
3654          wrpr      %g2, %tl            ! Restore trap level.
3655          sir                                     ! Just issue a reset and don't try to recover.
3656          mov       %fp, %l6            ! Save the frame pointer
3657          set       EINTSTACK+USPACE+CC64FSZ-STKB, %fp ! Set the frame pointer to the middle of the idle stack
3658          add       %fp, -CC64FSZ, %sp  ! Create a stackframe
3659          wrpr      %g0, 15, %pil                 ! Disable interrupts, too
3660          wrpr      %g0, %g0, %canrestore         ! Our stack is hozed and our PCB
3661          wrpr      %g0, 7, %cansave    !  probably is too, so blow away
3662          ba        slowtrap            !  all our register windows.
3663           wrpr     %g0, 0x101, %tt
3664#endif
3665checkalignspill:
3666          /*
3667         * %g1 -- current tl
3668           * %g2 -- original tl
3669           * %g4 -- tstate
3670         * %g7 -- tt
3671           */
3672
3673          and       %g4, CWP, %g5
3674          wrpr      %g5, %cwp           ! Go back to the original register win
3675
3676          /*
3677           * Remember:
3678           *
3679           * %otherwin = 0
3680           * %cansave = NWINDOWS - 2 - %canrestore
3681           */
3682
3683          rdpr      %otherwin, %g6
3684          rdpr      %canrestore, %g3
3685          rdpr      %ver, %g5
3686          sub       %g3, %g6, %g3                 ! Calculate %canrestore - %g7
3687          and       %g5, CWP, %g5                 ! NWINDOWS-1
3688          movrlz    %g3, %g0, %g3                 ! Clamp at zero
3689          wrpr      %g0, 0, %otherwin
3690          wrpr      %g3, 0, %canrestore ! This is the new canrestore
3691          dec       %g5                           ! NWINDOWS-2
3692          wrpr      %g5, 0, %cleanwin   ! Set cleanwin to max, since we're in-kernel
3693          sub       %g5, %g3, %g5                 ! NWINDOWS-2-%canrestore
3694          wrpr      %g5, 0, %cansave
3695
3696          wrpr      %g0, T_ALIGN, %tt   ! This was an alignment fault
3697          /*
3698           * Now we need to determine if this was a userland store or not.
3699           * Userland stores occur in anything other than the kernel spill
3700           * handlers (trap type 09x).
3701           */
3702          and       %g7, 0xff0, %g5
3703          cmp       %g5, 0x90
3704          bz,pn     %icc, slowtrap
3705           nop
3706          bclr      TSTATE_PRIV, %g4
3707          wrpr      %g4, 0, %tstate
3708          ba,a,pt   %icc, slowtrap
3709           nop
3710
3711/*
3712 * slowtrap() builds a trap frame and calls trap().
3713 * This is called `slowtrap' because it *is*....
3714 * We have to build a full frame for ptrace(), for instance.
3715 *
3716 * Registers:
3717 *
3718 */
3719slowtrap:
3720#ifdef TRAPS_USE_IG
3721          wrpr      %g0, PSTATE_KERN|PSTATE_IG, %pstate     ! DEBUG
3722#endif
3723#ifdef DIAGNOSTIC
3724          /* Make sure kernel stack is aligned */
3725          btst      0x03, %sp           ! 32-bit stack OK?
3726           and      %sp, 0x07, %g4                ! 64-bit stack OK?
3727          bz,pt     %icc, 1f
3728          cmp       %g4, 0x1            ! Must end in 0b001
3729          be,pt     %icc, 1f
3730           rdpr     %wstate, %g7
3731          cmp       %g7, WSTATE_KERN
3732          bnz,pt    %icc, 1f            ! User stack -- we'll blow it away
3733           nop
3734          set       PANICSTACK-CC64FSZ-STKB, %sp
37351:
3736#endif
3737          rdpr      %tt, %g4
3738          rdpr      %tstate, %g1
3739          rdpr      %tpc, %g2
3740          rdpr      %tnpc, %g3
3741
3742          TRAP_SETUP(-CC64FSZ-TF_SIZE)
3743Lslowtrap_reenter:
3744          stx       %g1, [%sp + CC64FSZ + STKB + TF_TSTATE]
3745          mov       %g4, %o1            ! (type)
3746          stx       %g2, [%sp + CC64FSZ + STKB + TF_PC]
3747          rd        %y, %g5
3748          stx       %g3, [%sp + CC64FSZ + STKB + TF_NPC]
3749          mov       %g1, %o3            ! (pstate)
3750          st        %g5, [%sp + CC64FSZ + STKB + TF_Y]
3751          mov       %g2, %o2            ! (pc)
3752          sth       %o1, [%sp + CC64FSZ + STKB + TF_TT]! debug
3753
3754          ! Get back to normal globals
3755#ifdef SUN4V
3756          sethi     %hi(cputyp), %g5
3757          ld        [%g5 + %lo(cputyp)], %g5
3758          cmp       %g5, CPU_SUN4V
3759          bne,pt    %icc, 1f
3760           nop
3761          NORMAL_GLOBALS_SUN4V
3762          ba        2f
3763           nop
37641:
3765#endif
3766          NORMAL_GLOBALS_SUN4U
37672:
3768          stx       %g1, [%sp + CC64FSZ + STKB + TF_G + (1*8)]
3769          stx       %g2, [%sp + CC64FSZ + STKB + TF_G + (2*8)]
3770          add       %sp, CC64FSZ + STKB, %o0                ! (&tf)
3771          stx       %g3, [%sp + CC64FSZ + STKB + TF_G + (3*8)]
3772          stx       %g4, [%sp + CC64FSZ + STKB + TF_G + (4*8)]
3773          stx       %g5, [%sp + CC64FSZ + STKB + TF_G + (5*8)]
3774          rdpr      %pil, %g5
3775          stx       %g6, [%sp + CC64FSZ + STKB + TF_G + (6*8)]
3776          stx       %g7, [%sp + CC64FSZ + STKB + TF_G + (7*8)]
3777          stb       %g5, [%sp + CC64FSZ + STKB + TF_PIL]
3778          stb       %g5, [%sp + CC64FSZ + STKB + TF_OLDPIL]
3779          /*
3780           * Phew, ready to enable traps and call C code.
3781           */
3782          rdpr      %tl, %g1
3783          dec       %g1
3784          movrlz    %g1, %g0, %g1
3785          wrpr      %g0, %g1, %tl                 ! Revert to kernel mode
3786          !! In the EMBEDANY memory model %g4 points to the start of the data segment.
3787          !! In our case we need to clear it before calling any C-code
3788          clr       %g4
3789
3790          wr        %g0, ASI_PRIMARY_NOFAULT, %asi                    ! Restore default ASI
3791          wrpr      %g0, PSTATE_INTR, %pstate     ! traps on again
3792          call      _C_LABEL(trap)                          ! trap(tf, type, pc, pstate)
3793           nop
3794
3795          b         return_from_trap
3796           ldx      [%sp + CC64FSZ + STKB + TF_TSTATE], %g1 ! Load this for return_from_trap
3797          NOTREACHED
3798#if 1
3799/*
3800 * This code is no longer needed.
3801 */
3802/*
3803 * Do a `software' trap by re-entering the trap code, possibly first
3804 * switching from interrupt stack to kernel stack.  This is used for
3805 * scheduling and signal ASTs (which generally occur from softclock or
3806 * tty or net interrupts).
3807 *
3808 * We enter with the trap type in %g1.  All we have to do is jump to
3809 * Lslowtrap_reenter above, but maybe after switching stacks....
3810 *
3811 * We should be running alternate globals.  The normal globals and
3812 * out registers were just loaded from the old trap frame.
3813 *
3814 *        Input Params:
3815 *        %g1 = tstate
3816 *        %g2 = tpc
3817 *        %g3 = tnpc
3818 *        %g4 = tt == T_AST
3819 */
3820softtrap:
3821          sethi     %hi(EINTSTACK-STKB), %g5
3822          sethi     %hi(EINTSTACK-INTSTACK), %g7
3823          or        %g5, %lo(EINTSTACK-STKB), %g5
3824          dec       %g7
3825          sub       %g5, %sp, %g5
3826          sethi     %hi(CPCB), %g6
3827          andncc    %g5, %g7, %g0
3828          bnz,pt    %xcc, Lslowtrap_reenter
3829           LDPTR    [%g6 + %lo(CPCB)], %g7
3830          set       USPACE-CC64FSZ-TF_SIZE-STKB, %g5
3831          add       %g7, %g5, %g6
3832          SET_SP_REDZONE(%g7, %g5)
3833#ifdef DEBUG
3834          stx       %g1, [%g6 + CC64FSZ + STKB + TF_FAULT]            ! Generate a new trapframe
3835#endif
3836          stx       %i0, [%g6 + CC64FSZ + STKB + TF_O + (0*8)]        !         but don't bother with
3837          stx       %i1, [%g6 + CC64FSZ + STKB + TF_O + (1*8)]        !         locals and ins
3838          stx       %i2, [%g6 + CC64FSZ + STKB + TF_O + (2*8)]
3839          stx       %i3, [%g6 + CC64FSZ + STKB + TF_O + (3*8)]
3840          stx       %i4, [%g6 + CC64FSZ + STKB + TF_O + (4*8)]
3841          stx       %i5, [%g6 + CC64FSZ + STKB + TF_O + (5*8)]
3842          stx       %i6, [%g6 + CC64FSZ + STKB + TF_O + (6*8)]
3843          stx       %i7, [%g6 + CC64FSZ + STKB + TF_O + (7*8)]
3844#ifdef DEBUG
3845          ldx       [%sp + CC64FSZ + STKB + TF_I + (0*8)], %l0        ! Copy over the rest of the regs
3846          ldx       [%sp + CC64FSZ + STKB + TF_I + (1*8)], %l1        ! But just dirty the locals
3847          ldx       [%sp + CC64FSZ + STKB + TF_I + (2*8)], %l2
3848          ldx       [%sp + CC64FSZ + STKB + TF_I + (3*8)], %l3
3849          ldx       [%sp + CC64FSZ + STKB + TF_I + (4*8)], %l4
3850          ldx       [%sp + CC64FSZ + STKB + TF_I + (5*8)], %l5
3851          ldx       [%sp + CC64FSZ + STKB + TF_I + (6*8)], %l6
3852          ldx       [%sp + CC64FSZ + STKB + TF_I + (7*8)], %l7
3853          stx       %l0, [%g6 + CC64FSZ + STKB + TF_I + (0*8)]
3854          stx       %l1, [%g6 + CC64FSZ + STKB + TF_I + (1*8)]
3855          stx       %l2, [%g6 + CC64FSZ + STKB + TF_I + (2*8)]
3856          stx       %l3, [%g6 + CC64FSZ + STKB + TF_I + (3*8)]
3857          stx       %l4, [%g6 + CC64FSZ + STKB + TF_I + (4*8)]
3858          stx       %l5, [%g6 + CC64FSZ + STKB + TF_I + (5*8)]
3859          stx       %l6, [%g6 + CC64FSZ + STKB + TF_I + (6*8)]
3860          stx       %l7, [%g6 + CC64FSZ + STKB + TF_I + (7*8)]
3861          ldx       [%sp + CC64FSZ + STKB + TF_L + (0*8)], %l0
3862          ldx       [%sp + CC64FSZ + STKB + TF_L + (1*8)], %l1
3863          ldx       [%sp + CC64FSZ + STKB + TF_L + (2*8)], %l2
3864          ldx       [%sp + CC64FSZ + STKB + TF_L + (3*8)], %l3
3865          ldx       [%sp + CC64FSZ + STKB + TF_L + (4*8)], %l4
3866          ldx       [%sp + CC64FSZ + STKB + TF_L + (5*8)], %l5
3867          ldx       [%sp + CC64FSZ + STKB + TF_L + (6*8)], %l6
3868          ldx       [%sp + CC64FSZ + STKB + TF_L + (7*8)], %l7
3869          stx       %l0, [%g6 + CC64FSZ + STKB + TF_L + (0*8)]
3870          stx       %l1, [%g6 + CC64FSZ + STKB + TF_L + (1*8)]
3871          stx       %l2, [%g6 + CC64FSZ + STKB + TF_L + (2*8)]
3872          stx       %l3, [%g6 + CC64FSZ + STKB + TF_L + (3*8)]
3873          stx       %l4, [%g6 + CC64FSZ + STKB + TF_L + (4*8)]
3874          stx       %l5, [%g6 + CC64FSZ + STKB + TF_L + (5*8)]
3875          stx       %l6, [%g6 + CC64FSZ + STKB + TF_L + (6*8)]
3876          stx       %l7, [%g6 + CC64FSZ + STKB + TF_L + (7*8)]
3877#endif
3878          ba,pt     %xcc, Lslowtrap_reenter
3879           mov      %g6, %sp
3880#endif
3881
3882#if 0
3883/*
3884 * breakpoint:      capture as much info as possible and then call DDB
3885 * or trap, as the case may be.
3886 *
3887 * First, we switch to interrupt globals, and blow away %g7.  Then
3888 * switch down one stackframe -- just fiddle w/cwp, don't save or
3889 * we'll trap.  Then slowly save all the globals into our static
3890 * register buffer.  etc. etc.
3891 */
3892
3893breakpoint:
3894          wrpr      %g0, PSTATE_KERN|PSTATE_IG, %pstate     ! Get IG to use
3895          rdpr      %cwp, %g7
3896          inc       1, %g7                                            ! Equivalent of save
3897          wrpr      %g7, 0, %cwp                                      ! Now we have some unused locals to fiddle with
3898XXX ddb_regs is now ddb-regp and is a pointer not a symbol.
3899          set       _C_LABEL(ddb_regs), %l0
3900          stx       %g1, [%l0+DBR_IG+(1*8)]                           ! Save IGs
3901          stx       %g2, [%l0+DBR_IG+(2*8)]
3902          stx       %g3, [%l0+DBR_IG+(3*8)]
3903          stx       %g4, [%l0+DBR_IG+(4*8)]
3904          stx       %g5, [%l0+DBR_IG+(5*8)]
3905          stx       %g6, [%l0+DBR_IG+(6*8)]
3906          stx       %g7, [%l0+DBR_IG+(7*8)]
3907          wrpr      %g0, PSTATE_KERN|PSTATE_MG, %pstate     ! Get MG to use
3908          stx       %g1, [%l0+DBR_MG+(1*8)]                           ! Save MGs
3909          stx       %g2, [%l0+DBR_MG+(2*8)]
3910          stx       %g3, [%l0+DBR_MG+(3*8)]
3911          stx       %g4, [%l0+DBR_MG+(4*8)]
3912          stx       %g5, [%l0+DBR_MG+(5*8)]
3913          stx       %g6, [%l0+DBR_MG+(6*8)]
3914          stx       %g7, [%l0+DBR_MG+(7*8)]
3915          wrpr      %g0, PSTATE_KERN|PSTATE_AG, %pstate     ! Get AG to use
3916          stx       %g1, [%l0+DBR_AG+(1*8)]                           ! Save AGs
3917          stx       %g2, [%l0+DBR_AG+(2*8)]
3918          stx       %g3, [%l0+DBR_AG+(3*8)]
3919          stx       %g4, [%l0+DBR_AG+(4*8)]
3920          stx       %g5, [%l0+DBR_AG+(5*8)]
3921          stx       %g6, [%l0+DBR_AG+(6*8)]
3922          stx       %g7, [%l0+DBR_AG+(7*8)]
3923          wrpr      %g0, PSTATE_KERN, %pstate     ! Get G to use
3924          stx       %g1, [%l0+DBR_G+(1*8)]                            ! Save Gs
3925          stx       %g2, [%l0+DBR_G+(2*8)]
3926          stx       %g3, [%l0+DBR_G+(3*8)]
3927          stx       %g4, [%l0+DBR_G+(4*8)]
3928          stx       %g5, [%l0+DBR_G+(5*8)]
3929          stx       %g6, [%l0+DBR_G+(6*8)]
3930          stx       %g7, [%l0+DBR_G+(7*8)]
3931          rdpr      %canrestore, %l1
3932          stb       %l1, [%l0+DBR_CANRESTORE]
3933          rdpr      %cansave, %l2
3934          stb       %l2, [%l0+DBR_CANSAVE]
3935          rdpr      %cleanwin, %l3
3936          stb       %l3, [%l0+DBR_CLEANWIN]
3937          rdpr      %wstate, %l4
3938          stb       %l4, [%l0+DBR_WSTATE]
3939          rd        %y, %l5
3940          stw       %l5, [%l0+DBR_Y]
3941          rdpr      %tl, %l6
3942          stb       %l6, [%l0+DBR_TL]
3943          dec       1, %g7
3944#endif
3945
3946/*
3947 * I will not touch any of the DDB or KGDB stuff until I know what's going
3948 * on with the symbol table.  This is all still v7/v8 code and needs to be fixed.
3949 */
3950#ifdef KGDB
3951/*
3952 * bpt is entered on all breakpoint traps.
3953 * If this is a kernel breakpoint, we do not want to call trap().
3954 * Among other reasons, this way we can set breakpoints in trap().
3955 */
3956bpt:
3957          set       TSTATE_PRIV, %l4
3958          andcc     %l4, %l0, %g0                 ! breakpoint from kernel?
3959          bz        slowtrap            ! no, go do regular trap
3960           nop
3961
3962          /*
3963           * Build a trap frame for kgdb_trap_glue to copy.
3964           * Enable traps but set ipl high so that we will not
3965           * see interrupts from within breakpoints.
3966           */
3967          save      %sp, -CCFSZ-TF_SIZE, %sp                ! allocate a trap frame
3968          TRAP_SETUP(-CCFSZ-TF_SIZE)
3969          or        %l0, PSR_PIL, %l4   ! splhigh()
3970          wr        %l4, 0, %psr                  ! the manual claims that this
3971          wr        %l4, PSR_ET, %psr   ! song and dance is necessary
3972          std       %l0, [%sp + CCFSZ + 0]        ! tf.tf_psr, tf.tf_pc
3973          mov       %l3, %o0            ! trap type arg for kgdb_trap_glue
3974          rd        %y, %l3
3975          std       %l2, [%sp + CCFSZ + 8]        ! tf.tf_npc, tf.tf_y
3976          rd        %wim, %l3
3977          st        %l3, [%sp + CCFSZ + 16]       ! tf.tf_wim (a kgdb-only r/o field)
3978          st        %g1, [%sp + CCFSZ + 20]       ! tf.tf_global[1]
3979          std       %g2, [%sp + CCFSZ + 24]       ! etc
3980          std       %g4, [%sp + CCFSZ + 32]
3981          std       %g6, [%sp + CCFSZ + 40]
3982          std       %i0, [%sp + CCFSZ + 48]       ! tf.tf_in[0..1]
3983          std       %i2, [%sp + CCFSZ + 56]       ! etc
3984          std       %i4, [%sp + CCFSZ + 64]
3985          std       %i6, [%sp + CCFSZ + 72]
3986
3987          /*
3988           * Now call kgdb_trap_glue(); if it returns, call trap().
3989           */
3990          mov       %o0, %l3            ! gotta save trap type
3991          call      _C_LABEL(kgdb_trap_glue)                ! kgdb_trap_glue(type, &trapframe)
3992           add      %sp, CCFSZ, %o1               ! (&trapframe)
3993
3994          /*
3995           * Use slowtrap to call trap---but first erase our tracks
3996           * (put the registers back the way they were).
3997           */
3998          mov       %l3, %o0            ! slowtrap will need trap type
3999          ld        [%sp + CCFSZ + 12], %l3
4000          wr        %l3, 0, %y
4001          ld        [%sp + CCFSZ + 20], %g1
4002          ldd       [%sp + CCFSZ + 24], %g2
4003          ldd       [%sp + CCFSZ + 32], %g4
4004          b         Lslowtrap_reenter
4005           ldd      [%sp + CCFSZ + 40], %g6
4006
4007/*
4008 * Enter kernel breakpoint.  Write all the windows (not including the
4009 * current window) into the stack, so that backtrace works.  Copy the
4010 * supplied trap frame to the kgdb stack and switch stacks.
4011 *
4012 * kgdb_trap_glue(type, tf0)
4013 *        int type;
4014 *        struct trapframe *tf0;
4015 */
4016ENTRY_NOPROFILE(kgdb_trap_glue)
4017          save      %sp, -CCFSZ, %sp
4018
4019          flushw                                  ! flush all windows
4020          mov       %sp, %l4            ! %l4 = current %sp
4021
4022          /* copy trapframe to top of kgdb stack */
4023          set       _C_LABEL(kgdb_stack) + KGDB_STACK_SIZE - 80, %l0
4024                                                  ! %l0 = tfcopy -> end_of_kgdb_stack
4025          mov       80, %l1
40261:        ldd       [%i1], %l2
4027          inc       8, %i1
4028          deccc     8, %l1
4029          std       %l2, [%l0]
4030          bg        1b
4031           inc      8, %l0
4032
4033#ifdef NOTDEF_DEBUG
4034          /* save old red zone and then turn it off */
4035          sethi     %hi(_C_LABEL(redzone)), %l7
4036          ld        [%l7 + %lo(_C_LABEL(redzone))], %l6
4037          st        %g0, [%l7 + %lo(_C_LABEL(redzone))]
4038#endif
4039          /* switch to kgdb stack */
4040          add       %l0, -CCFSZ-TF_SIZE, %sp
4041
4042          /* if (kgdb_trap(type, tfcopy)) kgdb_rett(tfcopy); */
4043          mov       %i0, %o0
4044          call      _C_LABEL(kgdb_trap)
4045          add       %l0, -80, %o1
4046          tst       %o0
4047          bnz,a     kgdb_rett
4048           add      %l0, -80, %g1
4049
4050          /*
4051           * kgdb_trap() did not handle the trap at all so the stack is
4052           * still intact.  A simple `restore' will put everything back,
4053           * after we reset the stack pointer.
4054           */
4055          mov       %l4, %sp
4056#ifdef NOTDEF_DEBUG
4057          st        %l6, [%l7 + %lo(_C_LABEL(redzone))]     ! restore red zone
4058#endif
4059          ret
4060           restore
4061
4062/*
4063 * Return from kgdb trap.  This is sort of special.
4064 *
4065 * We know that kgdb_trap_glue wrote the window above it, so that we will
4066 * be able to (and are sure to have to) load it up.  We also know that we
4067 * came from kernel land and can assume that the %fp (%i6) we load here
4068 * is proper.  We must also be sure not to lower ipl (it is at splhigh())
4069 * until we have traps disabled, due to the SPARC taking traps at the
4070 * new ipl before noticing that PSR_ET has been turned off.  We are on
4071 * the kgdb stack, so this could be disastrous.
4072 *
4073 * Note that the trapframe argument in %g1 points into the current stack
4074 * frame (current window).  We abandon this window when we move %g1->tf_psr
4075 * into %psr, but we will not have loaded the new %sp yet, so again traps
4076 * must be disabled.
4077 */
4078kgdb_rett:
4079          rd        %psr, %g4           ! turn off traps
4080          wr        %g4, PSR_ET, %psr
4081          /* use the three-instruction delay to do something useful */
4082          ld        [%g1], %g2                    ! pick up new %psr
4083          ld        [%g1 + 12], %g3               ! set %y
4084          wr        %g3, 0, %y
4085#ifdef NOTDEF_DEBUG
4086          st        %l6, [%l7 + %lo(_C_LABEL(redzone))] ! and restore red zone
4087#endif
4088          wr        %g0, 0, %wim                  ! enable window changes
4089          nop; nop; nop
4090          /* now safe to set the new psr (changes CWP, leaves traps disabled) */
4091          wr        %g2, 0, %psr                  ! set rett psr (including cond codes)
4092          /* 3 instruction delay before we can use the new window */
4093/*1*/     ldd       [%g1 + 24], %g2               ! set new %g2, %g3
4094/*2*/     ldd       [%g1 + 32], %g4               ! set new %g4, %g5
4095/*3*/     ldd       [%g1 + 40], %g6               ! set new %g6, %g7
4096
4097          /* now we can use the new window */
4098          mov       %g1, %l4
4099          ld        [%l4 + 4], %l1                ! get new pc
4100          ld        [%l4 + 8], %l2                ! get new npc
4101          ld        [%l4 + 20], %g1               ! set new %g1
4102
4103          /* set up returnee's out registers, including its %sp */
4104          ldd       [%l4 + 48], %i0
4105          ldd       [%l4 + 56], %i2
4106          ldd       [%l4 + 64], %i4
4107          ldd       [%l4 + 72], %i6
4108
4109          /* load returnee's window, making the window above it be invalid */
4110          restore
4111          restore   %g0, 1, %l1                   ! move to inval window and set %l1 = 1
4112          rd        %psr, %l0
4113          srl       %l1, %l0, %l1
4114          wr        %l1, 0, %wim                  ! %wim = 1 << (%psr & 31)
4115          sethi     %hi(CPCB), %l1
4116          LDPTR     [%l1 + %lo(CPCB)], %l1
4117          and       %l0, 31, %l0                  ! CWP = %psr & 31;
4118!         st        %l0, [%l1 + PCB_WIM]          ! cpcb->pcb_wim = CWP;
4119          save      %g0, %g0, %g0                 ! back to window to reload
4120!         LOADWIN(%sp)
4121          save      %g0, %g0, %g0                 ! back to trap window
4122          /* note, we have not altered condition codes; safe to just rett */
4123          RETT
4124#endif
4125
4126/*
4127 * syscall_setup() builds a trap frame and calls syscall().
4128 * sun_syscall is same but delivers sun system call number
4129 * XXX    should not have to save&reload ALL the registers just for
4130 *        ptrace...
4131 */
4132syscall_setup:
4133#ifdef TRAPS_USE_IG
4134          wrpr      %g0, PSTATE_KERN|PSTATE_IG, %pstate     ! DEBUG
4135#endif
4136          TRAP_SETUP(-CC64FSZ-TF_SIZE)
4137
4138#ifdef DEBUG
4139          rdpr      %tt, %o1  ! debug
4140          sth       %o1, [%sp + CC64FSZ + STKB + TF_TT]! debug
4141#endif
4142
4143          ! Get back to normal globals
4144#ifdef SUN4V
4145          sethi     %hi(cputyp), %g5
4146          ld        [%g5 + %lo(cputyp)], %g5
4147          cmp       %g5, CPU_SUN4V
4148          bne,pt    %icc, 1f
4149           nop
4150          NORMAL_GLOBALS_SUN4V
4151          ba        2f
4152           nop
41531:
4154#endif
4155          NORMAL_GLOBALS_SUN4U
41562:
4157
4158          stx       %g1, [%sp + CC64FSZ + STKB + TF_G + ( 1*8)]
4159          mov       %g1, %o1                      ! code
4160          rdpr      %tpc, %o2                     ! (pc)
4161          stx       %g2, [%sp + CC64FSZ + STKB + TF_G + ( 2*8)]
4162          rdpr      %tstate, %g1
4163          stx       %g3, [%sp + CC64FSZ + STKB + TF_G + ( 3*8)]
4164          rdpr      %tnpc, %o3
4165          stx       %g4, [%sp + CC64FSZ + STKB + TF_G + ( 4*8)]
4166          rd        %y, %o4
4167          stx       %g5, [%sp + CC64FSZ + STKB + TF_G + ( 5*8)]
4168          stx       %g6, [%sp + CC64FSZ + STKB + TF_G + ( 6*8)]
4169          wrpr      %g0, 0, %tl                             ! return to tl=0
4170          stx       %g7, [%sp + CC64FSZ + STKB + TF_G + ( 7*8)]
4171          add       %sp, CC64FSZ + STKB, %o0      ! (&tf)
4172
4173          stx       %g1, [%sp + CC64FSZ + STKB + TF_TSTATE]
4174          stx       %o2, [%sp + CC64FSZ + STKB + TF_PC]
4175          stx       %o3, [%sp + CC64FSZ + STKB + TF_NPC]
4176          st        %o4, [%sp + CC64FSZ + STKB + TF_Y]
4177
4178          rdpr      %pil, %g5
4179          stb       %g5, [%sp + CC64FSZ + STKB + TF_PIL]
4180          stb       %g5, [%sp + CC64FSZ + STKB + TF_OLDPIL]
4181
4182          !! In the EMBEDANY memory model %g4 points to the start of the data segment.
4183          !! In our case we need to clear it before calling any C-code
4184          clr       %g4
4185          wr        %g0, ASI_PRIMARY_NOFAULT, %asi          ! Restore default ASI
4186
4187          sethi     %hi(CURLWP), %l1
4188          LDPTR     [%l1 + %lo(CURLWP)], %l1
4189          LDPTR     [%l1 + L_PROC], %l1           ! now %l1 points to p
4190          LDPTR     [%l1 + P_MD_SYSCALL], %l1
4191          call      %l1
4192           wrpr     %g0, PSTATE_INTR, %pstate     ! turn on interrupts
4193
4194          /* see `lwp_trampoline' for the reason for this label */
4195return_from_syscall:
4196          wrpr      %g0, PSTATE_KERN, %pstate     ! Disable interrupts
4197          wrpr      %g0, 0, %tl                             ! Return to tl==0
4198          b         return_from_trap
4199           nop
4200          NOTREACHED
4201
4202/*
4203 * interrupt_vector:
4204 *
4205 * Spitfire chips never get level interrupts directly from H/W.
4206 * Instead, all interrupts come in as interrupt_vector traps.
4207 * The interrupt number or handler address is an 11 bit number
4208 * encoded in the first interrupt data word.  Additional words
4209 * are application specific and used primarily for cross-calls.
4210 *
4211 * The interrupt vector handler then needs to identify the
4212 * interrupt source from the interrupt number and arrange to
4213 * invoke the interrupt handler.  This can either be done directly
4214 * from here, or a softint at a particular level can be issued.
4215 *
4216 * To call an interrupt directly and not overflow the trap stack,
4217 * the trap registers should be saved on the stack, registers
4218 * cleaned, trap-level decremented, the handler called, and then
4219 * the process must be reversed.
4220 *
4221 * To simplify life all we do here is issue an appropriate softint.
4222 *
4223 * Note:  It is impossible to identify or change a device's
4224 *                  interrupt number until it is probed.  That's the
4225 *                  purpose for all the funny interrupt acknowledge
4226 *                  code.
4227 *
4228 */
4229
4230/*
4231 * Vectored interrupts:
4232 *
4233 * When an interrupt comes in, interrupt_vector uses the interrupt
4234 * vector number to lookup the appropriate intrhand from the intrlev
4235 * array.  It then looks up the interrupt level from the intrhand
4236 * structure.  It uses the level to index the intrpending array,
4237 * which is 8 slots for each possible interrupt level (so we can
4238 * shift instead of multiply for address calculation).  It hunts for
4239 * any available slot at that level.  Available slots are NULL.
4240 *
4241 * Then interrupt_vector uses the interrupt level in the intrhand
4242 * to issue a softint of the appropriate level.  The softint handler
4243 * figures out what level interrupt it's handling and pulls the first
4244 * intrhand pointer out of the intrpending array for that interrupt
4245 * level, puts a NULL in its place, clears the interrupt generator,
4246 * and invokes the interrupt handler.
4247 */
4248
4249/* intrpending array is now in per-CPU structure. */
4250
4251#ifdef DEBUG
4252#define INTRDEBUG_VECTOR      0x1
4253#define INTRDEBUG_LEVEL                 0x2
4254#define INTRDEBUG_FUNC                  0x4
4255#define INTRDEBUG_SPUR                  0x8
4256          .data
4257          .globl    _C_LABEL(intrdebug)
4258_C_LABEL(intrdebug):          .word 0x0
4259/*
4260 * Note: we use the local label `97' to branch forward to, to skip
4261 * actual debugging code following a `intrdebug' bit test.
4262 */
4263#endif
4264          .text
4265interrupt_vector:
4266#ifdef TRAPSTATS
4267          set       _C_LABEL(kiveccnt), %g1
4268          set       _C_LABEL(iveccnt), %g2
4269          rdpr      %tl, %g3
4270          dec       %g3
4271          movrz     %g3, %g2, %g1
4272          lduw      [%g1], %g2
4273          inc       %g2
4274          stw       %g2, [%g1]
4275#endif
4276          ldxa      [%g0] ASI_IRSR, %g1
4277          mov       IRDR_0H, %g7
4278          ldxa      [%g7] ASI_IRDR, %g7 ! Get interrupt number
4279          membar    #Sync
4280
4281          btst      IRSR_BUSY, %g1
4282          bz,pn     %icc, 3f            ! spurious interrupt
4283#ifdef MULTIPROCESSOR
4284           sethi    %hi(KERNBASE), %g1
4285
4286          cmp       %g7, %g1
4287          bl,a,pt   %xcc, Lsoftint_regular        ! >= KERNBASE is a fast cross-call
4288           and      %g7, (MAXINTNUM-1), %g7       ! XXX make sun4us work
4289
4290          mov       IRDR_1H, %g2
4291          ldxa      [%g2] ASI_IRDR, %g2 ! Get IPI handler argument 1
4292          mov       IRDR_2H, %g3
4293          ldxa      [%g3] ASI_IRDR, %g3 ! Get IPI handler argument 2
4294
4295          stxa      %g0, [%g0] ASI_IRSR ! Ack IRQ
4296          membar    #Sync                         ! Should not be needed due to retry
4297
4298          jmpl      %g7, %g0
4299           nop
4300#else
4301          and       %g7, (MAXINTNUM-1), %g7       ! XXX make sun4us work
4302#endif
4303
4304Lsoftint_regular:
4305          stxa      %g0, [%g0] ASI_IRSR ! Ack IRQ
4306          membar    #Sync                         ! Should not be needed due to retry
4307          sethi     %hi(_C_LABEL(intrlev)), %g3
4308          sllx      %g7, PTRSHFT, %g5   ! Calculate entry number
4309          or        %g3, %lo(_C_LABEL(intrlev)), %g3
4310          LDPTR     [%g3 + %g5], %g5    ! We have a pointer to the handler
4311          brz,pn    %g5, 3f                       ! NULL means it isn't registered yet.  Skip it.
4312           nop
4313
4314          ! increment per-ivec counter
4315          ldx       [%g5 + IH_CNT], %g1
4316          inc       %g1
4317          stx       %g1, [%g5 + IH_CNT]
4318
4319setup_sparcintr:
4320          LDPTR     [%g5+IH_PEND], %g6  ! Read pending flag
4321          brnz,pn   %g6, ret_from_intr_vector ! Skip it if it's running
4322           ldub     [%g5+IH_PIL], %g6   ! Read interrupt level
4323          sethi     %hi(CPUINFO_VA+CI_INTRPENDING), %g1
4324          sll       %g6, PTRSHFT, %g3   ! Find start of table for this IPL
4325          or        %g1, %lo(CPUINFO_VA+CI_INTRPENDING), %g1
4326          add       %g1, %g3, %g1
43271:
4328          LDPTR     [%g1], %g3                    ! Load list head
4329          STPTR     %g3, [%g5+IH_PEND]  ! Link our intrhand node in
4330          mov       %g5, %g7
4331          CASPTRA   [%g1] ASI_N, %g3, %g7
4332          cmp       %g7, %g3            ! Did it work?
4333          bne,pn    CCCR, 1b            ! No, try again
4334           .empty
43352:
4336#ifdef NOT_DEBUG
4337          set       _C_LABEL(intrdebug), %g7
4338          ld        [%g7], %g7
4339          btst      INTRDEBUG_VECTOR, %g7
4340          bz,pt     %icc, 97f
4341           nop
4342
4343          cmp       %g6, 0xa            ! ignore clock interrupts?
4344          bz,pt     %icc, 97f
4345           nop
4346
4347          STACKFRAME(-CC64FSZ)                    ! Get a clean register window
4348          LOAD_ASCIZ(%o0,\
4349              "interrupt_vector: number %lx softint mask %lx pil %lu slot %p\n")
4350          mov       %g2, %o1
4351          rdpr      %pil, %o3
4352          mov       %g1, %o4
4353          GLOBTOLOC
4354          clr       %g4
4355          call      prom_printf
4356           mov      %g6, %o2
4357          LOCTOGLOB
4358          restore
435997:
4360#endif
4361          mov       1, %g7
4362          sll       %g7, %g6, %g6
4363          wr        %g6, 0, SET_SOFTINT ! Invoke a softint
4364
4365          .global ret_from_intr_vector
4366ret_from_intr_vector:
4367          retry
4368          NOTREACHED
4369
43703:
4371#ifdef NOT_DEBUG    /* always do this */
4372          set       _C_LABEL(intrdebug), %g6
4373          ld        [%g6], %g6
4374          btst      INTRDEBUG_SPUR, %g6
4375          bz,pt     %icc, 97f
4376           nop
4377#endif
4378#if 1
4379          set       PANICSTACK-STKB, %g1          ! Use panic stack temporarily
4380          save      %g1, -CC64FSZ, %sp  ! Get a clean register window
4381          LOAD_ASCIZ(%o0, "interrupt_vector: spurious vector %lx at pil %d\n")
4382          mov       %g7, %o1
4383          GLOBTOLOC
4384          clr       %g4
4385          call      prom_printf
4386           rdpr     %pil, %o2
4387          LOCTOGLOB
4388          restore
438997:
4390#endif
4391          ba,a      ret_from_intr_vector
4392           nop                                    ! XXX spitfire bug?
4393
4394sun4v_cpu_mondo:
4395! XXX Rework this when a UP kernel works - crash for now
4396          sir
4397          mov       0x3c0, %g1                               ! CPU Mondo Queue Head
4398          ldxa      [%g1] ASI_QUEUE, %g2                     ! fetch index value for head
4399          set       CPUINFO_VA, %g3
4400          ldx       [%g3 + CI_PADDR], %g3
4401          add       %g3, CI_CPUMQ, %g3
4402          ldxa      [%g3] ASI_PHYS_CACHED, %g3     ! fetch head element
4403          ldxa      [%g3 + %g2] ASI_PHYS_CACHED, %g4 ! fetch func
4404          add       %g2, 8, %g5
4405          ldxa      [%g3 + %g5] ASI_PHYS_CACHED, %g5 ! fetch arg1
4406          add       %g2, 16, %g6
4407          ldxa      [%g3 + %g6] ASI_PHYS_CACHED, %g6 ! fetch arg2
4408          add       %g2, 64, %g2                             ! point to next element in queue
4409          and       %g2, 0x7ff, %g2                          ! modulo queue size 2048 (32*64)
4410          stxa      %g2, [%g1] ASI_QUEUE                     ! update head index
4411          membar    #Sync
4412
4413          mov       %g4, %g2
4414          mov       %g5, %g3
4415          mov       %g6, %g5
4416          jmpl      %g2, %g0
4417           nop                          ! No store here!
4418          retry
4419          NOTREACHED
4420
4421sun4v_dev_mondo:
4422          mov       0x3d0, %g1                              ! Dev Mondo Queue Head
4423          ldxa      [%g1] ASI_QUEUE, %g2                    ! fetch index value
4424          mov       0x3d8, %g1                              ! Dev Mondo Queue Tail
4425          ldxa      [%g1] ASI_QUEUE, %g4                    ! fetch index value
4426          cmp       %g2, %g4                      ! head = queue?
4427          bne,pt    %xcc, 2f                      ! unusually not the case
4428           nop
4429          retry                                             ! unlikely, ignore interrupt
44302:
4431          set       CPUINFO_VA, %g3                          ! fetch cpuinfo pa
4432          ldx       [%g3 + CI_PADDR], %g3                    ! fetch intstack pa
4433          set       CPUINFO_VA-INTSTACK, %g4       ! offset to cpuinfo
4434          add       %g4, %g3, %g3                            ! %g3 is now cpuifo
4435          add       %g3, CI_DEVMQ, %g3             ! calc offset to devmq
4436          ldxa      [%g3] ASI_PHYS_CACHED, %g3     ! fetch address of devmq
4437          ldxa      [%g3 + %g2] ASI_PHYS_CACHED, %g5 !
4438          add       %g2, 64, %g2                             ! each element is 64 bytes
4439          and       %g2, 0x7ff, %g2                          ! assume 32 elements
4440          mov       0x3d0, %g1                               ! Dev Mondo Queue Head
4441          stxa      %g2, [%g1] ASI_QUEUE                     ! adjust head index value
4442          membar    #Sync
4443
4444          cmp       %g5, MAXINTNUM                          ! Handle both sun4v legacy (sysino) and cookies.
4445          bgeu,pn   %xcc, 1f                      ! See UltraSPARC Virtual Machine Specification
4446           nop                                              ! version 3 chapter 6 (Interrupt model)
4447
4448          sethi     %hi(_C_LABEL(intrlev)), %g3
4449          sllx      %g5, PTRSHFT, %g5   ! Calculate entry number
4450          or        %g3, %lo(_C_LABEL(intrlev)), %g3
4451          LDPTR     [%g3 + %g5], %g5    ! We have a pointer to the handler
44521:
4453          brnz,pt   %g5, setup_sparcintr          ! branch if valid handle
4454           nop
4455
4456          ba,a      3b                            ! log if invalid handle
4457           nop
4458
4459/*
4460 * Ultra1 and Ultra2 CPUs use soft interrupts for everything.  What we do
4461 * on a soft interrupt, is we should check which bits in SOFTINT(%asr22)
4462 * are set, handle those interrupts, then clear them by setting the
4463 * appropriate bits in CLEAR_SOFTINT(%asr21).
4464 *
4465 * We have an array of 8 interrupt vector slots for each of 15 interrupt
4466 * levels.  If a vectored interrupt can be dispatched, the dispatch
4467 * routine will place a pointer to an intrhand structure in one of
4468 * the slots.  The interrupt handler will go through the list to look
4469 * for an interrupt to dispatch.  If it finds one it will pull it off
4470 * the list, free the entry, and call the handler.  The code is like
4471 * this:
4472 *
4473 *        for (i=0; i<8; i++)
4474 *                  if (ih = intrpending[intlev][i]) {
4475 *                            intrpending[intlev][i] = NULL;
4476 *                            if ((*ih->ih_fun)(ih->ih_arg ? ih->ih_arg : &frame))
4477 *                                      return;
4478 *                            strayintr(&frame);
4479 *                            return;
4480 *                  }
4481 *
4482 * Otherwise we go back to the old style of polled interrupts.
4483 *
4484 * After preliminary setup work, the interrupt is passed to each
4485 * registered handler in turn.  These are expected to return nonzero if
4486 * they took care of the interrupt.  If a handler claims the interrupt,
4487 * we exit (hardware interrupts are latched in the requestor so we'll
4488 * just take another interrupt in the unlikely event of simultaneous
4489 * interrupts from two different devices at the same level).  If we go
4490 * through all the registered handlers and no one claims it, we report a
4491 * stray interrupt.  This is more or less done as:
4492 *
4493 *        for (ih = intrhand[intlev]; ih; ih = ih->ih_next)
4494 *                  if ((*ih->ih_fun)(ih->ih_arg ? ih->ih_arg : &frame))
4495 *                            return;
4496 *        strayintr(&frame);
4497 *
4498 * Inputs:
4499 *        %l0 = %tstate
4500 *        %l1 = return pc
4501 *        %l2 = return npc
4502 *        %l3 = interrupt level
4503 *        (software interrupt only) %l4 = bits to clear in interrupt register
4504 *
4505 * Internal:
4506 *        %l4, %l5: local variables
4507 *        %l6 = %y
4508 *        %l7 = %g1
4509 *        %g2..%g7 go to stack
4510 *
4511 * An interrupt frame is built in the space for a full trapframe;
4512 * this contains the psr, pc, npc, and interrupt level.
4513 *
4514 * The level of this interrupt is determined by:
4515 *
4516 *       IRQ# = %tt - 0x40
4517 */
4518
4519ENTRY_NOPROFILE(sparc_interrupt)
4520#ifdef TRAPS_USE_IG
4521          ! This is for interrupt debugging
4522          wrpr      %g0, PSTATE_KERN|PSTATE_IG, %pstate     ! DEBUG
4523#endif
4524          /*
4525           * If this is a %tick or %stick softint, clear it then call
4526           * interrupt_vector. Only one of them should be enabled at any given
4527           * time.
4528           */
4529          rd        SOFTINT, %g1
4530          set       TICK_INT|STICK_INT, %g5
4531          andcc     %g5, %g1, %g5
4532          bz,pt     %icc, 0f
4533           sethi    %hi(CPUINFO_VA+CI_TICK_IH), %g3
4534          wr        %g0, %g5, CLEAR_SOFTINT
4535          ba,pt     %icc, setup_sparcintr
4536           LDPTR    [%g3 + %lo(CPUINFO_VA+CI_TICK_IH)], %g5
45370:
4538
4539#ifdef TRAPSTATS
4540          sethi     %hi(_C_LABEL(kintrcnt)), %g1
4541          sethi     %hi(_C_LABEL(uintrcnt)), %g2
4542          or        %g1, %lo(_C_LABEL(kintrcnt)), %g1
4543          or        %g1, %lo(_C_LABEL(uintrcnt)), %g2
4544          rdpr      %tl, %g3
4545          dec       %g3
4546          movrz     %g3, %g2, %g1
4547          lduw      [%g1], %g2
4548          inc       %g2
4549          stw       %g2, [%g1]
4550          /* See if we're on the interrupt stack already. */
4551          set       EINTSTACK, %g2
4552          set       (EINTSTACK-INTSTACK), %g1
4553          btst      1, %sp
4554          add       %sp, BIAS, %g3
4555          movz      %icc, %sp, %g3
4556          srl       %g3, 0, %g3
4557          sub       %g2, %g3, %g3
4558          cmp       %g3, %g1
4559          bgu       1f
4560           set      _C_LABEL(intristk), %g1
4561          lduw      [%g1], %g2
4562          inc       %g2
4563          stw       %g2, [%g1]
45641:
4565#endif
4566          INTR_SETUP(-CC64FSZ-TF_SIZE)
4567
4568          ! Switch to normal globals so we can save them
4569#ifdef SUN4V
4570          sethi     %hi(cputyp), %g5
4571          ld        [%g5 + %lo(cputyp)], %g5
4572          cmp       %g5, CPU_SUN4V
4573          bne,pt    %icc, 1f
4574           nop
4575          NORMAL_GLOBALS_SUN4V
4576          ! Save the normal globals
4577          stx       %g1, [%sp + CC64FSZ + STKB + TF_G + ( 1*8)]
4578          stx       %g2, [%sp + CC64FSZ + STKB + TF_G + ( 2*8)]
4579          stx       %g3, [%sp + CC64FSZ + STKB + TF_G + ( 3*8)]
4580          stx       %g4, [%sp + CC64FSZ + STKB + TF_G + ( 4*8)]
4581          stx       %g5, [%sp + CC64FSZ + STKB + TF_G + ( 5*8)]
4582          stx       %g6, [%sp + CC64FSZ + STKB + TF_G + ( 6*8)]
4583          stx       %g7, [%sp + CC64FSZ + STKB + TF_G + ( 7*8)]
4584
4585          /*
4586           * In the EMBEDANY memory model %g4 points to the start of the
4587           * data segment.  In our case we need to clear it before calling
4588           * any C-code.
4589           */
4590          clr       %g4
4591
4592          ba        2f
4593           nop
45941:
4595#endif
4596          NORMAL_GLOBALS_SUN4U
4597          ! Save the normal globals
4598          stx       %g1, [%sp + CC64FSZ + STKB + TF_G + ( 1*8)]
4599          stx       %g2, [%sp + CC64FSZ + STKB + TF_G + ( 2*8)]
4600          stx       %g3, [%sp + CC64FSZ + STKB + TF_G + ( 3*8)]
4601          stx       %g4, [%sp + CC64FSZ + STKB + TF_G + ( 4*8)]
4602          stx       %g5, [%sp + CC64FSZ + STKB + TF_G + ( 5*8)]
4603          stx       %g6, [%sp + CC64FSZ + STKB + TF_G + ( 6*8)]
4604          stx       %g7, [%sp + CC64FSZ + STKB + TF_G + ( 7*8)]
4605
4606          /*
4607           * In the EMBEDANY memory model %g4 points to the start of the
4608           * data segment.  In our case we need to clear it before calling
4609           * any C-code.
4610           */
4611          clr       %g4
4612
4613          flushw                        ! Do not remove this insn -- causes interrupt loss
4614
46152:
4616          rd        %y, %l6
4617          INCR64(CPUINFO_VA+CI_NINTR)   ! cnt.v_ints++ (clobbers %o0,%o1)
4618          rdpr      %tt, %l5            ! Find out our current IPL
4619          rdpr      %tstate, %l0
4620          rdpr      %tpc, %l1
4621          rdpr      %tnpc, %l2
4622          rdpr      %tl, %l3            ! Dump our trap frame now we have taken the IRQ
4623          stw       %l6, [%sp + CC64FSZ + STKB + TF_Y]      ! Silly, but we need to save this for rft
4624          dec       %l3
4625          wrpr      %g0, %l3, %tl
4626          sth       %l5, [%sp + CC64FSZ + STKB + TF_TT]! debug
4627          stx       %l0, [%sp + CC64FSZ + STKB + TF_TSTATE] ! set up intrframe/clockframe
4628          stx       %l1, [%sp + CC64FSZ + STKB + TF_PC]
4629          btst      TSTATE_PRIV, %l0              ! User mode?
4630          stx       %l2, [%sp + CC64FSZ + STKB + TF_NPC]
4631
4632          sub       %l5, 0x40, %l6                          ! Convert to interrupt level
4633          sethi     %hi(_C_LABEL(intr_evcnts)), %l4
4634          stb       %l6, [%sp + CC64FSZ + STKB + TF_PIL]    ! set up intrframe/clockframe
4635          rdpr      %pil, %o1
4636          mulx      %l6, EVC_SIZE, %l3
4637          or        %l4, %lo(_C_LABEL(intr_evcnts)), %l4    ! intrcnt[intlev]++;
4638          stb       %o1, [%sp + CC64FSZ + STKB + TF_OLDPIL] ! old %pil
4639          ldx       [%l4 + %l3], %o0
4640          add       %l4, %l3, %l4
4641          clr       %l5                           ! Zero handled count
4642#ifdef MULTIPROCESSOR
4643          mov       1, %l3                        ! Ack softint
46441:        add       %o0, 1, %l7
4645          casxa     [%l4] ASI_N, %o0, %l7
4646          cmp       %o0, %l7
4647          bne,a,pn %xcc, 1b             ! retry if changed
4648           mov      %l7, %o0
4649#else
4650          inc       %o0
4651          mov       1, %l3                        ! Ack softint
4652          stx       %o0, [%l4]
4653#endif
4654          sll       %l3, %l6, %l3                 ! Generate IRQ mask
4655
4656          wrpr      %l6, %pil
4657
4658#define SOFTINT_INT \
4659          (1<<IPL_SOFTCLOCK|1<<IPL_SOFTBIO|1<<IPL_SOFTNET|1<<IPL_SOFTSERIAL)
4660
4661          ! Increment the per-cpu interrupt depth in case of hardintrs
4662          btst      SOFTINT_INT, %l3
4663          bnz,pn    %icc, sparc_intr_retry
4664           sethi    %hi(CPUINFO_VA+CI_IDEPTH), %l1
4665          ld        [%l1 + %lo(CPUINFO_VA+CI_IDEPTH)], %l2
4666          inc       %l2
4667          st        %l2, [%l1 + %lo(CPUINFO_VA+CI_IDEPTH)]
4668
4669sparc_intr_retry:
4670          wr        %l3, 0, CLEAR_SOFTINT         ! (don't clear possible %tick IRQ)
4671          sethi     %hi(CPUINFO_VA+CI_INTRPENDING), %l4
4672          sll       %l6, PTRSHFT, %l2
4673          or        %l4, %lo(CPUINFO_VA+CI_INTRPENDING), %l4
4674          add       %l2, %l4, %l4
4675
46761:
4677          membar    #StoreLoad                    ! Make sure any failed casxa insns complete
4678          LDPTR     [%l4], %l2                    ! Check a slot
4679          cmp       %l2, -1
4680          beq,pn    CCCR, intrcmplt               ! Empty list?
4681           mov      -1, %l7
4682          membar    #LoadStore
4683          CASPTRA   [%l4] ASI_N, %l2, %l7         ! Grab the entire list
4684          cmp       %l7, %l2
4685          bne,pn    CCCR, 1b
4686           add      %sp, CC64FSZ+STKB, %o2        ! tf = %sp + CC64FSZ + STKB
4687          LDPTR     [%l2 + IH_PEND], %l7
4688          cmp       %l7, -1                       ! Last slot?
4689          be,pt     CCCR, 3f
4690           membar   #LoadStore
4691
4692          /*
4693           * Reverse a pending list since setup_sparcintr/send_softint
4694           * makes it in a LIFO order.
4695           */
4696          mov       -1, %o0                       ! prev = -1
46971:        STPTR     %o0, [%l2 + IH_PEND]          ! ih->ih_pending = prev
4698          mov       %l2, %o0            ! prev = ih
4699          mov       %l7, %l2            ! ih = ih->ih_pending
4700          LDPTR     [%l2 + IH_PEND], %l7
4701          cmp       %l7, -1                       ! Last slot?
4702          bne,pn    CCCR, 1b
4703           membar   #LoadStore
4704          ba,pt     CCCR, 3f
4705           mov      %o0, %l7            ! save ih->ih_pending
4706
47072:
4708          add       %sp, CC64FSZ+STKB, %o2        ! tf = %sp + CC64FSZ + STKB
4709          LDPTR     [%l2 + IH_PEND], %l7          ! save ih->ih_pending
4710          membar    #LoadStore
47113:
4712          STPTR     %g0, [%l2 + IH_PEND]          ! Clear pending flag
4713          membar    #Sync
4714          LDPTR     [%l2 + IH_FUN], %o4 ! ih->ih_fun
4715          LDPTR     [%l2 + IH_ARG], %o0 ! ih->ih_arg
4716
4717#ifdef NOT_DEBUG
4718          set       _C_LABEL(intrdebug), %o3
4719          ld        [%o2], %o3
4720          btst      INTRDEBUG_FUNC, %o3
4721          bz,a,pt   %icc, 97f
4722           nop
4723
4724          cmp       %l6, 0xa            ! ignore clock interrupts?
4725          bz,pt     %icc, 97f
4726           nop
4727
4728          STACKFRAME(-CC64FSZ)                    ! Get a clean register window
4729          LOAD_ASCIZ(%o0, "sparc_interrupt: func %p arg %p\n")
4730          mov       %i0, %o2            ! arg
4731          GLOBTOLOC
4732          call      prom_printf
4733           mov      %i4, %o1            ! func
4734          LOCTOGLOB
4735          restore
473697:
4737          mov       %l4, %o1
4738#endif
4739
4740          wrpr      %g0, PSTATE_INTR, %pstate     ! Reenable interrupts
4741          jmpl      %o4, %o7            ! handled = (*ih->ih_fun)(...)
4742           movrz    %o0, %o2, %o0                 ! arg = (arg == 0) ? arg : tf
4743          wrpr      %g0, PSTATE_KERN, %pstate     ! Disable interrupts
4744          LDPTR     [%l2 + IH_CLR], %l1
4745          membar    #Sync
4746
4747          brz,pn    %l1, 0f
4748           add      %l5, %o0, %l5
4749          stx       %g0, [%l1]                    ! Clear intr source
4750          membar    #Sync                         ! Should not be needed
47510:
4752          LDPTR     [%l2 + IH_ACK], %l1 ! ih->ih_ack
4753          brz,pn    %l1, 1f
4754           nop
4755          jmpl      %l1, %o7            ! (*ih->ih_ack)(ih)
4756           mov      %l2, %o0
47571:
4758          cmp       %l7, -1
4759          bne,pn    CCCR, 2b            ! 'Nother?
4760           mov      %l7, %l2
4761
4762intrcmplt:
4763          /*
4764           * Re-read SOFTINT to see if any new  pending interrupts
4765           * at this level.
4766           */
4767          mov       1, %l3                        ! Ack softint
4768          rd        SOFTINT, %l7                  ! %l5 contains #intr handled.
4769          sll       %l3, %l6, %l3                 ! Generate IRQ mask
4770          btst      %l3, %l7            ! leave mask in %l3 for retry code
4771          bnz,pn    %icc, sparc_intr_retry
4772           mov      1, %l5                        ! initialize intr count for next run
4773
4774          ! Decrement this cpu's interrupt depth in case of hardintrs
4775          btst      SOFTINT_INT, %l3
4776          bnz,pn    %icc, 1f
4777           sethi    %hi(CPUINFO_VA+CI_IDEPTH), %l4
4778          ld        [%l4 + %lo(CPUINFO_VA+CI_IDEPTH)], %l5
4779          dec       %l5
4780          st        %l5, [%l4 + %lo(CPUINFO_VA+CI_IDEPTH)]
47811:
4782
4783#ifdef NOT_DEBUG
4784          set       _C_LABEL(intrdebug), %o2
4785          ld        [%o2], %o2
4786          btst      INTRDEBUG_FUNC, %o2
4787          bz,a,pt   %icc, 97f
4788           nop
4789
4790          cmp       %l6, 0xa            ! ignore clock interrupts?
4791          bz,pt     %icc, 97f
4792           nop
4793
4794          STACKFRAME(-CC64FSZ)                    ! Get a clean register window
4795          LOAD_ASCIZ(%o0, "sparc_interrupt:  done\n")
4796          GLOBTOLOC
4797          call      prom_printf
4798           nop
4799          LOCTOGLOB
4800          restore
480197:
4802#endif
4803
4804          ldub      [%sp + CC64FSZ + STKB + TF_OLDPIL], %l3 ! restore old %pil
4805          wrpr      %l3, 0, %pil
4806
4807          b         return_from_trap
4808           ldx      [%sp + CC64FSZ + STKB + TF_TSTATE], %g1 ! Load this for return_from_trap
4809
4810#ifdef notyet
4811/*
4812 * Level 12 (ZS serial) interrupt.  Handle it quickly, schedule a
4813 * software interrupt, and get out.  Do the software interrupt directly
4814 * if we would just take it on the way out.
4815 *
4816 * Input:
4817 *        %l0 = %psr
4818 *        %l1 = return pc
4819 *        %l2 = return npc
4820 * Internal:
4821 *        %l3 = zs device
4822 *        %l4, %l5 = temporary
4823 *        %l6 = rr3 (or temporary data) + 0x100 => need soft int
4824 *        %l7 = zs soft status
4825 */
4826zshard:
4827#endif /* notyet */
4828
4829          .globl    return_from_trap, rft_kernel, rft_user
4830          .globl    softtrap, slowtrap
4831
4832/*
4833 * Various return-from-trap routines (see return_from_trap).
4834 */
4835
4836/*
4837 * Return from trap.
4838 * registers are:
4839 *
4840 *        [%sp + CC64FSZ + STKB] => trap frame
4841 *      %g1 => tstate from trap frame
4842 *
4843 * We must load all global, out, and trap registers from the trap frame.
4844 *
4845 * If returning to kernel, we should be at the proper trap level because
4846 * we don't touch %tl.
4847 *
4848 * When returning to user mode, the trap level does not matter, as it
4849 * will be set explicitly.
4850 *
4851 * If we are returning to user code, we must:
4852 *  1.  Check for register windows in the pcb that belong on the stack.
4853 *        If there are any, reload them
4854 */
4855return_from_trap:
4856#ifdef DEBUG
4857          !! Make sure we don't have pc == npc == 0 or we suck.
4858          ldx       [%sp + CC64FSZ + STKB + TF_PC], %g2
4859          ldx       [%sp + CC64FSZ + STKB + TF_NPC], %g3
4860          orcc      %g2, %g3, %g0
4861          tz        %icc, 1
4862#endif
4863
4864          !!
4865          !! We'll make sure we flush our pcb here, rather than later.
4866          !!
4867!         ldx       [%sp + CC64FSZ + STKB + TF_TSTATE], %g1 ! already passed in, no need to reload
4868          btst      TSTATE_PRIV, %g1                        ! returning to userland?
4869
4870          !!
4871          !! Let all pending interrupts drain before returning to userland
4872          !!
4873          bnz,pn    %icc, 1f                                ! Returning to userland?
4874           nop
4875          ENABLE_INTERRUPTS %g5
4876          wrpr      %g0, %g0, %pil                                    ! Lower IPL
48771:
4878          !! Make sure we have no IRQs
4879          DISABLE_INTERRUPTS %g5
4880
4881#ifdef SUN4V
4882          sethi     %hi(cputyp), %g5
4883          ld        [%g5 + %lo(cputyp)], %g5
4884          cmp       %g5, CPU_SUN4V
4885          bne,pt    %icc, 1f
4886           nop
4887          !! Make sure we have normal globals
4888          NORMAL_GLOBALS_SUN4V
4889          /* Restore normal globals */
4890          ldx       [%sp + CC64FSZ + STKB + TF_G + (1*8)], %g1
4891          ldx       [%sp + CC64FSZ + STKB + TF_G + (2*8)], %g2
4892          ldx       [%sp + CC64FSZ + STKB + TF_G + (3*8)], %g3
4893          ldx       [%sp + CC64FSZ + STKB + TF_G + (4*8)], %g4
4894          ldx       [%sp + CC64FSZ + STKB + TF_G + (5*8)], %g5
4895          ldx       [%sp + CC64FSZ + STKB + TF_G + (6*8)], %g6
4896          ldx       [%sp + CC64FSZ + STKB + TF_G + (7*8)], %g7
4897          /* Switch to alternate globals */
4898          ALTERNATE_GLOBALS_SUN4V
4899          ba        2f
4900           nop
49011:
4902#endif
4903          !! Make sure we have normal globals
4904          NORMAL_GLOBALS_SUN4U
4905          /* Restore normal globals */
4906          ldx       [%sp + CC64FSZ + STKB + TF_G + (1*8)], %g1
4907          ldx       [%sp + CC64FSZ + STKB + TF_G + (2*8)], %g2
4908          ldx       [%sp + CC64FSZ + STKB + TF_G + (3*8)], %g3
4909          ldx       [%sp + CC64FSZ + STKB + TF_G + (4*8)], %g4
4910          ldx       [%sp + CC64FSZ + STKB + TF_G + (5*8)], %g5
4911          ldx       [%sp + CC64FSZ + STKB + TF_G + (6*8)], %g6
4912          ldx       [%sp + CC64FSZ + STKB + TF_G + (7*8)], %g7
4913          /* Switch to alternate globals */
4914#ifdef TRAPS_USE_IG
4915          wrpr      %g0, PSTATE_KERN|PSTATE_IG, %pstate     ! DEBUG
4916#else
4917          ALTERNATE_GLOBALS_SUN4U
4918#endif
49192:
4920
4921          /* Load outs */
4922          ldx       [%sp + CC64FSZ + STKB + TF_O + (0*8)], %i0
4923          ldx       [%sp + CC64FSZ + STKB + TF_O + (1*8)], %i1
4924          ldx       [%sp + CC64FSZ + STKB + TF_O + (2*8)], %i2
4925          ldx       [%sp + CC64FSZ + STKB + TF_O + (3*8)], %i3
4926          ldx       [%sp + CC64FSZ + STKB + TF_O + (4*8)], %i4
4927          ldx       [%sp + CC64FSZ + STKB + TF_O + (5*8)], %i5
4928          ldx       [%sp + CC64FSZ + STKB + TF_O + (6*8)], %i6
4929          ldx       [%sp + CC64FSZ + STKB + TF_O + (7*8)], %i7
4930          /* Now load trap registers into alternate globals */
4931          ld        [%sp + CC64FSZ + STKB + TF_Y], %g4
4932          ldx       [%sp + CC64FSZ + STKB + TF_TSTATE], %g1           ! load new values
4933          wr        %g4, 0, %y
4934          ldx       [%sp + CC64FSZ + STKB + TF_PC], %g2
4935          ldx       [%sp + CC64FSZ + STKB + TF_NPC], %g3
4936
4937#ifdef NOTDEF_DEBUG
4938          ldub      [%sp + CC64FSZ + STKB + TF_PIL], %g5              ! restore %pil
4939          wrpr      %g5, %pil                               ! DEBUG
4940#endif
4941
4942          /* Returning to user mode or kernel mode? */
4943          btst      TSTATE_PRIV, %g1              ! returning to userland?
4944          bz,pt     %icc, rft_user
4945           sethi    %hi(CPUINFO_VA+CI_WANT_AST), %g7        ! first instr of rft_user
4946
4947/*
4948 * Return from trap, to kernel.
4949 *
4950 * We will assume, for the moment, that all kernel traps are properly stacked
4951 * in the trap registers, so all we have to do is insert the (possibly modified)
4952 * register values into the trap registers then do a retry.
4953 *
4954 */
4955rft_kernel:
4956          rdpr      %tl, %g4                      ! Grab a set of trap registers
4957          inc       %g4
4958          wrpr      %g4, %g0, %tl
4959          wrpr      %g3, 0, %tnpc
4960          wrpr      %g2, 0, %tpc
4961          wrpr      %g1, 0, %tstate
4962
4963          rdpr      %canrestore, %g2
4964          brnz      %g2, 1f
4965           nop
4966
4967          wr        %g0, ASI_NUCLEUS, %asi
4968          rdpr      %cwp, %g1
4969          dec       %g1
4970          wrpr      %g1, %cwp
4971#ifdef _LP64
4972          FILL      ldxa, %sp+BIAS, 8, %asi
4973#else
4974          FILL      lda, %sp, 4, %asi
4975#endif
4976          restored
4977          inc       %g1
4978          wrpr      %g1, %cwp
49791:
4980          restore
4981          rdpr      %tstate, %g1                            ! Since we may have trapped our regs may be toast
4982          rdpr      %cwp, %g2
4983          andn      %g1, CWP, %g1
4984          wrpr      %g1, %g2, %tstate             ! Put %cwp in %tstate
4985          CLRTT
4986#ifdef TRAPSTATS
4987          rdpr      %tl, %g2
4988          set       _C_LABEL(rftkcnt), %g1
4989          sllx      %g2, 2, %g2
4990          add       %g1, %g2, %g1
4991          lduw      [%g1], %g2
4992          inc       %g2
4993          stw       %g2, [%g1]
4994#endif
4995#if       0
4996          wrpr      %g0, 0, %cleanwin   ! DEBUG
4997#endif
4998#if defined(DDB) && defined(MULTIPROCESSOR)
4999          set       sparc64_ipi_pause_trap_point, %g1
5000          rdpr      %tpc, %g2
5001          cmp       %g1, %g2
5002          bne,pt    %icc, 0f
5003           nop
5004          done
50050:
5006#endif
5007          retry
5008          NOTREACHED
5009/*
5010 * Return from trap, to user.  Checks for scheduling trap (`ast') first;
5011 * will re-enter trap() if set.  Note that we may have to switch from
5012 * the interrupt stack to the kernel stack in this case.
5013 *        %g1 = %tstate
5014 *        %g2 = return %pc
5015 *        %g3 = return %npc
5016 * If returning to a valid window, just set psr and return.
5017 */
5018          .data
5019rft_wcnt: .word 0
5020          .text
5021
5022rft_user:
5023!         sethi     %hi(CPUINFO_VA+CI_WANT_AST), %g7        ! (done above)
5024          lduw      [%g7 + %lo(CPUINFO_VA+CI_WANT_AST)], %g7! want AST trap?
5025          brnz,pn   %g7, softtrap                           ! yes, re-enter trap with type T_AST
5026           mov      T_AST, %g4
5027
5028#ifdef NOTDEF_DEBUG
5029          sethi     %hi(CPCB), %g4
5030          LDPTR     [%g4 + %lo(CPCB)], %g4
5031          ldub      [%g4 + PCB_NSAVED], %g4                 ! nsaved
5032          brz,pt    %g4, 2f             ! Only print if nsaved <> 0
5033           nop
5034
5035          set       1f, %o0
5036          mov       %g4, %o1
5037          mov       %g2, %o2                      ! pc
5038          wr        %g0, ASI_DMMU, %asi           ! restore the user context
5039          ldxa      [CTX_SECONDARY] %asi, %o3     ! ctx
5040          GLOBTOLOC
5041          mov       %g3, %o5
5042          call      printf
5043           mov      %i6, %o4                      ! sp
5044!         wrpr      %g0, PSTATE_INTR, %pstate               ! Allow IRQ service
5045!         wrpr      %g0, PSTATE_KERN, %pstate               ! DenyIRQ service
5046          LOCTOGLOB
50471:
5048          .data
5049          .asciz    "rft_user: nsaved=%x pc=%d ctx=%x sp=%x npc=%p\n"
5050          _ALIGN
5051          .text
5052#endif
5053
5054          /*
5055           * NB: only need to do this after a cache miss
5056           */
5057#ifdef TRAPSTATS
5058          set       _C_LABEL(rftucnt), %g6
5059          lduw      [%g6], %g7
5060          inc       %g7
5061          stw       %g7, [%g6]
5062#endif
5063          /*
5064           * Now check to see if any regs are saved in the pcb and restore them.
5065           *
5066           * Here we need to undo the damage caused by switching to a kernel
5067           * stack.
5068           *
5069           * We will use alternate globals %g4..%g7 because %g1..%g3 are used
5070           * by the data fault trap handlers and we don't want possible conflict.
5071           */
5072
5073          sethi     %hi(CPCB), %g6
5074          rdpr      %otherwin, %g7                          ! restore register window controls
5075#ifdef DEBUG
5076          rdpr      %canrestore, %g5              ! DEBUG
5077          tst       %g5                                     ! DEBUG
5078          tnz       %icc, 1; nop                            ! DEBUG
5079!         mov       %g0, %g5                      ! There should be *NO* %canrestore
5080          add       %g7, %g5, %g7                           ! DEBUG
5081#endif
5082          wrpr      %g0, %g7, %canrestore
5083          LDPTR     [%g6 + %lo(CPCB)], %g6
5084          wrpr      %g0, 0, %otherwin
5085
5086          ldub      [%g6 + PCB_NSAVED], %g7                 ! Any saved reg windows?
5087          wrpr      %g0, WSTATE_USER, %wstate     ! Need to know where our sp points
5088
5089#ifdef DEBUG
5090          set       rft_wcnt, %g4       ! Keep track of all the windows we restored
5091          stw       %g7, [%g4]
5092#endif
5093
5094          brz,pt    %g7, 5f                                 ! No saved reg wins
5095           nop
5096          dec       %g7                                     ! We can do this now or later.  Move to last entry
5097
5098#ifdef DEBUG
5099          rdpr      %canrestore, %g4                        ! DEBUG Make sure we've restored everything
5100          brnz,a,pn %g4, 0f                                 ! DEBUG
5101           sir                                                        ! DEBUG we should NOT have any usable windows here
51020:                                                                    ! DEBUG
5103          wrpr      %g0, 5, %tl
5104#endif
5105          rdpr      %otherwin, %g4
5106          sll       %g7, 7, %g5                             ! calculate ptr into rw64 array 8*16 == 128 or 7 bits
5107          brz,pt    %g4, 6f                                 ! We should not have any user windows left
5108           add      %g5, %g6, %g5
5109
5110          set       1f, %o0
5111          mov       %g7, %o1
5112          mov       %g4, %o2
5113          call      printf
5114           wrpr     %g0, PSTATE_KERN, %pstate
5115          set       2f, %o0
5116          call      panic
5117           nop
5118          NOTREACHED
5119          .data
51201:        .asciz    "pcb_nsaved=%x and otherwin=%x\n"
51212:        .asciz    "rft_user\n"
5122          _ALIGN
5123          .text
51246:
51253:
5126          restored                                          ! Load in the window
5127          restore                                                     ! This should not trap!
5128          ldx       [%g5 + PCB_RW + ( 0*8)], %l0            ! Load the window from the pcb
5129          ldx       [%g5 + PCB_RW + ( 1*8)], %l1
5130          ldx       [%g5 + PCB_RW + ( 2*8)], %l2
5131          ldx       [%g5 + PCB_RW + ( 3*8)], %l3
5132          ldx       [%g5 + PCB_RW + ( 4*8)], %l4
5133          ldx       [%g5 + PCB_RW + ( 5*8)], %l5
5134          ldx       [%g5 + PCB_RW + ( 6*8)], %l6
5135          ldx       [%g5 + PCB_RW + ( 7*8)], %l7
5136
5137          ldx       [%g5 + PCB_RW + ( 8*8)], %i0
5138          ldx       [%g5 + PCB_RW + ( 9*8)], %i1
5139          ldx       [%g5 + PCB_RW + (10*8)], %i2
5140          ldx       [%g5 + PCB_RW + (11*8)], %i3
5141          ldx       [%g5 + PCB_RW + (12*8)], %i4
5142          ldx       [%g5 + PCB_RW + (13*8)], %i5
5143          ldx       [%g5 + PCB_RW + (14*8)], %i6
5144          ldx       [%g5 + PCB_RW + (15*8)], %i7
5145
5146#ifdef DEBUG
5147          stx       %g0, [%g5 + PCB_RW + (14*8)]            ! DEBUG mark that we've saved this one
5148#endif
5149
5150          cmp       %g5, %g6
5151          bgu,pt    %xcc, 3b                                ! Next one?
5152           dec      8*16, %g5
5153
5154          stb       %g0, [%g6 + PCB_NSAVED]                           ! Clear them out so we won't do this again
5155          GET_MAXCWP %g5
5156          add       %g5, %g7, %g4
5157          dec       1, %g5                                            ! NWINDOWS-1-1
5158          wrpr      %g5, 0, %cansave
5159          wrpr      %g0, 0, %canrestore                     ! Make sure we have no freeloaders XXX
5160          wrpr      %g0, WSTATE_USER, %wstate               ! Save things to user space
5161          mov       %g7, %g5                                ! We already did one restore
51624:
5163          rdpr      %canrestore, %g4
5164          inc       %g4
5165          deccc     %g5
5166          wrpr      %g4, 0, %cleanwin                       ! Make *sure* we don't trap to cleanwin
5167          bge,a,pt  %xcc, 4b                                ! return to starting regwin
5168           save     %g0, %g0, %g0                                     ! This may force a datafault
5169
5170#ifdef DEBUG
5171          wrpr      %g0, 0, %tl
5172#endif
5173#ifdef TRAPSTATS
5174          set       _C_LABEL(rftuld), %g5
5175          lduw      [%g5], %g4
5176          inc       %g4
5177          stw       %g4, [%g5]
5178#endif
5179          !!
5180          !! We can't take any save faults in here 'cause they will never be serviced
5181          !!
5182
5183#ifdef DEBUG
5184          sethi     %hi(CPCB), %g5
5185          LDPTR     [%g5 + %lo(CPCB)], %g5
5186          ldub      [%g5 + PCB_NSAVED], %g5                 ! Any saved reg windows?
5187          tst       %g5
5188          tnz       %icc, 1; nop                            ! Debugger if we still have saved windows
5189          bne,a     rft_user                      ! Try starting over again
5190           sethi    %hi(CPUINFO_VA+CI_WANT_AST), %g7
5191#endif
5192          /*
5193           * Set up our return trapframe so we can recover if we trap from here
5194           * on in.
5195           */
5196          wrpr      %g0, 1, %tl                             ! Set up the trap state
5197          wrpr      %g2, 0, %tpc
5198          wrpr      %g3, 0, %tnpc
5199          ba,pt     %icc, 6f
5200           wrpr     %g1, %g0, %tstate
5201
52025:
5203          /*
5204           * Set up our return trapframe so we can recover if we trap from here
5205           * on in.
5206           */
5207          wrpr      %g0, 1, %tl                             ! Set up the trap state
5208          wrpr      %g2, 0, %tpc
5209          wrpr      %g3, 0, %tnpc
5210          wrpr      %g1, %g0, %tstate
5211
5212          /*
5213           * The restore instruction further down may cause the trap level
5214           * to exceed the maximum trap level on sun4v, so a manual fill
5215           * may be necessary.
5216          */
5217
5218#ifdef SUN4V
5219          sethi     %hi(cputyp), %g5
5220          ld        [%g5 + %lo(cputyp)], %g5
5221          cmp       %g5, CPU_SUN4V
5222          bne,pt    %icc, 1f
5223           nop
5224
5225          ! Only manual fill if the restore instruction will cause a fill trap
5226          rdpr      %canrestore, %g5
5227          brnz      %g5, 1f
5228           nop
5229
5230          ! Do a manual fill
5231          wr        %g0, ASI_AIUS, %asi
5232          rdpr      %cwp, %g4
5233          dec       %g4
5234          wrpr      %g4, 0, %cwp
5235rft_user_fault_start:
5236          FILL      ldxa, %sp+BIAS, 8, %asi
5237rft_user_fault_end:
5238          restored
5239          inc       %g4
5240          wrpr      %g4, 0, %cwp
52411:
5242#endif
5243          restore
52446:
5245          rdpr      %canrestore, %g5
5246          wrpr      %g5, 0, %cleanwin                       ! Force cleanup of kernel windows
5247
5248#ifdef NOTDEF_DEBUG
5249          ldx       [%g6 + CC64FSZ + STKB + TF_L + (0*8)], %g5! DEBUG -- get proper value for %l0
5250          cmp       %l0, %g5
5251          be,a,pt %icc, 1f
5252           nop
5253!         sir                           ! WATCHDOG
5254          set       badregs, %g1        ! Save the suspect regs
5255          stw       %l0, [%g1+(4*0)]
5256          stw       %l1, [%g1+(4*1)]
5257          stw       %l2, [%g1+(4*2)]
5258          stw       %l3, [%g1+(4*3)]
5259          stw       %l4, [%g1+(4*4)]
5260          stw       %l5, [%g1+(4*5)]
5261          stw       %l6, [%g1+(4*6)]
5262          stw       %l7, [%g1+(4*7)]
5263          stw       %i0, [%g1+(4*8)+(4*0)]
5264          stw       %i1, [%g1+(4*8)+(4*1)]
5265          stw       %i2, [%g1+(4*8)+(4*2)]
5266          stw       %i3, [%g1+(4*8)+(4*3)]
5267          stw       %i4, [%g1+(4*8)+(4*4)]
5268          stw       %i5, [%g1+(4*8)+(4*5)]
5269          stw       %i6, [%g1+(4*8)+(4*6)]
5270          stw       %i7, [%g1+(4*8)+(4*7)]
5271          save
5272          inc       %g7
5273          wrpr      %g7, 0, %otherwin
5274          wrpr      %g0, 0, %canrestore
5275          wrpr      %g0, WSTATE_KERN, %wstate     ! Need to know where our sp points
5276          set       rft_wcnt, %g4       ! Restore nsaved before trapping
5277          sethi     %hi(CPCB), %g6
5278          LDPTR     [%g6 + %lo(CPCB)], %g6
5279          lduw      [%g4], %g4
5280          stb       %g4, [%g6 + PCB_NSAVED]
5281          ta        1
5282          sir
5283          .data
5284badregs:
5285          .space    16*4
5286          .text
52871:
5288#endif
5289
5290          rdpr      %tstate, %g1
5291          rdpr      %cwp, %g7                     ! Find our cur window
5292          andn      %g1, CWP, %g1                           ! Clear it from %tstate
5293          wrpr      %g1, %g7, %tstate             ! Set %tstate with %cwp
5294          mov       CTX_SECONDARY, %g1            ! Restore the user context
5295          GET_MMU_CONTEXTID %g4, %g1, %g3
5296          mov       CTX_PRIMARY, %g2
5297          SET_MMU_CONTEXTID %g4, %g2, %g3
5298          sethi     %hi(KERNBASE), %g7            ! Should not be needed due to retry
5299          membar    #Sync                                   ! Should not be needed due to retry
5300          flush     %g7                                     ! Should not be needed due to retry
5301
5302          CLRTT
5303#ifdef TRAPSTATS
5304          set       _C_LABEL(rftudone), %g1
5305          lduw      [%g1], %g2
5306          inc       %g2
5307          stw       %g2, [%g1]
5308#endif
5309#ifdef DEBUG
5310          sethi     %hi(CPCB), %g5
5311          LDPTR     [%g5 + %lo(CPCB)], %g5
5312          ldub      [%g5 + PCB_NSAVED], %g5                 ! Any saved reg windows?
5313          tst       %g5
5314          tnz       %icc, 1; nop                            ! Debugger if we still have saved windows!
5315#endif
5316          wrpr      %g0, 0, %pil                            ! Enable all interrupts
5317          retry
5318
5319! exported end marker for kernel gdb
5320          .globl    _C_LABEL(endtrapcode)
5321_C_LABEL(endtrapcode):
5322
5323/*
5324 * Kernel entry point.
5325 *
5326 * The contract between bootloader and kernel is:
5327 *
5328 * %o0              OpenFirmware entry point, to keep Sun's updaters happy
5329 * %o1              Address of boot information vector (see bootinfo.h)
5330 * %o2              Length of the vector, in bytes
5331 * %o3              OpenFirmware entry point, to mimic Sun bootloader behavior
5332 * %o4              OpenFirmware, to meet earlier NetBSD kernels expectations
5333 */
5334          .align    8
5335start:
5336dostart:
5337          /*
5338           * Startup.
5339           *
5340           * The Sun FCODE bootloader is nice and loads us where we want
5341           * to be.  We have a full set of mappings already set up for us.
5342           *
5343           * I think we end up having an entire 16M allocated to us.
5344           *
5345           * We enter with the prom entry vector in %o0, dvec in %o1,
5346           * and the bootops vector in %o2.
5347           *
5348           * All we need to do is:
5349           *
5350           *        1:        Save the prom vector
5351           *
5352           *        2:        Create a decent stack for ourselves
5353           *
5354           *        3:        Install the permanent 4MB kernel mapping
5355           *
5356           *        4:        Call the C language initialization code
5357           *
5358           */
5359
5360          /*
5361           * Set the psr into a known state:
5362           * Set supervisor mode, interrupt level >= 13, traps enabled
5363           */
5364          wrpr      %g0, 13, %pil
5365          wrpr      %g0, PSTATE_INTR|PSTATE_PEF, %pstate
5366          wr        %g0, FPRS_FEF, %fprs                    ! Turn on FPU
5367
5368          /*
5369           * Step 2: Set up a v8-like stack if we need to
5370           */
5371
5372#ifdef _LP64
5373          btst      1, %sp
5374          bnz,pt    %icc, 0f
5375           nop
5376          add       %sp, -BIAS, %sp
5377#else
5378          btst      1, %sp
5379          bz,pt     %icc, 0f
5380           nop
5381          add       %sp, BIAS, %sp
5382#endif
53830:
5384
5385          call      _C_LABEL(bootstrap)
5386           clr      %g4                                     ! Clear data segment pointer
5387
5388/*
5389 * Initialize the boot CPU.  Basically:
5390 *
5391 *        Locate the cpu_info structure for this CPU.
5392 *        Establish a locked mapping for interrupt stack.
5393 *        Switch to the initial stack.
5394 *        Call the routine passed in in cpu_info->ci_spinup
5395 */
5396
5397#ifdef NO_VCACHE
5398#define   SUN4U_TTE_DATABITS  SUN4U_TTE_L|SUN4U_TTE_CP|SUN4U_TTE_P|SUN4U_TTE_W
5399#else
5400#define   SUN4U_TTE_DATABITS  SUN4U_TTE_L|SUN4U_TTE_CP|SUN4U_TTE_CV|SUN4U_TTE_P|SUN4U_TTE_W
5401#endif
5402
5403
5404ENTRY_NOPROFILE(cpu_initialize)         /* for cosmetic reasons - nicer backtrace */
5405
5406          /* Cache the cputyp in %l6 for later use below */
5407          sethi     %hi(cputyp), %l6
5408          ld        [%l6 + %lo(cputyp)], %l6
5409
5410          /*
5411           * Step 5: is no more.
5412           */
5413
5414          /*
5415           * Step 6: hunt through cpus list and find the one that matches our cpuid
5416           */
5417
5418          call      _C_LABEL(cpu_myid)  ! Retrieve cpuid in %o0
5419           mov      %g0, %o0
5420
5421          sethi     %hi(_C_LABEL(cpus)), %l1
5422          LDPTR     [%l1 + %lo(_C_LABEL(cpus))], %l1
54230:
5424          ld        [%l1 + CI_CPUID], %l3                   ! Load CPUID
5425          cmp       %l3, %o0                      ! Does it match?
5426          bne,a,pt  %icc, 0b            ! no
5427           LDPTR    [%l1 + CI_NEXT], %l1                    ! Load next cpu_info pointer
5428
5429          /*
5430           * Get pointer to our cpu_info struct
5431           */
5432          mov       %l1, %l7                      ! save cpu_info pointer
5433          ldx       [%l1 + CI_PADDR], %l1                   ! Load the interrupt stack's PA
5434#ifdef SUN4V
5435          cmp       %l6, CPU_SUN4V
5436          bne,pt    %icc, 3f
5437           nop
5438
5439          /* sun4v */
5440          call      _C_LABEL(pmap_setup_intstack_sun4v)     ! Call nice C function for mapping INTSTACK
5441           mov      %l1, %o0
5442          ba        4f
5443           nop
54443:
5445#endif
5446          /* sun4u */
5447          sethi     %hi(0xa0000000), %l2                    ! V=1|SZ=01|NFO=0|IE=0
5448          sllx      %l2, 32, %l2                            ! Shift it into place
5449
5450          mov       -1, %l3                                 ! Create a nice mask
5451          sllx      %l3, 43, %l4                            ! Mask off high bits
5452          or        %l4, 0xfff, %l4                         ! We can just load this in 12 (of 13) bits
5453
5454          andn      %l1, %l4, %l1                           ! Mask the phys page number
5455
5456          or        %l2, %l1, %l1                           ! Now take care of the high bits
5457          or        %l1, SUN4U_TTE_DATABITS, %l2  ! And low bits:     L=1|CP=1|CV=?|E=0|P=1|W=1|G=0
5458
5459          !!
5460          !!  Now, map in the interrupt stack as context==0
5461          !!
5462          set       TLB_TAG_ACCESS, %l5
5463          set       INTSTACK, %l0
5464          stxa      %l0, [%l5] ASI_DMMU           ! Make DMMU point to it
5465          stxa      %l2, [%g0] ASI_DMMU_DATA_IN   ! Store it
5466          membar    #Sync
54674:
5468
5469          !! Setup kernel stack (we rely on curlwp on this cpu
5470          !! being lwp0 here and its uarea is mapped special
5471          !! and already accessible here)
5472          flushw
5473          LDPTR     [%l7 + CI_CPCB], %l0                    ! load PCB/uarea pointer
5474          set       2*USPACE - TF_SIZE - CC64FSZ, %l1
5475          add       %l1, %l0, %l0
5476#ifdef _LP64
5477          andn      %l0, 0x0f, %l0                          ! Needs to be 16-byte aligned
5478          sub       %l0, BIAS, %l0                          ! and biased
5479#endif
5480          mov       %l0, %sp
5481          flushw
5482
5483#ifdef DEBUG
5484          set       _C_LABEL(pmapdebug), %o1
5485          ld        [%o1], %o1
5486          sethi     %hi(0x40000), %o2
5487          btst      %o2, %o1
5488          bz        0f
5489
5490          set       1f, %o0             ! Debug printf
5491          call      _C_LABEL(prom_printf)
5492           nop
5493          .data
54941:
5495          .asciz    "Setting trap base...\n"
5496          _ALIGN
5497          .text
54980:
5499#endif
5500          /*
5501           * Step 7: change the trap base register, and install our TSB pointers
5502           */
5503
5504          /*
5505           * install our TSB pointers
5506           */
5507
5508#ifdef SUN4V
5509          cmp       %l6, CPU_SUN4V
5510          bne,pt    %icc, 5f
5511           nop
5512
5513          /* sun4v */
5514          LDPTR     [%l7 + CI_TSB_DESC], %o0
5515          call      _C_LABEL(pmap_setup_tsb_sun4v)
5516           nop
5517          ba        1f
5518           nop
55195:
5520#endif
5521          /* sun4u */
5522          sethi     %hi(_C_LABEL(tsbsize)), %l2
5523          sethi     %hi(0x1fff), %l3
5524          sethi     %hi(TSB), %l4
5525          LDPTR     [%l7 + CI_TSB_DMMU], %l0
5526          LDPTR     [%l7 + CI_TSB_IMMU], %l1
5527          ld        [%l2 + %lo(_C_LABEL(tsbsize))], %l2
5528          or        %l3, %lo(0x1fff), %l3
5529          or        %l4, %lo(TSB), %l4
5530
5531          andn      %l0, %l3, %l0                           ! Mask off size and split bits
5532          or        %l0, %l2, %l0                           ! Make a TSB pointer
5533          stxa      %l0, [%l4] ASI_DMMU           ! Install data TSB pointer
5534
5535          andn      %l1, %l3, %l1                           ! Mask off size and split bits
5536          or        %l1, %l2, %l1                           ! Make a TSB pointer
5537          stxa      %l1, [%l4] ASI_IMMU           ! Install instruction TSB pointer
5538          membar    #Sync
5539          set       1f, %l1
5540          flush     %l1
55411:
5542
5543          /* set trap table */
5544#ifdef SUN4V
5545          cmp       %l6, CPU_SUN4V
5546          bne,pt    %icc, 6f
5547           nop
5548          /* sun4v */
5549          set       _C_LABEL(trapbase_sun4v), %l1
5550          GET_MMFSA %o1
5551          call      _C_LABEL(prom_set_trap_table_sun4v)     ! Now we should be running 100% from our handlers
5552           mov      %l1, %o0
5553
5554          ba        7f
5555           nop
55566:
5557#endif
5558          /* sun4u */
5559          set       _C_LABEL(trapbase), %l1
5560          call      _C_LABEL(prom_set_trap_table_sun4u)     ! Now we should be running 100% from our handlers
5561           mov      %l1, %o0
55627:
5563          wrpr      %l1, 0, %tba                            ! Make sure the PROM didn't foul up.
5564
5565          /*
5566           * Switch to the kernel mode and run away.
5567           */
5568          wrpr      %g0, WSTATE_KERN, %wstate
5569
5570#ifdef DEBUG
5571          wrpr      %g0, 1, %tl                             ! Debug -- start at tl==3 so we'll watchdog
5572          wrpr      %g0, 0x1ff, %tt                         ! Debug -- clear out unused trap regs
5573          wrpr      %g0, 0, %tpc
5574          wrpr      %g0, 0, %tnpc
5575          wrpr      %g0, 0, %tstate
5576          wrpr      %g0, 0, %tl
5577#endif
5578
5579#ifdef DEBUG
5580          set       _C_LABEL(pmapdebug), %o1
5581          ld        [%o1], %o1
5582          sethi     %hi(0x40000), %o2
5583          btst      %o2, %o1
5584          bz        0f
5585
5586          LDPTR     [%l7 + CI_SPINUP], %o1
5587          set       1f, %o0             ! Debug printf
5588          call      _C_LABEL(prom_printf)
5589           mov      %sp, %o2
5590
5591          .data
55921:
5593          .asciz    "Calling startup routine %p with stack at %p...\n"
5594          _ALIGN
5595          .text
55960:
5597#endif
5598          /*
5599           * Call our startup routine.
5600           */
5601
5602          LDPTR     [%l7 + CI_SPINUP], %o1
5603
5604          call      %o1                                     ! Call routine
5605           clr      %o0                                     ! our frame arg is ignored
5606
5607          set       1f, %o0                                 ! Main should never come back here
5608          call      _C_LABEL(panic)
5609           nop
5610          .data
56111:
5612          .asciz    "main() returned\n"
5613          _ALIGN
5614          .text
5615
5616          .align 8
5617ENTRY(get_romtba)
5618          retl
5619           rdpr     %tba, %o0
5620
5621ENTRY(setcputyp)
5622          sethi     %hi(cputyp), %o1    ! Trash %o1 assuming this is ok
5623          st        %o0, [%o1 + %lo(cputyp)]
5624          retl
5625           nop
5626
5627#ifdef MULTIPROCESSOR
5628          /*
5629           * cpu_mp_startup is called with:
5630           *
5631           *        %g2 = cpu_args
5632           */
5633ENTRY(cpu_mp_startup)
5634          mov       1, %o0
5635          sllx      %o0, 63, %o0
5636          wr        %o0, TICK_CMPR      ! XXXXXXX clear and disable %tick_cmpr for now
5637          wrpr    %g0, 0, %cleanwin
5638          wrpr      %g0, 0, %tl                             ! Make sure we're not in NUCLEUS mode
5639          wrpr      %g0, WSTATE_KERN, %wstate
5640          wrpr      %g0, PSTATE_KERN, %pstate
5641          flushw
5642
5643          /* Cache the cputyp in %l6 for later use below */
5644          sethi     %hi(cputyp), %l6
5645          ld        [%l6 + %lo(cputyp)], %l6
5646
5647          /*
5648           * Get pointer to our cpu_info struct
5649           */
5650          ldx       [%g2 + CBA_CPUINFO], %l1      ! Load the interrupt stack's PA
5651
5652#ifdef SUN4V
5653          cmp       %l6, CPU_SUN4V
5654          bne,pt    %icc, 3f
5655           nop
5656
5657          /* sun4v */
5658
5659          sethi     %hi(0x80000000), %l2                    ! V=1|NFO=0|SW=0
5660          sllx      %l2, 32, %l2                            ! Shift it into place
5661          mov       -1, %l3                                 ! Create a nice mask
5662          sllx      %l3, 56, %l4                            ! Mask off high 8 bits
5663          or        %l4, 0xfff, %l4                         ! We can just load this in 12 (of 13) bits
5664          andn      %l1, %l4, %l1                           ! Mask the phys page number into RA
5665          or        %l2, %l1, %l1                           ! Now take care of the 8 high bits V|NFO|SW
5666          or        %l1, 0x0741, %l2              ! And low 13 bits IE=0|E=0|CP=1|CV=1|P=1|
5667                                                            !                     X=0|W=1|SW=00|SZ=0001
5668
5669          /*
5670           *  Now, map in the interrupt stack & cpu_info as context==0
5671           */
5672
5673          set       INTSTACK, %o0                           ! vaddr
5674          clr       %o1                                     ! reserved
5675          mov       %l2, %o2                      ! tte
5676          mov       MAP_DTLB, %o3                           ! flags
5677          mov       FT_MMU_MAP_PERM_ADDR, %o5     ! hv fast trap function
5678          ta        ST_FAST_TRAP
5679          cmp       %o0, 0
5680          be,pt     %icc, 5f
5681           nop
5682          sir                                               ! crash if mapping fails
56835:
5684
5685          /*
5686           * Set 0 as primary context XXX
5687           */
5688
5689          mov       CTX_PRIMARY, %o0
5690          SET_MMU_CONTEXTID_SUN4V %g0, %o0
5691
5692          ba        4f
5693           nop
56943:
5695#endif
5696
5697          /* sun4u */
5698
5699          sethi     %hi(0xa0000000), %l2                    ! V=1|SZ=01|NFO=0|IE=0
5700          sllx      %l2, 32, %l2                            ! Shift it into place
5701          mov       -1, %l3                                 ! Create a nice mask
5702          sllx      %l3, 43, %l4                            ! Mask off high bits
5703          or        %l4, 0xfff, %l4                         ! We can just load this in 12 (of 13) bits
5704          andn      %l1, %l4, %l1                           ! Mask the phys page number
5705          or        %l2, %l1, %l1                           ! Now take care of the high bits
5706          or        %l1, SUN4U_TTE_DATABITS, %l2  ! And low bits:     L=1|CP=1|CV=?|E=0|P=1|W=1|G=0
5707
5708          /*
5709           *  Now, map in the interrupt stack & cpu_info as context==0
5710           */
5711
5712          set       TLB_TAG_ACCESS, %l5
5713          set       INTSTACK, %l0
5714          stxa      %l0, [%l5] ASI_DMMU           ! Make DMMU point to it
5715          stxa      %l2, [%g0] ASI_DMMU_DATA_IN   ! Store it
5716
5717          /*
5718           * Set 0 as primary context XXX
5719           */
5720
5721          mov       CTX_PRIMARY, %o0
5722          SET_MMU_CONTEXTID_SUN4U %g0, %o0
5723
57244:
5725          membar    #Sync
5726
5727          /*
5728           * Temporarily use the interrupt stack
5729           */
5730#ifdef _LP64
5731          set       ((EINTSTACK - CC64FSZ - TF_SIZE)) & ~0x0f - BIAS, %sp
5732#else
5733          set       EINTSTACK - CC64FSZ - TF_SIZE, %sp
5734#endif
5735          set       1, %fp
5736          clr       %i7
5737
5738#ifdef SUN4V
5739          cmp       %l6, CPU_SUN4V
5740          bne,pt    %icc, 2f
5741           nop
5742
5743          /* sun4v */
5744
5745          /*
5746           * install our TSB pointers
5747           */
5748
5749          set       CPUINFO_VA, %o0
5750          LDPTR     [%o0 + CI_TSB_DESC], %o0
5751          call      _C_LABEL(pmap_setup_tsb_sun4v)
5752           nop
5753
5754          /* set trap table */
5755
5756          set       _C_LABEL(trapbase_sun4v), %l1
5757          GET_MMFSA %o1
5758          call      _C_LABEL(prom_set_trap_table_sun4v)
5759           mov      %l1, %o0
5760
5761          ! Now we should be running 100% from our handlers
5762          ba        3f
5763           nop
57642:
5765#endif
5766          /* sun4u */
5767
5768          /*
5769           * install our TSB pointers
5770           */
5771
5772          sethi     %hi(CPUINFO_VA+CI_TSB_DMMU), %l0
5773          sethi     %hi(CPUINFO_VA+CI_TSB_IMMU), %l1
5774          sethi     %hi(_C_LABEL(tsbsize)), %l2
5775          sethi     %hi(0x1fff), %l3
5776          sethi     %hi(TSB), %l4
5777          LDPTR     [%l0 + %lo(CPUINFO_VA+CI_TSB_DMMU)], %l0
5778          LDPTR     [%l1 + %lo(CPUINFO_VA+CI_TSB_IMMU)], %l1
5779          ld        [%l2 + %lo(_C_LABEL(tsbsize))], %l2
5780          or        %l3, %lo(0x1fff), %l3
5781          or        %l4, %lo(TSB), %l4
5782
5783          andn      %l0, %l3, %l0                           ! Mask off size and split bits
5784          or        %l0, %l2, %l0                           ! Make a TSB pointer
5785          stxa      %l0, [%l4] ASI_DMMU           ! Install data TSB pointer
5786          membar    #Sync
5787
5788          andn      %l1, %l3, %l1                           ! Mask off size and split bits
5789          or        %l1, %l2, %l1                           ! Make a TSB pointer
5790          stxa      %l1, [%l4] ASI_IMMU           ! Install instruction TSB pointer
5791          membar    #Sync
5792          set       1f, %o0
5793          flush     %o0
57941:
5795
5796          /* set trap table */
5797
5798          set       _C_LABEL(trapbase), %l1
5799          call      _C_LABEL(prom_set_trap_table_sun4u)
5800           mov      %l1, %o0
58013:
5802          wrpr      %l1, 0, %tba                            ! Make sure the PROM didn't
5803                                                            ! foul up.
5804          /*
5805           * Use this CPUs idlelewp's uarea stack
5806           */
5807          sethi     %hi(CPUINFO_VA+CI_IDLELWP), %l0
5808          LDPTR     [%l0 + %lo(CPUINFO_VA+CI_IDLELWP)], %l0
5809          set       USPACE - TF_SIZE - CC64FSZ, %l1
5810          LDPTR     [%l0 + L_PCB], %l0
5811          add       %l0, %l1, %l0
5812#ifdef _LP64
5813          andn      %l0, 0x0f, %l0                          ! Needs to be 16-byte aligned
5814          sub       %l0, BIAS, %l0                          ! and biased
5815#endif
5816          mov       %l0, %sp
5817          flushw
5818
5819          /*
5820           * Switch to the kernel mode and run away.
5821           */
5822          wrpr      %g0, 13, %pil
5823          wrpr      %g0, PSTATE_INTR|PSTATE_PEF, %pstate
5824          wr        %g0, FPRS_FEF, %fprs                              ! Turn on FPU
5825
5826          call      _C_LABEL(cpu_hatch)
5827           clr %g4
5828
5829          b         _C_LABEL(idle_loop)
5830           clr      %o0
5831
5832          NOTREACHED
5833
5834          .globl cpu_mp_startup_end
5835cpu_mp_startup_end:
5836#endif
5837
5838/*
5839 * openfirmware(cell* param);
5840 *
5841 * OpenFirmware entry point
5842 *
5843 * If we're running in 32-bit mode we need to convert to a 64-bit stack
5844 * and 64-bit cells.  The cells we'll allocate off the stack for simplicity.
5845 */
5846          .align 8
5847ENTRY(openfirmware)
5848          sethi     %hi(romp), %o4
5849          andcc     %sp, 1, %g0
5850          bz,pt     %icc, 1f
5851           LDPTR    [%o4+%lo(romp)], %o4                    ! v9 stack, just load the addr and callit
5852          save      %sp, -CC64FSZ, %sp
5853          rdpr      %pil, %i2
5854          mov       PIL_HIGH, %i3
5855          cmp       %i3, %i2
5856          movle     %icc, %i2, %i3
5857          wrpr      %g0, %i3, %pil
5858          mov       %i0, %o0
5859          mov       %g1, %l1
5860          mov       %g2, %l2
5861          mov       %g3, %l3
5862          mov       %g4, %l4
5863          mov       %g5, %l5
5864          mov       %g6, %l6
5865          mov       %g7, %l7
5866          rdpr      %pstate, %l0
5867          jmpl      %i4, %o7
5868#if !defined(_LP64)
5869           wrpr     %g0, PSTATE_PROM, %pstate
5870#else
5871           wrpr     %g0, PSTATE_PROM|PSTATE_IE, %pstate
5872#endif
5873          wrpr      %l0, %g0, %pstate
5874          mov       %l1, %g1
5875          mov       %l2, %g2
5876          mov       %l3, %g3
5877          mov       %l4, %g4
5878          mov       %l5, %g5
5879          mov       %l6, %g6
5880          mov       %l7, %g7
5881          wrpr      %i2, 0, %pil
5882          ret
5883           restore  %o0, %g0, %o0
5884
58851:        ! v8 -- need to screw with stack & params
5886#ifdef NOTDEF_DEBUG
5887          mov       %o7, %o5
5888          call      globreg_check
5889           nop
5890          mov       %o5, %o7
5891#endif
5892          save      %sp, -CC64FSZ, %sp            ! Get a new 64-bit stack frame
5893          add       %sp, -BIAS, %sp
5894          rdpr      %pstate, %l0
5895          srl       %sp, 0, %sp
5896          rdpr      %pil, %i2 ! s = splx(level)
5897          mov       %i0, %o0
5898          mov       PIL_HIGH, %i3
5899          mov       %g1, %l1
5900          mov       %g2, %l2
5901          cmp       %i3, %i2
5902          mov       %g3, %l3
5903          mov       %g4, %l4
5904          mov       %g5, %l5
5905          movle     %icc, %i2, %i3
5906          mov       %g6, %l6
5907          mov       %g7, %l7
5908          wrpr      %i3, %g0, %pil
5909          jmpl      %i4, %o7
5910          ! Enable 64-bit addresses for the prom
5911#if defined(_LP64)
5912           wrpr     %g0, PSTATE_PROM, %pstate
5913#else
5914           wrpr     %g0, PSTATE_PROM|PSTATE_IE, %pstate
5915#endif
5916          wrpr      %l0, 0, %pstate
5917          wrpr      %i2, 0, %pil
5918          mov       %l1, %g1
5919          mov       %l2, %g2
5920          mov       %l3, %g3
5921          mov       %l4, %g4
5922          mov       %l5, %g5
5923          mov       %l6, %g6
5924          mov       %l7, %g7
5925          ret
5926           restore  %o0, %g0, %o0
5927
5928/*
5929 * void ofw_exit(cell_t args[])
5930 */
5931ENTRY(openfirmware_exit)
5932          STACKFRAME(-CC64FSZ)
5933          flushw                                            ! Flush register windows
5934
5935          wrpr      %g0, PIL_HIGH, %pil           ! Disable interrupts
5936          sethi     %hi(romtba), %l5
5937          LDPTR     [%l5 + %lo(romtba)], %l5
5938          wrpr      %l5, 0, %tba                            ! restore the ofw trap table
5939
5940          /* Arrange locked kernel stack as PROM stack */
5941          set       EINTSTACK  - CC64FSZ, %l5
5942
5943          andn      %l5, 0x0f, %l5                          ! Needs to be 16-byte aligned
5944          sub       %l5, BIAS, %l5                          ! and biased
5945          mov       %l5, %sp
5946          flushw
5947
5948          sethi     %hi(romp), %l6
5949          LDPTR     [%l6 + %lo(romp)], %l6
5950
5951          mov     CTX_PRIMARY, %l3                ! set context 0
5952          stxa    %g0, [%l3] ASI_DMMU
5953          membar    #Sync
5954
5955          wrpr      %g0, PSTATE_PROM, %pstate     ! Disable interrupts
5956                                                            ! and enable 64-bit addresses
5957          wrpr      %g0, 0, %tl                             ! force trap level 0
5958          call      %l6
5959           mov      %i0, %o0
5960          NOTREACHED
5961
5962/*
5963 * sp_tlb_flush_pte_us(vaddr_t va, int ctx)
5964 * sp_tlb_flush_pte_usiii(vaddr_t va, int ctx)
5965 *
5966 * Flush tte from both IMMU and DMMU.
5967 *
5968 * This uses %o0-%o5
5969 */
5970          .align 8
5971ENTRY(sp_tlb_flush_pte_us)
5972#ifdef DEBUG
5973          set       pmapdebug, %o3
5974          lduw      [%o3], %o3
5975!         movrz     %o1, -1, %o3                                      ! Print on either pmapdebug & PDB_DEMAP or ctx == 0
5976          btst      0x0020, %o3
5977          bz,pt     %icc, 2f
5978           nop
5979          save      %sp, -CC64FSZ, %sp
5980          set       1f, %o0
5981          mov       %i1, %o1
5982          andn      %i0, 0xfff, %o3
5983          or        %o3, 0x010, %o3
5984          call      _C_LABEL(printf)
5985           mov      %i0, %o2
5986          restore
5987          .data
59881:
5989          .asciz    "sp_tlb_flush_pte_us:         demap ctx=%x va=%08x res=%x\n"
5990          _ALIGN
5991          .text
59922:
5993#endif
5994#ifdef MULTIPROCESSOR
5995          rdpr      %pstate, %o3
5996          andn      %o3, PSTATE_IE, %o4                     ! disable interrupts
5997          wrpr      %o4, 0, %pstate
5998#endif
5999          srlx      %o0, PG_SHIFT4U, %o0                              ! drop unused va bits
6000          mov       CTX_SECONDARY, %o2
6001          sllx      %o0, PG_SHIFT4U, %o0
6002          ldxa      [%o2] ASI_DMMU, %o5                     ! Save secondary context
6003          sethi     %hi(KERNBASE), %o4
6004          membar    #LoadStore
6005          stxa      %o1, [%o2] ASI_DMMU                     ! Insert context to demap
6006          membar    #Sync
6007          or        %o0, DEMAP_PAGE_SECONDARY, %o0                    ! Demap page from secondary context only
6008          stxa      %o0, [%o0] ASI_DMMU_DEMAP               ! Do the demap
6009          stxa      %o0, [%o0] ASI_IMMU_DEMAP               ! to both TLBs
6010#ifdef TLB_FLUSH_LOWVA
6011          srl       %o0, 0, %o0                                       ! and make sure it's both 32- and 64-bit entries
6012          stxa      %o0, [%o0] ASI_DMMU_DEMAP               ! Do the demap
6013          stxa      %o0, [%o0] ASI_IMMU_DEMAP               ! Do the demap
6014#endif
6015          flush     %o4
6016          stxa      %o5, [%o2] ASI_DMMU                     ! Restore secondary context
6017          membar    #Sync
6018          retl
6019#ifdef MULTIPROCESSOR
6020           wrpr     %o3, %pstate                                      ! restore interrupts
6021#else
6022           nop
6023#endif
6024
6025ENTRY(sp_tlb_flush_pte_usiii)
6026#ifdef DEBUG
6027          set       pmapdebug, %o3
6028          lduw      [%o3], %o3
6029!         movrz     %o1, -1, %o3                                      ! Print on either pmapdebug & PDB_DEMAP or ctx == 0
6030          btst      0x0020, %o3
6031          bz,pt     %icc, 2f
6032           nop
6033          save      %sp, -CC64FSZ, %sp
6034          set       1f, %o0
6035          mov       %i1, %o1
6036          andn      %i0, 0xfff, %o3
6037          or        %o3, 0x010, %o3
6038          call      _C_LABEL(printf)
6039           mov      %i0, %o2
6040          restore
6041          .data
60421:
6043          .asciz    "sp_tlb_flush_pte_usiii:      demap ctx=%x va=%08x res=%x\n"
6044          _ALIGN
6045          .text
60462:
6047#endif
6048          ! %o0 = VA [in]
6049          ! %o1 = ctx value [in] / KERNBASE
6050          ! %o2 = CTX_PRIMARY
6051          ! %o3 = saved %tl
6052          ! %o4 = saved %pstate
6053          ! %o5 = saved primary ctx
6054
6055          ! Need this for UP as well
6056          rdpr      %pstate, %o4
6057          andn      %o4, PSTATE_IE, %o3                     ! disable interrupts
6058          wrpr      %o3, 0, %pstate
6059
6060          !!
6061          !! Cheetahs do not support flushing the IMMU from secondary context
6062          !!
6063          rdpr      %tl, %o3
6064          mov       CTX_PRIMARY, %o2
6065          brnz,pt   %o3, 1f
6066           andn     %o0, 0xfff, %o0                                   ! drop unused va bits
6067          wrpr      %g0, 1, %tl                                       ! Make sure we're NUCLEUS
60681:
6069          ldxa      [%o2] ASI_DMMU, %o5                     ! Save primary context
6070          membar    #LoadStore
6071          stxa      %o1, [%o2] ASI_DMMU                     ! Insert context to demap
6072          sethi     %hi(KERNBASE), %o1
6073          membar    #Sync
6074          or        %o0, DEMAP_PAGE_PRIMARY, %o0
6075          stxa      %o0, [%o0] ASI_DMMU_DEMAP               ! Do the demap
6076          membar    #Sync
6077          stxa      %o0, [%o0] ASI_IMMU_DEMAP               ! to both TLBs
6078          membar    #Sync
6079#ifdef TLB_FLUSH_LOWVA
6080          srl       %o0, 0, %o0                                       ! and make sure it's both 32- and 64-bit entries
6081          stxa      %o0, [%o0] ASI_DMMU_DEMAP               ! Do the demap
6082          membar    #Sync
6083          stxa      %o0, [%o0] ASI_IMMU_DEMAP               ! Do the demap
6084          membar    #Sync
6085#endif
6086          flush     %o1
6087          stxa      %o5, [%o2] ASI_DMMU                     ! Restore primary context
6088          membar    #Sync
6089          brnz,pt   %o3, 1f
6090           flush    %o1
6091          wrpr      %g0, %o3, %tl                                     ! Return to kernel mode.
60921:
6093          retl
6094           wrpr     %o4, %pstate                                      ! restore interrupts
6095
6096
6097/*
6098 * sp_tlb_flush_all_us(void)
6099 * sp_tlb_flush_all_usiii(void)
6100 *
6101 * Flush all user TLB entries from both IMMU and DMMU.
6102 * We have both UltraSPARC I+II, and UltraSPARC >=III versions.
6103 */
6104          .align 8
6105ENTRY(sp_tlb_flush_all_us)
6106          rdpr      %pstate, %o3
6107          andn      %o3, PSTATE_IE, %o4                     ! disable interrupts
6108          wrpr      %o4, 0, %pstate
6109          set       ((TLB_SIZE_SPITFIRE-1) * 8), %o0
6110          set       CTX_SECONDARY, %o4
6111          ldxa      [%o4] ASI_DMMU, %o4                     ! save secondary context
6112          set       CTX_MASK, %o5
6113          membar    #Sync
6114
6115          ! %o0 = loop counter
6116          ! %o1 = ctx value
6117          ! %o2 = TLB tag value
6118          ! %o3 = saved %pstate
6119          ! %o4 = saved primary ctx
6120          ! %o5 = CTX_MASK
6121          ! %xx = saved %tl
6122
61230:
6124          ldxa      [%o0] ASI_DMMU_TLB_TAG, %o2             ! fetch the TLB tag
6125          andcc     %o2, %o5, %o1                                     ! context 0?
6126          bz,pt     %xcc, 1f                                ! if so, skip
6127           mov      CTX_SECONDARY, %o2
6128
6129          stxa      %o1, [%o2] ASI_DMMU                     ! set the context
6130          set       DEMAP_CTX_SECONDARY, %o2
6131          membar    #Sync
6132          stxa      %o2, [%o2] ASI_DMMU_DEMAP               ! do the demap
6133          membar    #Sync
6134
61351:
6136          dec       8, %o0
6137          brgz,pt %o0, 0b                                             ! loop over all entries
6138           nop
6139
6140/*
6141 * now do the IMMU
6142 */
6143
6144          set       ((TLB_SIZE_SPITFIRE-1) * 8), %o0
6145
61460:
6147          ldxa      [%o0] ASI_IMMU_TLB_TAG, %o2             ! fetch the TLB tag
6148          andcc     %o2, %o5, %o1                                     ! context 0?
6149          bz,pt     %xcc, 1f                                ! if so, skip
6150           mov      CTX_SECONDARY, %o2
6151
6152          stxa      %o1, [%o2] ASI_DMMU                     ! set the context
6153          set       DEMAP_CTX_SECONDARY, %o2
6154          membar    #Sync
6155          stxa      %o2, [%o2] ASI_IMMU_DEMAP               ! do the demap
6156          membar    #Sync
6157
61581:
6159          dec       8, %o0
6160          brgz,pt %o0, 0b                                             ! loop over all entries
6161           nop
6162
6163          set       CTX_SECONDARY, %o2
6164          stxa      %o4, [%o2] ASI_DMMU                     ! restore secondary ctx
6165          sethi     %hi(KERNBASE), %o4
6166          membar    #Sync
6167          flush     %o4
6168          retl
6169           wrpr     %o3, %pstate
6170
6171          .align 8
6172ENTRY(sp_tlb_flush_all_usiii)
6173          rdpr      %tl, %o5
6174          brnz,pt   %o5, 1f
6175           set      DEMAP_ALL, %o2
6176          wrpr      1, %tl
61771:
6178          rdpr      %pstate, %o3
6179          andn      %o3, PSTATE_IE, %o4                     ! disable interrupts
6180          wrpr      %o4, 0, %pstate
6181
6182          stxa      %o2, [%o2] ASI_IMMU_DEMAP
6183          membar    #Sync
6184          stxa      %o2, [%o2] ASI_DMMU_DEMAP
6185
6186          sethi     %hi(KERNBASE), %o4
6187          membar    #Sync
6188          flush     %o4
6189
6190          wrpr      %o5, %tl
6191          retl
6192           wrpr     %o3, %pstate
6193
6194/*
6195 * sp_blast_dcache(int dcache_size, int dcache_line_size)
6196 * sp_blast_dcache_disabled(int dcache_size, int dcache_line_size)
6197 *
6198 * Clear out all of D$ regardless of contents.  The latter one also
6199 * disables the D$ while doing so.
6200 */
6201          .align 8
6202ENTRY(sp_blast_dcache)
6203/*
6204 * We turn off interrupts for the duration to prevent RED exceptions.
6205 */
6206#ifdef PROF
6207          save      %sp, -CC64FSZ, %sp
6208#endif
6209
6210          rdpr      %pstate, %o3
6211          sub       %o0, %o1, %o0
6212          andn      %o3, PSTATE_IE, %o4                     ! Turn off PSTATE_IE bit
6213          wrpr      %o4, 0, %pstate
62141:
6215          stxa      %g0, [%o0] ASI_DCACHE_TAG
6216          membar    #Sync
6217          brnz,pt   %o0, 1b
6218           sub      %o0, %o1, %o0
6219
6220          sethi     %hi(KERNBASE), %o2
6221          flush     %o2
6222          membar    #Sync
6223#ifdef PROF
6224          wrpr      %o3, %pstate
6225          ret
6226           restore
6227#else
6228          retl
6229           wrpr     %o3, %pstate
6230#endif
6231
6232          .align 8
6233ENTRY(sp_blast_dcache_disabled)
6234/*
6235 * We turn off interrupts for the duration to prevent RED exceptions.
6236 */
6237#ifdef PROF
6238          save      %sp, -CC64FSZ, %sp
6239#endif
6240
6241          rdpr      %pstate, %o3
6242          sub       %o0, %o1, %o0
6243          andn      %o3, PSTATE_IE, %o4                     ! Turn off PSTATE_IE bit
6244          wrpr      %o4, 0, %pstate
6245
6246          ldxa    [%g0] ASI_MCCR, %o5
6247          andn      %o5, MCCR_DCACHE_EN, %o4                ! Turn off the D$
6248          stxa      %o4, [%g0] ASI_MCCR
6249          flush     %g0
6250
62511:
6252          stxa      %g0, [%o0] ASI_DCACHE_TAG
6253          membar    #Sync
6254          brnz,pt   %o0, 1b
6255           sub      %o0, %o1, %o0
6256
6257          sethi     %hi(KERNBASE), %o2
6258          flush     %o2
6259          membar    #Sync
6260
6261          stxa      %o5, [%g0] ASI_MCCR                     ! Restore the D$
6262          flush     %g0
6263#ifdef PROF
6264          wrpr      %o3, %pstate
6265          ret
6266           restore
6267#else
6268          retl
6269           wrpr     %o3, %pstate
6270#endif
6271
6272#ifdef MULTIPROCESSOR
6273/*
6274 * void sparc64_ipi_blast_dcache(int dcache_size, int dcache_line_size)
6275 *
6276 * Clear out all of D$ regardless of contents
6277 *
6278 * On entry:
6279 *        %g2 = dcache_size
6280 *        %g3 = dcache_line_size
6281 */
6282          .align 8
6283ENTRY(sparc64_ipi_blast_dcache)
6284          sub       %g2, %g3, %g2
62851:
6286          stxa      %g0, [%g2] ASI_DCACHE_TAG
6287          membar    #Sync
6288          brnz,pt   %g2, 1b
6289           sub      %g2, %g3, %g2
6290
6291          sethi     %hi(KERNBASE), %g5
6292          flush     %g5
6293          membar    #Sync
6294
6295          ba,a      ret_from_intr_vector
6296           nop
6297#endif /* MULTIPROCESSOR */
6298
6299/*
6300 * blast_icache_us()
6301 * blast_icache_usiii()
6302 *
6303 * Clear out all of I$ regardless of contents
6304 * Does not modify %o0
6305 *
6306 * We turn off interrupts for the duration to prevent RED exceptions.
6307 * For the Cheetah version, we also have to to turn off the I$ during this as
6308 * ASI_ICACHE_TAG accesses interfere with coherency.
6309 */
6310          .align 8
6311ENTRY(blast_icache_us)
6312          rdpr      %pstate, %o3
6313          sethi     %hi(icache_size), %o1
6314          ld        [%o1 + %lo(icache_size)], %o1
6315          sethi     %hi(icache_line_size), %o2
6316          ld        [%o2 + %lo(icache_line_size)], %o2
6317          sub       %o1, %o2, %o1
6318          andn      %o3, PSTATE_IE, %o4                     ! Turn off PSTATE_IE bit
6319          wrpr      %o4, 0, %pstate
63201:
6321          stxa      %g0, [%o1] ASI_ICACHE_TAG
6322          brnz,pt   %o1, 1b
6323           sub      %o1, %o2, %o1
6324          sethi     %hi(KERNBASE), %o5
6325          flush     %o5
6326          membar    #Sync
6327          retl
6328           wrpr     %o3, %pstate
6329
6330          .align 8
6331ENTRY(blast_icache_usiii)
6332          rdpr      %pstate, %o3
6333          sethi     %hi(icache_size), %o1
6334          ld        [%o1 + %lo(icache_size)], %o1
6335          sethi     %hi(icache_line_size), %o2
6336          ld        [%o2 + %lo(icache_line_size)], %o2
6337          sub       %o1, %o2, %o1
6338          andn      %o3, PSTATE_IE, %o4                     ! Turn off PSTATE_IE bit
6339          wrpr      %o4, 0, %pstate
6340          ldxa    [%g0] ASI_MCCR, %o5
6341          andn      %o5, MCCR_ICACHE_EN, %o4                ! Turn off the I$
6342          stxa      %o4, [%g0] ASI_MCCR
6343          flush     %g0
63441:
6345          stxa      %g0, [%o1] ASI_ICACHE_TAG
6346          membar    #Sync
6347          brnz,pt   %o1, 1b
6348           sub      %o1, %o2, %o1
6349          stxa      %o5, [%g0] ASI_MCCR                     ! Restore the I$
6350          flush     %g0
6351          retl
6352           wrpr     %o3, %pstate
6353
6354/*
6355 * dcache_flush_page_us(paddr_t pa)
6356 * dcache_flush_page_usiii(paddr_t pa)
6357 *
6358 * Clear one page from D$.
6359 *
6360 */
6361          .align 8
6362ENTRY(dcache_flush_page_us)
6363#ifndef _LP64
6364          COMBINE(%o0, %o1, %o0)
6365#endif
6366          mov       -1, %o1             ! Generate mask for tag: bits [29..2]
6367          srlx      %o0, 13-2, %o2      ! Tag is PA bits <40:13> in bits <29:2>
6368          clr       %o4
6369          srl       %o1, 2, %o1         ! Now we have bits <29:0> set
6370          set       (2*NBPG), %o5
6371          ba,pt     %icc, 1f
6372           andn     %o1, 3, %o1         ! Now we have bits <29:2> set
6373
6374          .align 8
63751:
6376          ldxa      [%o4] ASI_DCACHE_TAG, %o3
6377          mov       %o4, %o0
6378          deccc     32, %o5
6379          bl,pn     %icc, 2f
6380           inc      32, %o4
6381
6382          xor       %o3, %o2, %o3
6383          andcc     %o3, %o1, %g0
6384          bne,pt    %xcc, 1b
6385           membar   #LoadStore
6386
6387          stxa      %g0, [%o0] ASI_DCACHE_TAG
6388          ba,pt     %icc, 1b
6389           membar   #StoreLoad
63902:
6391
6392          sethi     %hi(KERNBASE), %o5
6393          flush     %o5
6394          retl
6395           membar   #Sync
6396
6397          .align 8
6398ENTRY(dcache_flush_page_usiii)
6399#ifndef _LP64
6400          COMBINE(%o0, %o1, %o0)
6401#endif
6402          set       NBPG, %o1
6403          sethi     %hi(dcache_line_size), %o2
6404          add       %o0, %o1, %o1       ! end address
6405          ld        [%o2 + %lo(dcache_line_size)], %o2
6406
64071:
6408          stxa      %g0, [%o0] ASI_DCACHE_INVALIDATE
6409          add       %o0, %o2, %o0
6410          cmp       %o0, %o1
6411          bl,pt     %xcc, 1b
6412           nop
6413
6414          sethi     %hi(KERNBASE), %o5
6415          flush     %o5
6416          retl
6417           membar   #Sync
6418
6419/*
6420 *        cache_flush_phys_us(paddr_t, psize_t, int);
6421 *        cache_flush_phys_usiii(paddr_t, psize_t, int);
6422 *
6423 *        Clear a set of paddrs from the D$, I$ and if param3 is
6424 *        non-zero, E$.  (E$ is not supported yet).
6425 */
6426
6427          .align 8
6428ENTRY(cache_flush_phys_us)
6429#ifndef _LP64
6430          COMBINE(%o0, %o1, %o0)
6431          COMBINE(%o2, %o3, %o1)
6432          mov       %o4, %o2
6433#endif
6434#ifdef DEBUG
6435          tst       %o2                 ! Want to clear E$?
6436          tnz       1                   ! Error!
6437#endif
6438          add       %o0, %o1, %o1       ! End PA
6439          dec       %o1
6440
6441          !!
6442          !! Both D$ and I$ tags match pa bits 42-13, but
6443          !! they are shifted different amounts.  So we'll
6444          !! generate a mask for bits 40-13.
6445          !!
6446
6447          mov       -1, %o2             ! Generate mask for tag: bits [40..13]
6448          srl       %o2, 5, %o2         ! 32-5 = [27..0]
6449          sllx      %o2, 13, %o2        ! 27+13 = [40..13]
6450
6451          and       %o2, %o0, %o0       ! Mask away uninteresting bits
6452          and       %o2, %o1, %o1       ! (probably not necessary)
6453
6454          set       (2*NBPG), %o5
6455          clr       %o4
64561:
6457          ldxa      [%o4] ASI_DCACHE_TAG, %o3
6458          sllx      %o3, 40-29, %o3     ! Shift D$ tag into place
6459          and       %o3, %o2, %o3       ! Mask out trash
6460
6461          cmp       %o0, %o3
6462          blt,pt    %xcc, 2f  ! Too low
6463           cmp      %o1, %o3
6464          bgt,pt    %xcc, 2f  ! Too high
6465           nop
6466
6467          membar    #LoadStore
6468          stxa      %g0, [%o4] ASI_DCACHE_TAG ! Just right
6469          membar    #Sync
64702:
6471          ldda      [%o4] ASI_ICACHE_TAG, %g0     ! Tag goes in %g1
6472          sllx      %g1, 40-35, %g1                         ! Shift I$ tag into place
6473          and       %g1, %o2, %g1                           ! Mask out trash
6474          cmp       %o0, %g1
6475          blt,pt    %xcc, 3f
6476           cmp      %o1, %g1
6477          bgt,pt    %xcc, 3f
6478           nop
6479          stxa      %g0, [%o4] ASI_ICACHE_TAG
64803:
6481          membar    #StoreLoad
6482          dec       32, %o5
6483          brgz,pt   %o5, 1b
6484           inc      32, %o4
6485
6486          sethi     %hi(KERNBASE), %o5
6487          flush     %o5
6488          retl
6489           membar   #Sync
6490
6491          .align 8
6492ENTRY(cache_flush_phys_usiii)
6493#ifndef _LP64
6494          COMBINE(%o0, %o1, %o0)
6495          COMBINE(%o2, %o3, %o1)
6496          mov       %o4, %o2
6497#endif
6498#ifdef DEBUG
6499          tst       %o2                 ! Want to clear E$?
6500          tnz       1                   ! Error!
6501#endif
6502          add       %o0, %o1, %o1       ! End PA
6503          sethi     %hi(dcache_line_size), %o3
6504          ld        [%o3 + %lo(dcache_line_size)], %o3
6505          sethi     %hi(KERNBASE), %o5
65061:
6507          stxa      %g0, [%o0] ASI_DCACHE_INVALIDATE
6508          add       %o0, %o3, %o0
6509          cmp       %o0, %o1
6510          bl,pt     %xcc, 1b
6511           nop
6512
6513          /* don't need to flush the I$ on cheetah */
6514
6515          flush     %o5
6516          retl
6517           membar   #Sync
6518
6519#ifdef COMPAT_16
6520#ifdef _LP64
6521/*
6522 * XXXXX Still needs lotsa cleanup after sendsig is complete and offsets are known
6523 *
6524 * The following code is copied to the top of the user stack when each
6525 * process is exec'ed, and signals are `trampolined' off it.
6526 *
6527 * When this code is run, the stack looks like:
6528 *        [%sp]                         128 bytes to which registers can be dumped
6529 *        [%sp + 128]                   signal number (goes in %o0)
6530 *        [%sp + 128 + 4]               signal code (goes in %o1)
6531 *        [%sp + 128 + 8]               first word of saved state (sigcontext)
6532 *            .
6533 *            .
6534 *            .
6535 *        [%sp + NNN]         last word of saved state
6536 * (followed by previous stack contents or top of signal stack).
6537 * The address of the function to call is in %g1; the old %g1 and %o0
6538 * have already been saved in the sigcontext.  We are running in a clean
6539 * window, all previous windows now being saved to the stack.
6540 *
6541 * Note that [%sp + 128 + 8] == %sp + 128 + 16.  The copy at %sp+128+8
6542 * will eventually be removed, with a hole left in its place, if things
6543 * work out.
6544 */
6545ENTRY_NOPROFILE(sigcode)
6546          /*
6547           * XXX  the `save' and `restore' below are unnecessary: should
6548           *        replace with simple arithmetic on %sp
6549           *
6550           * Make room on the stack for 64 %f registers + %fsr.  This comes
6551           * out to 64*4+8 or 264 bytes, but this must be aligned to a multiple
6552           * of 64, or 320 bytes.
6553           */
6554          save      %sp, -CC64FSZ - 320, %sp
6555          mov       %g2, %l2            ! save globals in %l registers
6556          mov       %g3, %l3
6557          mov       %g4, %l4
6558          mov       %g5, %l5
6559          mov       %g6, %l6
6560          mov       %g7, %l7
6561          /*
6562           * Saving the fpu registers is expensive, so do it iff it is
6563           * enabled and dirty.
6564           */
6565          rd        %fprs, %l0
6566          btst      FPRS_DL|FPRS_DU, %l0          ! All clean?
6567          bz,pt     %icc, 2f
6568           btst     FPRS_DL, %l0                  ! test dl
6569          bz,pt     %icc, 1f
6570           btst     FPRS_DU, %l0                  ! test du
6571
6572          ! fpu is enabled, oh well
6573          stx       %fsr, [%sp + CC64FSZ + BIAS + 0]
6574          add       %sp, BIAS+CC64FSZ+BLOCK_SIZE, %l0       ! Generate a pointer so we can
6575          andn      %l0, BLOCK_ALIGN, %l0         ! do a block store
6576          stda      %f0, [%l0] ASI_BLK_P
6577          inc       BLOCK_SIZE, %l0
6578          stda      %f16, [%l0] ASI_BLK_P
65791:
6580          bz,pt     %icc, 2f
6581           add      %sp, BIAS+CC64FSZ+BLOCK_SIZE, %l0       ! Generate a pointer so we can
6582          andn      %l0, BLOCK_ALIGN, %l0         ! do a block store
6583          add       %l0, 2*BLOCK_SIZE, %l0        ! and skip what we already stored
6584          stda      %f32, [%l0] ASI_BLK_P
6585          inc       BLOCK_SIZE, %l0
6586          stda      %f48, [%l0] ASI_BLK_P
65872:
6588          membar    #Sync
6589          rd        %fprs, %l0                    ! reload fprs copy, for checking after
6590          rd        %y, %l1                       ! in any case, save %y
6591          lduw      [%fp + BIAS + 128], %o0       ! sig
6592          lduw      [%fp + BIAS + 128 + 4], %o1   ! code
6593          call      %g1                           ! (*sa->sa_handler)(sig,code,scp)
6594           add      %fp, BIAS + 128 + 8, %o2      ! scp
6595          wr        %l1, %g0, %y                  ! in any case, restore %y
6596
6597          /*
6598           * Now that the handler has returned, re-establish all the state
6599           * we just saved above, then do a sigreturn.
6600           */
6601          btst      FPRS_DL|FPRS_DU, %l0          ! All clean?
6602          bz,pt     %icc, 2f
6603           btst     FPRS_DL, %l0                  ! test dl
6604          bz,pt     %icc, 1f
6605           btst     FPRS_DU, %l0                  ! test du
6606
6607          ldx       [%sp + CC64FSZ + BIAS + 0], %fsr
6608          add       %sp, BIAS+CC64FSZ+BLOCK_SIZE, %l0       ! Generate a pointer so we can
6609          andn      %l0, BLOCK_ALIGN, %l0         ! do a block load
6610          ldda      [%l0] ASI_BLK_P, %f0
6611          inc       BLOCK_SIZE, %l0
6612          ldda      [%l0] ASI_BLK_P, %f16
66131:
6614          bz,pt     %icc, 2f
6615           nop
6616          add       %sp, BIAS+CC64FSZ+BLOCK_SIZE, %l0       ! Generate a pointer so we can
6617          andn      %l0, BLOCK_ALIGN, %l0         ! do a block load
6618          inc       2*BLOCK_SIZE, %l0   ! and skip what we already loaded
6619          ldda      [%l0] ASI_BLK_P, %f32
6620          inc       BLOCK_SIZE, %l0
6621          ldda      [%l0] ASI_BLK_P, %f48
66222:
6623          mov       %l2, %g2
6624          mov       %l3, %g3
6625          mov       %l4, %g4
6626          mov       %l5, %g5
6627          mov       %l6, %g6
6628          mov       %l7, %g7
6629          membar    #Sync
6630
6631          restore   %g0, SYS_compat_16___sigreturn14, %g1 ! get registers back & set syscall #
6632          add       %sp, BIAS + 128 + 8, %o0! compute scp
6633!         andn      %o0, 0x0f, %o0
6634          t         ST_SYSCALL                    ! sigreturn(scp)
6635          ! sigreturn does not return unless it fails
6636          mov       SYS_exit, %g1                 ! exit(errno)
6637          t         ST_SYSCALL
6638          /* NOTREACHED */
6639
6640          .globl    _C_LABEL(esigcode)
6641_C_LABEL(esigcode):
6642#endif
6643
6644#if !defined(_LP64)
6645
6646#define SIGCODE_NAME                    sigcode
6647#define ESIGCODE_NAME                   esigcode
6648#define SIGRETURN_NAME                  SYS_compat_16___sigreturn14
6649#define EXIT_NAME             SYS_exit
6650
6651#include "sigcode32.s"
6652
6653#endif
6654#endif
6655
6656/*
6657 * getfp() - get stack frame pointer
6658 */
6659ENTRY(getfp)
6660          retl
6661           mov %fp, %o0
6662
6663/*
6664 * Call optional cpu_idle handler if provided
6665 */
6666ENTRY(cpu_idle)
6667          set       CPUINFO_VA, %o0
6668          LDPTR     [%o0 + CI_IDLESPIN], %o1
6669          tst       %o1
6670          bz        1f
6671           nop
6672          jmp       %o1
6673           nop
66741:
6675          retl
6676          nop
6677
6678/*
6679 * cpu_switchto() switches to an lwp to run and runs it, saving the
6680 * current one away.
6681 *
6682 * struct lwp * cpu_switchto(struct lwp *current, struct lwp *next)
6683 * Switch to the specified next LWP
6684 * Arguments:
6685 *        i0        'struct lwp *' of the current LWP
6686 *        i1        'struct lwp *' of the LWP to switch to
6687 *        i2        'bool' of the flag returning to a softint LWP or not
6688 * Returns:
6689 *        the old lwp switched away from
6690 */
6691ENTRY(cpu_switchto)
6692          save      %sp, -CC64FSZ, %sp
6693          /*
6694           * REGISTER USAGE AT THIS POINT:
6695           *        %l1 = newpcb
6696           *        %l3 = new trapframe
6697           *        %l4 = new l->l_proc
6698           *        %l5 = pcb of oldlwp
6699           *        %l6 = %hi(CPCB)
6700           *        %l7 = %hi(CURLWP)
6701           *        %i0 = oldlwp
6702           *        %i1 = lwp
6703           *        %i2 = returning
6704           *        %o0 = tmp 1
6705           *        %o1 = tmp 2
6706           *        %o2 = tmp 3
6707           *        %o3 = tmp 4
6708           */
6709
6710          flushw                                  ! save all register windows except this one
6711          wrpr      %g0, PSTATE_KERN, %pstate     ! make sure we're on normal globals
6712                                                            ! with traps turned off
6713
6714          sethi     %hi(CPCB), %l6
6715
6716          rdpr      %pstate, %o1                            ! oldpstate = %pstate;
6717          LDPTR     [%i0 + L_PCB], %l5
6718
6719          stx       %i7, [%l5 + PCB_PC]
6720          stx       %i6, [%l5 + PCB_SP]
6721          sth       %o1, [%l5 + PCB_PSTATE]
6722
6723          rdpr      %cwp, %o2           ! Useless
6724          stb       %o2, [%l5 + PCB_CWP]
6725
6726          sethi     %hi(CURLWP), %l7
6727
6728          LDPTR   [%i1 + L_PCB], %l1    ! newpcb = l->l_pcb;
6729
6730          /*
6731           * Load the new lwp.  To load, we must change stacks and
6732           * alter cpcb and the window control registers, hence we must
6733           * keep interrupts disabled.
6734           *
6735           * Issue barriers to coordinate mutex_exit on this CPU with
6736           * mutex_vector_enter on another CPU.
6737           *
6738           * 1. Any prior mutex_exit by oldlwp must be visible to other
6739           *    CPUs before we set ci_curlwp := newlwp on this one,
6740           *    requiring a store-before-store barrier.
6741           *
6742           * 2. ci_curlwp := newlwp must be visible on all other CPUs
6743           *    before any subsequent mutex_exit by newlwp can even test
6744           *    whether there might be waiters, requiring a
6745           *    store-before-load barrier.
6746           *
6747           * See kern_mutex.c for details -- this is necessary for
6748           * adaptive mutexes to detect whether the lwp is on the CPU in
6749           * order to safely block without requiring atomic r/m/w in
6750           * mutex_exit.
6751           */
6752
6753          membar    #StoreStore
6754          STPTR     %i1, [%l7 + %lo(CURLWP)]      ! curlwp = l;
6755          membar    #StoreLoad
6756          STPTR     %l1, [%l6 + %lo(CPCB)]                  ! cpcb = newpcb;
6757
6758          ldx       [%l1 + PCB_SP], %i6
6759          ldx       [%l1 + PCB_PC], %i7
6760
6761          wrpr      %g0, 0, %otherwin   ! These two insns should be redundant
6762          wrpr      %g0, 0, %canrestore
6763          GET_MAXCWP %o3
6764          wrpr      %g0, %o3, %cleanwin
6765          dec       1, %o3                        ! CANSAVE + CANRESTORE + OTHERWIN = MAXCWP - 1
6766          /* Skip the rest if returning to a interrupted LWP. */
6767          brnz,pn   %i2, Lsw_noras
6768           wrpr     %o3, %cansave
6769
6770          /* finally, enable traps */
6771          wrpr      %g0, PSTATE_INTR, %pstate
6772
6773          !flushw
6774          !membar #Sync
6775
6776          /*
6777           * Check for restartable atomic sequences (RAS)
6778           */
6779          LDPTR     [%i1 + L_PROC], %l4           ! now %l4 points to p
6780          mov       %l4, %o0            ! p is first arg to ras_lookup
6781          LDPTR     [%o0 + P_RASLIST], %o1        ! any RAS in p?
6782          brz,pt    %o1, Lsw_noras                ! no, skip RAS check
6783           LDPTR    [%i1 + L_TF], %l3   ! pointer to trap frame
6784          call      _C_LABEL(ras_lookup)
6785           ldx      [%l3 + TF_PC], %o1
6786          cmp       %o0, -1
6787          be,pt     CCCR, Lsw_noras
6788           add      %o0, 4, %o1
6789          stx       %o0, [%l3 + TF_PC]  ! store rewound %pc
6790          stx       %o1, [%l3 + TF_NPC] ! and %npc
6791
6792Lsw_noras:
6793
6794          /*
6795           * We are resuming the process that was running at the
6796           * call to switch().  Just set psr ipl and return.
6797           */
6798!         wrpr      %g0, 0, %cleanwin   ! DEBUG
6799          clr       %g4                 ! This needs to point to the base of the data segment
6800          wr        %g0, ASI_PRIMARY_NOFAULT, %asi                    ! Restore default ASI
6801          !wrpr     %g0, PSTATE_INTR, %pstate
6802          ret
6803           restore %i0, %g0, %o0                                      ! return old curlwp
6804
6805#ifdef __HAVE_FAST_SOFTINTS
6806/*
6807 * Switch to the LWP assigned to handle interrupts from the given
6808 * source.  We borrow the VM context from the interrupted LWP.
6809 *
6810 * int softint_fastintr(void *l)
6811 *
6812 * Arguments:
6813 *        i0        softint lwp
6814 */
6815ENTRY(softint_fastintr)
6816          save      %sp, -CC64FSZ, %sp
6817          set       CPUINFO_VA, %l0                         ! l0 = curcpu()
6818          rdpr      %pil, %l7                     ! l7 = splhigh()
6819          wrpr      %g0, PIL_HIGH, %pil
6820          LDPTR     [%l0 + CI_EINTSTACK], %l6     ! l6 = ci_eintstack
6821          add       %sp, -CC64FSZ, %l2            ! ci_eintstack = sp - CC64FSZ
6822          STPTR     %l2, [%l0 + CI_EINTSTACK]     ! save intstack for nested intr
6823
6824          mov       %i0, %o0                      ! o0/i0 = softint lwp
6825          mov       %l7, %o1                      ! o1/i1 = ipl
6826          save      %sp, -CC64FSZ, %sp            ! make one more register window
6827          flushw                                            ! and save all
6828
6829          sethi     %hi(CURLWP), %l7
6830          sethi     %hi(CPCB), %l6
6831          LDPTR     [%l7 + %lo(CURLWP)], %l0      ! l0 = interrupted lwp (curlwp)
6832
6833          /* save interrupted lwp/pcb info */
6834          sethi     %hi(softint_fastintr_ret - 8), %o0      ! trampoline function
6835          LDPTR     [%l0 + L_PCB], %l5            ! l5 = interrupted pcb
6836          or        %o0, %lo(softint_fastintr_ret - 8), %o0
6837          stx       %i6, [%l5 + PCB_SP]
6838          stx       %o0, [%l5 + PCB_PC]
6839          rdpr      %pstate, %o1
6840          rdpr      %cwp, %o2
6841          sth       %o1, [%l5 + PCB_PSTATE]
6842          stb       %o2, [%l5 + PCB_CWP]
6843
6844          /* switch to softint lwp */
6845          sethi     %hi(USPACE - TF_SIZE - CC64FSZ - STKB), %o3
6846          LDPTR     [%i0 + L_PCB], %l1            ! l1 = softint pcb
6847          or        %o3, %lo(USPACE - TF_SIZE - CC64FSZ - STKB), %o3
6848          membar    #StoreStore                   /* for mutex_enter; see cpu_switchto */
6849          STPTR     %i0, [%l7 + %lo(CURLWP)]
6850          /*
6851           * No need for barrier after ci->ci_curlwp = softlwp -- when we
6852           * enter a softint lwp, it can't be holding any mutexes, so it
6853           * can't release any until after it has acquired them, so we
6854           * need not participate in the protocol with mutex_vector_enter
6855           * barriers here.
6856           */
6857          add       %l1, %o3, %i6
6858          STPTR     %l1, [%l6 + %lo(CPCB)]
6859          stx       %i6, [%l1 + PCB_SP]
6860          add       %i6, -CC64FSZ, %sp            ! new stack
6861
6862          /* now switched, then invoke MI dispatcher */
6863          mov       %i1, %o1
6864          call      _C_LABEL(softint_dispatch)
6865           mov      %l0, %o0
6866
6867          /* switch back to interrupted lwp */
6868          ldx       [%l5 + PCB_SP], %i6
6869          membar    #StoreStore                   /* for mutex_enter; see cpu_switchto */
6870          STPTR     %l0, [%l7 + %lo(CURLWP)]
6871          membar    #StoreLoad                    /* for mutex_enter; see cpu_switchto */
6872          STPTR     %l5, [%l6 + %lo(CPCB)]
6873
6874          restore                                           ! rewind register window
6875
6876          STPTR     %l6, [%l0 + CI_EINTSTACK]     ! restore ci_eintstack
6877          wrpr      %g0, %l7, %pil                          ! restore ipl
6878          ret
6879           restore  %g0, 1, %o0
6880
6881/*
6882 * Trampoline function that gets returned to by cpu_switchto() when
6883 * an interrupt handler blocks.
6884 *
6885 * Arguments:
6886 *        o0        old lwp from cpu_switchto()
6887 *
6888 * from softint_fastintr():
6889 *        l0        CPUINFO_VA
6890 *        l6        saved ci_eintstack
6891 *        l7        saved ipl
6892 */
6893softint_fastintr_ret:
6894          /* re-adjust after mi_switch() */
6895          ld        [%l0 + CI_MTX_COUNT], %o1
6896          inc       %o1                                     ! ci_mtx_count++
6897          st        %o1, [%l0 + CI_MTX_COUNT]
6898
6899          STPTR     %l6, [%l0 + CI_EINTSTACK]     ! restore ci_eintstack
6900          wrpr      %g0, %l7, %pil                          ! restore ipl
6901          ret
6902           restore  %g0, 1, %o0
6903
6904#endif /* __HAVE_FAST_SOFTINTS */
6905
6906/*
6907 * Snapshot the current process so that stack frames are up to date.
6908 * Only used just before a crash dump.
6909 */
6910ENTRY(snapshot)
6911          rdpr      %pstate, %o1                  ! save psr
6912          stx       %o7, [%o0 + PCB_PC] ! save pc
6913          stx       %o6, [%o0 + PCB_SP] ! save sp
6914          rdpr      %pil, %o2
6915          sth       %o1, [%o0 + PCB_PSTATE]
6916          rdpr      %cwp, %o3
6917          stb       %o2, [%o0 + PCB_PIL]
6918          stb       %o3, [%o0 + PCB_CWP]
6919
6920          flushw
6921          save      %sp, -CC64FSZ, %sp
6922          flushw
6923          ret
6924           restore
6925
6926/*
6927 * cpu_lwp_fork() arranges for lwp_trampoline() to run when the
6928 * nascent lwp is selected by switch().
6929 *
6930 * The switch frame will contain pointer to struct lwp of this lwp in
6931 * %l2, a pointer to the function to call in %l0, and an argument to
6932 * pass to it in %l1 (we abuse the callee-saved registers).
6933 *
6934 * We enter lwp_trampoline as if we are "returning" from
6935 * cpu_switchto(), so %o0 contains previous lwp (the one we are
6936 * switching from) that we pass to lwp_startup().
6937 *
6938 * If the function *(%l0) returns, we arrange for an immediate return
6939 * to user mode.  This happens in two known cases: after execve(2) of
6940 * init, and when returning a child to user mode after a fork(2).
6941 *
6942 * If were setting up a kernel thread, the function *(%l0) will not
6943 * return.
6944 */
6945ENTRY(lwp_trampoline)
6946          /*
6947           * Note: cpu_lwp_fork() has set up a stack frame for us to run
6948           * in, so we can call other functions from here without using
6949           * `save ... restore'.
6950           */
6951
6952          ! newlwp in %l2, oldlwp in %o0
6953          call    lwp_startup
6954           mov    %l2, %o1
6955
6956          call      %l0                           ! re-use current frame
6957           mov      %l1, %o0
6958
6959          /*
6960           * Here we finish up as in syscall, but simplified.
6961           */
6962          b         return_from_trap
6963           nop
6964
6965/*
6966 * pmap_zero_page_phys(pa)
6967 *
6968 * Zero one page physically addressed
6969 *
6970 * Block load/store ASIs do not exist for physical addresses,
6971 * so we won't use them.
6972 *
6973 * We will execute a flush at the end to sync the I$.
6974 *
6975 * This version expects to have the dcache_flush_page_all(pa)
6976 * to have been called before calling into here.
6977 */
6978ENTRY(pmap_zero_page_phys)
6979#ifndef _LP64
6980          COMBINE(%o0, %o1, %o0)
6981#endif
6982#ifdef DEBUG
6983          set       pmapdebug, %o4
6984          ld        [%o4], %o4
6985          btst      0x80, %o4 ! PDB_COPY
6986          bz,pt     %icc, 3f
6987           nop
6988          save      %sp, -CC64FSZ, %sp
6989          set       2f, %o0
6990          call      printf
6991           mov      %i0, %o1
6992!         ta        1; nop
6993          restore
6994          .data
69952:        .asciz    "pmap_zero_page(%p)\n"
6996          _ALIGN
6997          .text
69983:
6999#endif
7000          set       NBPG, %o2           ! Loop count
7001          wr        %g0, ASI_PHYS_CACHED, %asi
70021:
7003          /* Unroll the loop 8 times */
7004          stxa      %g0, [%o0 + 0x00] %asi
7005          deccc     0x40, %o2
7006          stxa      %g0, [%o0 + 0x08] %asi
7007          stxa      %g0, [%o0 + 0x10] %asi
7008          stxa      %g0, [%o0 + 0x18] %asi
7009          stxa      %g0, [%o0 + 0x20] %asi
7010          stxa      %g0, [%o0 + 0x28] %asi
7011          stxa      %g0, [%o0 + 0x30] %asi
7012          stxa      %g0, [%o0 + 0x38] %asi
7013          bg,pt     %icc, 1b
7014           inc      0x40, %o0
7015
7016          sethi     %hi(KERNBASE), %o3
7017          flush     %o3
7018          retl
7019           wr       %g0, ASI_PRIMARY_NOFAULT, %asi          ! Make C code happy
7020
7021/*
7022 * pmap_copy_page_phys(paddr_t src, paddr_t dst)
7023 *
7024 * Copy one page physically addressed
7025 * We need to use a global reg for ldxa/stxa
7026 * so the top 32-bits cannot be lost if we take
7027 * a trap and need to save our stack frame to a
7028 * 32-bit stack.  We will unroll the loop by 4 to
7029 * improve performance.
7030 *
7031 * This version expects to have the dcache_flush_page_all(pa)
7032 * to have been called before calling into here.
7033 *
7034 */
7035ENTRY(pmap_copy_page_phys)
7036#ifndef _LP64
7037          COMBINE(%o0, %o1, %o0)
7038          COMBINE(%o2, %o3, %o1)
7039#endif
7040#ifdef DEBUG
7041          set       pmapdebug, %o4
7042          ld        [%o4], %o4
7043          btst      0x80, %o4 ! PDB_COPY
7044          bz,pt     %icc, 3f
7045           nop
7046          save      %sp, -CC64FSZ, %sp
7047          mov       %i0, %o1
7048          set       2f, %o0
7049          call      printf
7050           mov      %i1, %o2
7051!         ta        1; nop
7052          restore
7053          .data
70542:        .asciz    "pmap_copy_page(%p,%p)\n"
7055          _ALIGN
7056          .text
70573:
7058#endif
7059#if 1
7060          set       NBPG, %o2
7061          wr        %g0, ASI_PHYS_CACHED, %asi
70621:
7063          ldxa      [%o0 + 0x00] %asi, %g1
7064          ldxa      [%o0 + 0x08] %asi, %o3
7065          ldxa      [%o0 + 0x10] %asi, %o4
7066          ldxa      [%o0 + 0x18] %asi, %o5
7067          inc       0x20, %o0
7068          deccc     0x20, %o2
7069          stxa      %g1, [%o1 + 0x00] %asi
7070          stxa      %o3, [%o1 + 0x08] %asi
7071          stxa      %o4, [%o1 + 0x10] %asi
7072          stxa      %o5, [%o1 + 0x18] %asi
7073          bg,pt     %icc, 1b            ! We don't care about pages >4GB
7074           inc      0x20, %o1
7075          retl
7076           wr       %g0, ASI_PRIMARY_NOFAULT, %asi
7077#else
7078          set       NBPG, %o3
7079          add       %o3, %o0, %o3
7080          mov       %g1, %o4            ! Save g1
70811:
7082          ldxa      [%o0] ASI_PHYS_CACHED, %g1
7083          inc       8, %o0
7084          cmp       %o0, %o3
7085          stxa      %g1, [%o1] ASI_PHYS_CACHED
7086          bl,pt     %icc, 1b            ! We don't care about pages >4GB
7087           inc      8, %o1
7088          retl
7089           mov      %o4, %g1            ! Restore g1
7090#endif
7091
7092/*
7093 * extern int64_t pseg_get_real(struct pmap *pm, vaddr_t addr);
7094 *
7095 * Return TTE at addr in pmap.  Uses physical addressing only.
7096 * pmap->pm_physaddr must by the physical address of pm_segs
7097 *
7098 */
7099ENTRY(pseg_get_real)
7100!         flushw                        ! Make sure we don't have stack probs & lose hibits of %o
7101#ifndef _LP64
7102          clruw     %o1                                               ! Zero extend
7103#endif
7104          ldx       [%o0 + PM_PHYS], %o2                              ! pmap->pm_segs
7105
7106          srax      %o1, HOLESHIFT, %o3                     ! Check for valid address
7107          brz,pt    %o3, 0f                                           ! Should be zero or -1
7108           inc      %o3                                               ! Make -1 -> 0
7109          brnz,pn   %o3, 1f                                           ! Error! In hole!
71100:
7111          srlx      %o1, STSHIFT, %o3
7112          and       %o3, STMASK, %o3                        ! Index into pm_segs
7113          sll       %o3, 3, %o3
7114          add       %o2, %o3, %o2
7115          DLFLUSH(%o2,%o3)
7116          ldxa      [%o2] ASI_PHYS_CACHED, %o2              ! Load page directory pointer
7117          DLFLUSH2(%o3)
7118
7119          srlx      %o1, PDSHIFT, %o3
7120          and       %o3, PDMASK, %o3
7121          sll       %o3, 3, %o3
7122          brz,pn    %o2, 1f                                           ! NULL entry? check somewhere else
7123           add      %o2, %o3, %o2
7124          DLFLUSH(%o2,%o3)
7125          ldxa      [%o2] ASI_PHYS_CACHED, %o2              ! Load page table pointer
7126          DLFLUSH2(%o3)
7127
7128          srlx      %o1, PTSHIFT, %o3                       ! Convert to ptab offset
7129          and       %o3, PTMASK, %o3
7130          sll       %o3, 3, %o3
7131          brz,pn    %o2, 1f                                           ! NULL entry? check somewhere else
7132           add      %o2, %o3, %o2
7133          DLFLUSH(%o2,%o3)
7134          ldxa      [%o2] ASI_PHYS_CACHED, %o0
7135          DLFLUSH2(%o3)
7136          brgez,pn %o0, 1f                                  ! Entry invalid?  Punt
7137           btst     1, %sp
7138          bz,pn     %icc, 0f                                ! 64-bit mode?
7139           nop
7140          retl                                                        ! Yes, return full value
7141           nop
71420:
7143#if 1
7144          srl       %o0, 0, %o1
7145          retl                                                        ! No, generate a %o0:%o1 double
7146           srlx     %o0, 32, %o0
7147#else
7148          DLFLUSH(%o2,%o3)
7149          ldda      [%o2] ASI_PHYS_CACHED, %o0
7150          DLFLUSH2(%o3)
7151          retl                                                        ! No, generate a %o0:%o1 double
7152           nop
7153#endif
71541:
7155#ifndef _LP64
7156          clr       %o1
7157#endif
7158          retl
7159           clr      %o0
7160
7161/*
7162 * In 32-bit mode:
7163 *
7164 * extern int pseg_set_real(struct pmap* %o0, vaddr_t addr %o1,
7165 *                                int64_t tte %o2:%o3, paddr_t spare %o4:%o5);
7166 *
7167 * In 64-bit mode:
7168 *
7169 * extern int pseg_set_real(struct pmap* %o0, vaddr_t addr %o1,
7170 *                                int64_t tte %o2, paddr_t spare %o3);
7171 *
7172 * Set a pseg entry to a particular TTE value.  Return values are:
7173 *
7174 *        -2        addr in hole
7175 *        0         success   (spare was not used if given)
7176 *        1         failure   (spare was not given, but one is needed)
7177 *        2         success   (spare was given, used for L2)
7178 *        3         failure   (spare was given, used for L2, another is needed for L3)
7179 *        4         success   (spare was given, used for L3)
7180 *
7181 *        rv == 0   success, spare not used if one was given
7182 *        rv & 4    spare was used for L3
7183 *        rv & 2    spare was used for L2
7184 *        rv & 1    failure, spare is needed
7185 *
7186 * (NB: nobody in pmap checks for the virtual hole, so the system will hang.)
7187 * The way to call this is:  first just call it without a spare page.
7188 * If that fails, allocate a page and try again, passing the paddr of the
7189 * new page as the spare.
7190 * If spare is non-zero it is assumed to be the address of a zeroed physical
7191 * page that can be used to generate a directory table or page table if needed.
7192 *
7193 * We keep track of valid (A_TLB_V bit set) and wired (A_TLB_TSB_LOCK bit set)
7194 * mappings that are set here. We check both bits on the new data entered
7195 * and increment counts, as well as decrementing counts if the bits are set
7196 * in the value replaced by this call.
7197 * The counters are 32 bit or 64 bit wide, depending on the kernel type we are
7198 * running!
7199 */
7200ENTRY(pseg_set_real)
7201#ifndef _LP64
7202          clruw     %o1                                               ! Zero extend
7203          COMBINE(%o2, %o3, %o2)
7204          COMBINE(%o4, %o5, %o3)
7205#endif
7206          !!
7207          !! However we managed to get here we now have:
7208          !!
7209          !! %o0 = *pmap
7210          !! %o1 = addr
7211          !! %o2 = tte
7212          !! %o3 = paddr of spare page
7213          !!
7214          srax      %o1, HOLESHIFT, %o4                     ! Check for valid address
7215          brz,pt    %o4, 0f                                           ! Should be zero or -1
7216           inc      %o4                                               ! Make -1 -> 0
7217          brz,pt    %o4, 0f
7218           nop
7219#ifdef DEBUG
7220          ta        1                                                 ! Break into debugger
7221#endif
7222          retl
7223           mov -2, %o0                                                ! Error -- in hole!
7224
72250:
7226          ldx       [%o0 + PM_PHYS], %o4                              ! pmap->pm_segs
7227          clr       %g1
7228          srlx      %o1, STSHIFT, %o5
7229          and       %o5, STMASK, %o5
7230          sll       %o5, 3, %o5
7231          add       %o4, %o5, %o4
72320:
7233          DLFLUSH(%o4,%g5)
7234          ldxa      [%o4] ASI_PHYS_CACHED, %o5              ! Load page directory pointer
7235          DLFLUSH2(%g5)
7236
7237          brnz,a,pt %o5, 0f                                 ! Null pointer?
7238           mov      %o5, %o4
7239          brz,pn    %o3, 9f                                           ! Have a spare?
7240           mov      %o3, %o5
7241          casxa     [%o4] ASI_PHYS_CACHED, %g0, %o5
7242          brnz,pn   %o5, 0b                                           ! Something changed?
7243          DLFLUSH(%o4, %o5)
7244          mov       %o3, %o4
7245          mov       2, %g1                                            ! record spare used for L2
7246          clr       %o3                                               ! and not available for L3
72470:
7248          srlx      %o1, PDSHIFT, %o5
7249          and       %o5, PDMASK, %o5
7250          sll       %o5, 3, %o5
7251          add       %o4, %o5, %o4
72520:
7253          DLFLUSH(%o4,%g5)
7254          ldxa      [%o4] ASI_PHYS_CACHED, %o5              ! Load table directory pointer
7255          DLFLUSH2(%g5)
7256
7257          brnz,a,pt %o5, 0f                                 ! Null pointer?
7258           mov      %o5, %o4
7259          brz,pn    %o3, 9f                                           ! Have a spare?
7260           mov      %o3, %o5
7261          casxa     [%o4] ASI_PHYS_CACHED, %g0, %o5
7262          brnz,pn   %o5, 0b                                           ! Something changed?
7263          DLFLUSH(%o4, %o4)
7264          mov       %o3, %o4
7265          mov       4, %g1                                            ! record spare used for L3
72660:
7267          srlx      %o1, PTSHIFT, %o5                       ! Convert to ptab offset
7268          and       %o5, PTMASK, %o5
7269          sll       %o5, 3, %o5
7270          add       %o5, %o4, %o4
7271
7272          DLFLUSH(%o4,%g5)
7273          ldxa      [%o4] ASI_PHYS_CACHED, %o5              ! save old value in %o5
7274          stxa      %o2, [%o4] ASI_PHYS_CACHED              ! Easier than shift+or
7275          DLFLUSH2(%g5)
7276
7277          !! at this point we have:
7278          !!  %g1 = return value
7279          !!  %o0 = struct pmap * (where the counts are)
7280          !!  %o2 = new TTE
7281          !!  %o5 = old TTE
7282
7283          !! see if stats needs an update
7284#ifdef SUN4V
7285          sethi     %hi(cputyp), %g5
7286          ld        [%g5 + %lo(cputyp)], %g5
7287          cmp       %g5, CPU_SUN4V
7288          bne,pt    %icc, 0f
7289           nop
7290          sethi     %hh(SUN4V_TLB_TSB_LOCK), %g5
7291          sllx      %g5, 32, %g5
7292          ba        1f
7293           nop
72940:
7295#endif
7296          set       SUN4U_TLB_TSB_LOCK, %g5
72971:
7298          xor       %o2, %o5, %o3                           ! %o3 - what changed
7299
7300          brgez,pn %o3, 5f                        ! has resident changed? (we predict it has)
7301           btst     %g5, %o3                      ! has wired changed?
7302
7303          LDPTR     [%o0 + PM_RESIDENT], %o1      ! gonna update resident count
7304          brlz      %o2, 0f
7305           mov      1, %o4
7306          neg       %o4                                     ! new is not resident -> decrement
73070:        add       %o1, %o4, %o1
7308          STPTR     %o1, [%o0 + PM_RESIDENT]
7309          btst      %g5, %o3                      ! has wired changed?
73105:        bz,pt     %xcc, 8f                      ! we predict it's not
7311           btst     %g5, %o2                      ! don't waste delay slot, check if new one is wired
7312          LDPTR     [%o0 + PM_WIRED], %o1                   ! gonna update wired count
7313          bnz,pt    %xcc, 0f                      ! if wired changes, we predict it increments
7314           mov      1, %o4
7315          neg       %o4                                     ! new is not wired -> decrement
73160:        add       %o1, %o4, %o1
7317          STPTR     %o1, [%o0 + PM_WIRED]
73188:        retl
7319           mov      %g1, %o0                      ! return %g1
7320
73219:        retl
7322           or       %g1, 1, %o0                             ! spare needed, return flags + 1
7323
7324
7325/*
7326 * clearfpstate()
7327 *
7328 * Drops the current fpu state, without saving it.
7329 */
7330ENTRY(clearfpstate)
7331          rdpr      %pstate, %o1                  ! enable FPU
7332          wr        %g0, FPRS_FEF, %fprs
7333          or        %o1, PSTATE_PEF, %o1
7334          retl
7335           wrpr     %o1, 0, %pstate
7336
7337/*
7338 * savefpstate(f) struct fpstate *f;
7339 *
7340 * Store the current FPU state.
7341 *
7342 * Since the kernel may need to use the FPU and we have problems atomically
7343 * testing and enabling the FPU, we leave here with the FPRS_FEF bit set.
7344 * Normally this should be turned on in loadfpstate().
7345 */
7346 /* XXXXXXXXXX  Assume caller created a proper stack frame */
7347ENTRY(savefpstate)
7348!         flushw                        ! Make sure we don't have stack probs & lose hibits of %o
7349          rdpr      %pstate, %o1                  ! enable FP before we begin
7350          rd        %fprs, %o5
7351          wr        %g0, FPRS_FEF, %fprs
7352          or        %o1, PSTATE_PEF, %o1
7353          wrpr      %o1, 0, %pstate
7354
7355          stx       %fsr, [%o0 + FS_FSR]          ! f->fs_fsr = getfsr();
7356          rd        %gsr, %o4           ! Save %gsr
7357          st        %o4, [%o0 + FS_GSR]
7358
7359          add       %o0, FS_REGS, %o2
7360#ifdef DIAGNOSTIC
7361          btst      BLOCK_ALIGN, %o2    ! Needs to be re-executed
7362          bnz,pn    %icc, 6f            ! Check alignment
7363#endif
7364           st       %g0, [%o0 + FS_QSIZE]         ! f->fs_qsize = 0;
7365          btst      FPRS_DL|FPRS_DU, %o5          ! Both FPU halves clean?
7366          bz,pt     %icc, 5f            ! Then skip it
7367
7368           btst     FPRS_DL, %o5                  ! Lower FPU clean?
7369          membar    #Sync
7370          bz,a,pt   %icc, 1f            ! Then skip it, but upper FPU not clean
7371           add      %o2, 2*BLOCK_SIZE, %o2        ! Skip a block
7372
7373          stda      %f0, [%o2] ASI_BLK_P          ! f->fs_f0 = etc;
7374          inc       BLOCK_SIZE, %o2
7375          stda      %f16, [%o2] ASI_BLK_P
7376
7377          btst      FPRS_DU, %o5                  ! Upper FPU clean?
7378          bz,pt     %icc, 2f            ! Then skip it
7379           inc      BLOCK_SIZE, %o2
73801:
7381          stda      %f32, [%o2] ASI_BLK_P
7382          inc       BLOCK_SIZE, %o2
7383          stda      %f48, [%o2] ASI_BLK_P
73842:
7385          membar    #Sync                         ! Finish operation so we can
73865:
7387          retl
7388           wr       %g0, FPRS_FEF, %fprs          ! Mark FPU clean
7389
7390#ifdef DIAGNOSTIC
7391          !!
7392          !! Damn thing is *NOT* aligned on a 64-byte boundary
7393          !!
73946:
7395          wr        %g0, FPRS_FEF, %fprs
7396          ! XXX -- we should panic instead of silently entering debugger
7397          ta        1
7398          retl
7399           nop
7400#endif
7401
7402/*
7403 * Load FPU state.
7404 */
7405 /* XXXXXXXXXX  Should test to see if we only need to do a partial restore */
7406ENTRY(loadfpstate)
7407          flushw                        ! Make sure we don't have stack probs & lose hibits of %o
7408          rdpr      %pstate, %o1                  ! enable FP before we begin
7409          ld        [%o0 + FS_GSR], %o4 ! Restore %gsr
7410          set       PSTATE_PEF, %o2
7411          wr        %g0, FPRS_FEF, %fprs
7412          or        %o1, %o2, %o1
7413          wrpr      %o1, 0, %pstate
7414          ldx       [%o0 + FS_FSR], %fsr          ! setfsr(f->fs_fsr);
7415          add       %o0, FS_REGS, %o3   ! This is zero...
7416#ifdef DIAGNOSTIC
7417          btst      BLOCK_ALIGN, %o3
7418          bne,pn    %icc, 1f  ! Only use block loads on aligned blocks
7419#endif
7420           wr       %o4, %g0, %gsr
7421          membar    #Sync
7422          ldda      [%o3] ASI_BLK_P, %f0
7423          inc       BLOCK_SIZE, %o3
7424          ldda      [%o3] ASI_BLK_P, %f16
7425          inc       BLOCK_SIZE, %o3
7426          ldda      [%o3] ASI_BLK_P, %f32
7427          inc       BLOCK_SIZE, %o3
7428          ldda      [%o3] ASI_BLK_P, %f48
7429          membar    #Sync                         ! Make sure loads are complete
7430          retl
7431           wr       %g0, FPRS_FEF, %fprs          ! Clear dirty bits
7432
7433#ifdef DIAGNOSTIC
7434          !!
7435          !! Damn thing is *NOT* aligned on a 64-byte boundary
7436          !!
74371:
7438          wr        %g0, FPRS_FEF, %fprs          ! Clear dirty bits
7439          ! XXX -- we should panic instead of silently entering debugger
7440          ta        1
7441          retl
7442           nop
7443#endif
7444
7445/*
7446 * ienab_bis(bis) int bis;
7447 * ienab_bic(bic) int bic;
7448 *
7449 * Set and clear bits in the interrupt register.
7450 */
7451
7452/*
7453 * sun4u has separate asr's for clearing/setting the interrupt mask.
7454 */
7455ENTRY(ienab_bis)
7456          retl
7457           wr       %o0, 0, SET_SOFTINT ! SET_SOFTINT
7458
7459ENTRY(ienab_bic)
7460          retl
7461           wr       %o0, 0, CLEAR_SOFTINT         ! CLEAR_SOFTINT
7462
7463/*
7464 * send_softint(cpu, level, intrhand)
7465 *
7466 * Send a softint with an intrhand pointer so we can cause a vectored
7467 * interrupt instead of a polled interrupt.  This does pretty much the same
7468 * as interrupt_vector.  If cpu is -1 then send it to this CPU, if it's -2
7469 * send it to any CPU, otherwise send it to a particular CPU.
7470 *
7471 * XXXX Dispatching to different CPUs is not implemented yet.
7472 */
7473ENTRY(send_softint)
7474          rdpr      %pstate, %g1
7475          andn      %g1, PSTATE_IE, %g2 ! clear PSTATE.IE
7476          wrpr      %g2, 0, %pstate
7477
7478          sethi     %hi(CPUINFO_VA+CI_INTRPENDING), %o3
7479          LDPTR     [%o2 + IH_PEND], %o5
7480          or        %o3, %lo(CPUINFO_VA+CI_INTRPENDING), %o3
7481          brnz      %o5, 1f
7482           sll      %o1, PTRSHFT, %o5   ! Find start of table for this IPL
7483          add       %o3, %o5, %o3
74842:
7485          LDPTR     [%o3], %o5                    ! Load list head
7486          STPTR     %o5, [%o2+IH_PEND]  ! Link our intrhand node in
7487          mov       %o2, %o4
7488          CASPTRA   [%o3] ASI_N, %o5, %o4
7489          cmp       %o4, %o5            ! Did it work?
7490          bne,pn    CCCR, 2b            ! No, try again
7491           .empty
7492
7493          mov       1, %o4                        ! Change from level to bitmask
7494          sllx      %o4, %o1, %o4
7495          wr        %o4, 0, SET_SOFTINT ! SET_SOFTINT
74961:
7497          retl
7498           wrpr     %g1, 0, %pstate               ! restore PSTATE.IE
7499
7500
7501#define MICROPERSEC (1000000)
7502
7503/*
7504 * delay function
7505 *
7506 * void delay(N)  -- delay N microseconds
7507 *
7508 * Register usage: %o0 = "N" number of usecs to go (counts down to zero)
7509 *                     %o1 = "timerblurb" (stays constant)
7510 *                     %o2 = counter for 1 usec (counts down from %o1 to zero)
7511 *
7512 *
7513 *        ci_cpu_clockrate should be tuned during CPU probe to the CPU
7514 *        clockrate in Hz
7515 *
7516 */
7517ENTRY(delay)                            ! %o0 = n
7518#if 1
7519          rdpr      %tick, %o1                                                  ! Take timer snapshot
7520          sethi     %hi(CPUINFO_VA + CI_CLOCKRATE), %o2
7521          sethi     %hi(MICROPERSEC), %o3
7522          ldx       [%o2 + %lo(CPUINFO_VA + CI_CLOCKRATE + 8)], %o4   ! Get scale factor
7523          brnz,pt   %o4, 0f
7524           or       %o3, %lo(MICROPERSEC), %o3
7525
7526          !! Calculate ticks/usec
7527          ldx       [%o2 + %lo(CPUINFO_VA + CI_CLOCKRATE)], %o4       ! No, we need to calculate it
7528          udivx     %o4, %o3, %o4
7529          stx       %o4, [%o2 + %lo(CPUINFO_VA + CI_CLOCKRATE + 8)]   ! Save it so we don't need to divide again
75300:
7531
7532          mulx      %o0, %o4, %o0                                               ! Convert usec -> ticks
7533          rdpr      %tick, %o2                                                  ! Top of next itr
75341:
7535          sub       %o2, %o1, %o3                                               ! How many ticks have gone by?
7536          sub       %o0, %o3, %o4                                               ! Decrement count by that much
7537          movrgz    %o3, %o4, %o0                                               ! But only if we're decrementing
7538          mov       %o2, %o1                                          ! Remember last tick
7539          brgz,pt   %o0, 1b                                                     ! Done?
7540           rdpr     %tick, %o2                                                  ! Get new tick
7541
7542          retl
7543           nop
7544#else
7545/* This code only works if %tick does not wrap */
7546          rdpr      %tick, %g1                                                  ! Take timer snapshot
7547          sethi     %hi(CPUINFO_VA + CI_CLOCKRATE), %g2
7548          sethi     %hi(MICROPERSEC), %o2
7549          ldx       [%g2 + %lo(CPUINFO_VA + CI_CLOCKRATE)], %g2       ! Get scale factor
7550          or        %o2, %lo(MICROPERSEC), %o2
7551!         sethi     %hi(_C_LABEL(timerblurb), %o5                     ! This is if we plan to tune the clock
7552!         ld        [%o5 + %lo(_C_LABEL(timerblurb))], %o5            !  with respect to the counter/timer
7553          mulx      %o0, %g2, %g2                                               ! Scale it: (usec * Hz) / 1 x 10^6 = ticks
7554          udivx     %g2, %o2, %g2
7555          add       %g1, %g2, %g2
7556!         add       %o5, %g2, %g2                           5, %g2, %g2                                                 ! But this gets complicated
7557          rdpr      %tick, %g1                                                  ! Top of next itr
7558          mov       %g1, %g1  ! Erratum 50
75591:
7560          cmp       %g1, %g2
7561          bl,a,pn %xcc, 1b                                            ! Done?
7562           rdpr     %tick, %g1
7563
7564          retl
7565           nop
7566#endif
7567          /*
7568           * If something's wrong with the standard setup do this stupid loop
7569           * calibrated for a 143MHz processor.
7570           */
7571Lstupid_delay:
7572          set       142857143/MICROPERSEC, %o1
7573Lstupid_loop:
7574          brnz,pt   %o1, Lstupid_loop
7575           dec      %o1
7576          brnz,pt   %o0, Lstupid_delay
7577           dec      %o0
7578          retl
7579           nop
7580
7581/*
7582 * next_tick(long increment)
7583 *
7584 * Sets the %tick_cmpr register to fire off in `increment' machine
7585 * cycles in the future.  Also handles %tick wraparound.  In 32-bit
7586 * mode we're limited to a 32-bit increment.
7587 */
7588ENTRY(next_tick)
7589          rd        TICK_CMPR, %o2
7590          rdpr      %tick, %o1
7591
7592          mov       1, %o3              ! Mask off high bits of these registers
7593          sllx      %o3, 63, %o3
7594          andn      %o1, %o3, %o1
7595          andn      %o2, %o3, %o2
7596          cmp       %o1, %o2  ! Did we wrap?  (tick < tick_cmpr)
7597          bgt,pt    %icc, 1f
7598           add      %o1, 1000, %o1      ! Need some slack so we don't lose intrs.
7599
7600          /*
7601           * Handle the unlikely case of %tick wrapping.
7602           *
7603           * This should only happen every 10 years or more.
7604           *
7605           * We need to increment the time base by the size of %tick in
7606           * microseconds.  This will require some divides and multiplies
7607           * which can take time.  So we re-read %tick.
7608           *
7609           */
7610
7611          /* XXXXX NOT IMPLEMENTED */
7612
7613
7614
76151:
7616          add       %o2, %o0, %o2
7617          andn      %o2, %o3, %o4
7618          brlz,pn   %o4, Ltick_ovflw
7619           cmp      %o2, %o1  ! Has this tick passed?
7620          blt,pn    %xcc, 1b  ! Yes
7621           nop
7622
7623#ifdef BB_ERRATA_1
7624          ba,a      2f
7625           nop
7626#else
7627          retl
7628           wr       %o2, TICK_CMPR
7629#endif
7630
7631Ltick_ovflw:
7632/*
7633 * When we get here tick_cmpr has wrapped, but we don't know if %tick
7634 * has wrapped.  If bit 62 is set then we have not wrapped and we can
7635 * use the current value of %o4 as %tick.  Otherwise we need to return
7636 * to our loop with %o4 as %tick_cmpr (%o2).
7637 */
7638          srlx      %o3, 1, %o5
7639          btst      %o5, %o1
7640          bz,pn     %xcc, 1b
7641           mov      %o4, %o2
7642#ifdef BB_ERRATA_1
7643          ba,a      2f
7644           nop
7645          .align    64
76462:        wr        %o2, TICK_CMPR
7647          rd        TICK_CMPR, %g0
7648          retl
7649           nop
7650#else
7651          retl
7652           wr       %o2, TICK_CMPR
7653#endif
7654
7655/*
7656 * next_stick(long increment)
7657 *
7658 * Sets the %stick_cmpr register to fire off in `increment' machine
7659 * cycles in the future.  Also handles %stick wraparound.  In 32-bit
7660 * mode we're limited to a 32-bit increment.
7661 */
7662ENTRY(next_stick)
7663          rd        STICK_CMPR, %o2
7664          rd        STICK, %o1
7665
7666          mov       1, %o3              ! Mask off high bits of these registers
7667          sllx      %o3, 63, %o3
7668          andn      %o1, %o3, %o1
7669          andn      %o2, %o3, %o2
7670          cmp       %o1, %o2  ! Did we wrap?  (stick < stick_cmpr)
7671          bgt,pt    %xcc, 1f
7672           add      %o1, 1000, %o1      ! Need some slack so we don't lose intrs.
7673
7674          /*
7675           * Handle the unlikely case of %stick wrapping.
7676           *
7677           * This should only happen every 10 years or more.
7678           *
7679           * We need to increment the time base by the size of %stick in
7680           * microseconds.  This will require some divides and multiplies
7681           * which can take time.  So we re-read %stick.
7682           *
7683           */
7684
7685          /* XXXXX NOT IMPLEMENTED */
7686
7687
7688
76891:
7690          add       %o2, %o0, %o2
7691          andn      %o2, %o3, %o4
7692          brlz,pn   %o4, Lstick_ovflw
7693           cmp      %o2, %o1  ! Has this stick passed?
7694          blt,pn    %xcc, 1b  ! Yes
7695           nop
7696          retl
7697           wr       %o2, STICK_CMPR
7698
7699Lstick_ovflw:
7700/*
7701 * When we get here tick_cmpr has wrapped, but we don't know if %stick
7702 * has wrapped.  If bit 62 is set then we have not wrapped and we can
7703 * use the current value of %o4 as %stick.  Otherwise we need to return
7704 * to our loop with %o4 as %stick_cmpr (%o2).
7705 */
7706          srlx      %o3, 1, %o5
7707          btst      %o5, %o1
7708          bz,pn     %xcc, 1b
7709           mov      %o4, %o2
7710          retl
7711           wr       %o2, STICK_CMPR
7712
7713/*
7714 * next_stick_init()
7715 *
7716 * Sets the %stick_cmpr register to the value retrieved from %stick so
7717 * next_stick() does not spend too much time in the function when called
7718 * for the first time.
7719 * This has been observed on (at least) a SPARC-T5 (sun4v) system where
7720 * the %stick_cmpr ends up being less than the %stick value and then
7721 * the stickitr() interrupt is never triggered.
7722 */
7723ENTRY(next_stick_init)
7724          rd        STICK, %o0
7725          mov       1, %o1              ! Mask off high bits of the register
7726          sllx      %o1, 63, %o1
7727          andn      %o0, %o1, %o0
7728          retl
7729           wr       %o0, STICK_CMPR
7730
7731ENTRY(setjmp)
7732          save      %sp, -CC64FSZ, %sp  ! Need a frame to return to.
7733          flushw
7734          stx       %fp, [%i0+0]        ! 64-bit stack pointer
7735          stx       %i7, [%i0+8]        ! 64-bit return pc
7736          ret
7737           restore  %g0, 0, %o0
7738
7739          .data
7740Lpanic_ljmp:
7741          .asciz    "longjmp botch"
7742          _ALIGN
7743          .text
7744
7745ENTRY(longjmp)
7746          save      %sp, -CC64FSZ, %sp  ! prepare to restore to (old) frame
7747          flushw
7748          mov       1, %i2
7749          ldx       [%i0+0], %fp        ! get return stack
7750          ldx       [%i0+8], %i7        ! get rpc
7751          ret
7752           restore  %i2, 0, %o0
7753
7754#if defined(DDB) || defined(KGDB)
7755          /*
7756           * Debug stuff.  Dump the trap registers into buffer & set tl=0.
7757           *
7758           *  %o0 = *ts
7759           */
7760ENTRY(savetstate)
7761          mov       %o0, %o1
7762          rdpr      %tl, %o0
7763          brz       %o0, 2f
7764           mov      %o0, %o2
77651:
7766          rdpr      %tstate, %o3
7767          stx       %o3, [%o1]
7768          deccc     %o2
7769          inc       8, %o1
7770          rdpr      %tpc, %o4
7771          stx       %o4, [%o1]
7772          inc       8, %o1
7773          rdpr      %tnpc, %o5
7774          stx       %o5, [%o1]
7775          inc       8, %o1
7776          rdpr      %tt, %o4
7777          stx       %o4, [%o1]
7778          inc       8, %o1
7779          bnz       1b
7780           wrpr     %o2, 0, %tl
77812:
7782          retl
7783           nop
7784
7785          /*
7786           * Debug stuff.  Restore trap registers from buffer.
7787           *
7788           *  %o0 = %tl
7789           *  %o1 = *ts
7790           *
7791           * Maybe this should be re-written to increment tl instead of decrementing.
7792           */
7793ENTRY(restoretstate)
7794          flushw                        ! Make sure we don't have stack probs & lose hibits of %o
7795          brz,pn    %o0, 2f
7796           mov      %o0, %o2
7797          wrpr      %o0, 0, %tl
77981:
7799          ldx       [%o1], %o3
7800          deccc     %o2
7801          inc       8, %o1
7802          wrpr      %o3, 0, %tstate
7803          ldx       [%o1], %o4
7804          inc       8, %o1
7805          wrpr      %o4, 0, %tpc
7806          ldx       [%o1], %o5
7807          inc       8, %o1
7808          wrpr      %o5, 0, %tnpc
7809          ldx       [%o1], %o4
7810          inc       8, %o1
7811          wrpr      %o4, 0, %tt
7812          bnz       1b
7813           wrpr     %o2, 0, %tl
78142:
7815          retl
7816           wrpr     %o0, 0, %tl
7817
7818          /*
7819           * Switch to context in abs(%o0)
7820           */
7821ENTRY(switchtoctx_us)
7822          set       DEMAP_CTX_SECONDARY, %o3
7823          stxa      %o3, [%o3] ASI_DMMU_DEMAP
7824          mov       CTX_SECONDARY, %o4
7825          stxa      %o3, [%o3] ASI_IMMU_DEMAP
7826          membar    #Sync
7827          stxa      %o0, [%o4] ASI_DMMU           ! Maybe we should invalid
7828          sethi     %hi(KERNBASE), %o2
7829          membar    #Sync
7830          flush     %o2
7831          retl
7832           nop
7833
7834ENTRY(switchtoctx_usiii)
7835          mov       CTX_SECONDARY, %o4
7836          ldxa      [%o4] ASI_DMMU, %o2           ! Load secondary context
7837          mov       CTX_PRIMARY, %o5
7838          ldxa      [%o5] ASI_DMMU, %o1           ! Save primary context
7839          membar    #LoadStore
7840          stxa      %o2, [%o5] ASI_DMMU           ! Insert secondary for demap
7841          membar    #Sync
7842          set       DEMAP_CTX_PRIMARY, %o3
7843          stxa      %o3, [%o3] ASI_DMMU_DEMAP
7844          membar    #Sync
7845          stxa      %o0, [%o4] ASI_DMMU           ! Maybe we should invalid
7846          membar    #Sync
7847          stxa      %o1, [%o5] ASI_DMMU           ! Restore primary context
7848          sethi     %hi(KERNBASE), %o2
7849          membar    #Sync
7850          flush     %o2
7851          retl
7852           nop
7853
7854#ifndef _LP64
7855          /*
7856           * Convert to 32-bit stack then call OF_sym2val()
7857           */
7858ENTRY(OF_sym2val32)
7859          save      %sp, -CC64FSZ, %sp
7860          btst      7, %i0
7861          bnz,pn    %icc, 1f
7862           add      %sp, BIAS, %o1
7863          btst      1, %sp
7864          movnz     %icc, %o1, %sp
7865          call      _C_LABEL(OF_sym2val)
7866           mov      %i0, %o0
78671:
7868          ret
7869           restore  %o0, 0, %o0
7870
7871          /*
7872           * Convert to 32-bit stack then call OF_val2sym()
7873           */
7874ENTRY(OF_val2sym32)
7875          save      %sp, -CC64FSZ, %sp
7876          btst      7, %i0
7877          bnz,pn    %icc, 1f
7878           add      %sp, BIAS, %o1
7879          btst      1, %sp
7880          movnz     %icc, %o1, %sp
7881          call      _C_LABEL(OF_val2sym)
7882           mov      %i0, %o0
78831:
7884          ret
7885           restore  %o0, 0, %o0
7886#endif /* _LP64 */
7887#endif /* DDB */
7888
7889
7890#if defined(MULTIPROCESSOR)
7891/*
7892 * IPI target function to setup a C compatible environment and call a MI function.
7893 *
7894 * On entry:
7895 *        We are on one of the alternate set of globals
7896 *        %g2 = function to call
7897 *        %g3 = single argument to called function
7898 */
7899ENTRY(sparc64_ipi_ccall)
7900#ifdef TRAPS_USE_IG
7901          wrpr      %g0, PSTATE_KERN|PSTATE_IG, %pstate     ! DEBUG
7902#endif
7903          TRAP_SETUP(-CC64FSZ-TF_SIZE)
7904
7905#ifdef DEBUG
7906          rdpr      %tt, %o1  ! debug
7907          sth       %o1, [%sp + CC64FSZ + STKB + TF_TT]! debug
7908#endif
7909          mov       %g3, %o0                      ! save argument of function to call
7910          mov       %g2, %o5                      ! save function pointer
7911
7912          wrpr      %g0, PSTATE_KERN, %pstate     ! Get back to normal globals
7913          stx       %g1, [%sp + CC64FSZ + STKB + TF_G + ( 1*8)]
7914          rdpr      %tpc, %o2                     ! (pc)
7915          stx       %g2, [%sp + CC64FSZ + STKB + TF_G + ( 2*8)]
7916          rdpr      %tstate, %g1
7917          stx       %g3, [%sp + CC64FSZ + STKB + TF_G + ( 3*8)]
7918          rdpr      %tnpc, %o3
7919          stx       %g4, [%sp + CC64FSZ + STKB + TF_G + ( 4*8)]
7920          rd        %y, %o4
7921          stx       %g5, [%sp + CC64FSZ + STKB + TF_G + ( 5*8)]
7922          stx       %g6, [%sp + CC64FSZ + STKB + TF_G + ( 6*8)]
7923          stx       %g7, [%sp + CC64FSZ + STKB + TF_G + ( 7*8)]
7924
7925          stx       %g1, [%sp + CC64FSZ + STKB + TF_TSTATE]
7926          stx       %o2, [%sp + CC64FSZ + STKB + TF_PC]
7927          stx       %o3, [%sp + CC64FSZ + STKB + TF_NPC]
7928          st        %o4, [%sp + CC64FSZ + STKB + TF_Y]
7929
7930          rdpr      %pil, %g5
7931          stb       %g5, [%sp + CC64FSZ + STKB + TF_PIL]
7932          stb       %g5, [%sp + CC64FSZ + STKB + TF_OLDPIL]
7933
7934          rdpr      %tl, %g7
7935          dec       %g7
7936          movrlz    %g7, %g0, %g7
7937          wrpr      %g0, %g7, %tl
7938          !! In the EMBEDANY memory model %g4 points to the start of the data segment.
7939          !! In our case we need to clear it before calling any C-code
7940          clr       %g4
7941          wr        %g0, ASI_NUCLEUS, %asi                            ! default kernel ASI
7942
7943          call %o5                                          ! call function
7944           nop
7945
7946          b         return_from_trap                        ! and return from IPI
7947           ldx      [%sp + CC64FSZ + STKB + TF_TSTATE], %g1 ! Load this for return_from_trap
7948
7949#endif
7950
7951
7952          .data
7953          _ALIGN
7954#if NKSYMS || defined(DDB) || defined(MODULAR)
7955          .globl    _C_LABEL(esym)
7956_C_LABEL(esym):
7957          POINTER   0
7958          .globl    _C_LABEL(ssym)
7959_C_LABEL(ssym):
7960          POINTER   0
7961#endif
7962          .comm     _C_LABEL(promvec), PTRSZ
7963
7964#ifdef DEBUG
7965          .comm     _C_LABEL(trapdebug), 4
7966          .comm     _C_LABEL(pmapdebug), 4
7967#endif
7968