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