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