Annotation of src/sys/arch/sparc/sparc/locore.s, Revision 1.35
1.1 deraadt 1: /*
2: * Copyright (c) 1992, 1993
3: * The Regents of the University of California. All rights reserved.
4: *
5: * This software was developed by the Computer Systems Engineering group
6: * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
7: * contributed to Berkeley.
8: *
9: * All advertising materials mentioning features or use of this software
10: * must display the following acknowledgement:
11: * This product includes software developed by the University of
12: * California, Lawrence Berkeley Laboratory.
13: *
14: * Redistribution and use in source and binary forms, with or without
15: * modification, are permitted provided that the following conditions
16: * are met:
17: * 1. Redistributions of source code must retain the above copyright
18: * notice, this list of conditions and the following disclaimer.
19: * 2. Redistributions in binary form must reproduce the above copyright
20: * notice, this list of conditions and the following disclaimer in the
21: * documentation and/or other materials provided with the distribution.
22: * 3. All advertising materials mentioning features or use of this software
23: * must display the following acknowledgement:
24: * This product includes software developed by the University of
25: * California, Berkeley and its contributors.
26: * 4. Neither the name of the University nor the names of its contributors
27: * may be used to endorse or promote products derived from this software
28: * without specific prior written permission.
29: *
30: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
31: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
32: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
34: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
35: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
36: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
37: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
38: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
39: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
40: * SUCH DAMAGE.
41: *
1.10 deraadt 42: * @(#)locore.s 8.4 (Berkeley) 12/10/93
1.1 deraadt 43: */
44:
45: #define LOCORE
46: #include "assym.s"
47: #include <sparc/sparc/intreg.h>
48: #include <sparc/sparc/timerreg.h>
49: #ifdef notyet
50: #include <sparc/sparc/vaddrs.h>
51: #include <sparc/dev/zsreg.h>
52: #endif
53: #include <machine/ctlreg.h>
54: #include <machine/psl.h>
55: #include <machine/signal.h>
56: #include <machine/trap.h>
57:
58: /*
59: * GNU assembler does not understand `.empty' directive; Sun assembler
60: * gripes about labels without it. To allow cross-compilation using
61: * the Sun assembler, and because .empty directives are useful documentation,
62: * we use this trick.
63: */
64: #ifdef SUN_AS
65: #define EMPTY .empty
66: #else
67: #define EMPTY /* .empty */
68: #endif
69:
70: /* use as needed to align things on longword boundaries */
71: #define ALIGN .align 4
72:
73: /*
74: * CCFSZ (C Compiler Frame SiZe) is the size of a stack frame required if
75: * a function is to call C code. It should be just 64, but Sun defined
76: * their frame with space to hold arguments 0 through 5 (plus some junk),
77: * and varargs routines (such as printf) demand this, and gcc uses this
78: * area at times anyway.
79: */
80: #define CCFSZ 96
81:
82: /*
83: * A handy macro for maintaining instrumentation counters.
84: * Note that this clobbers %o0 and %o1. Normal usage is
85: * something like:
86: * foointr:
87: * TRAP_SETUP(...) ! makes %o registers safe
88: * INCR(_cnt+V_FOO) ! count a foo
89: */
90: #define INCR(what) \
91: sethi %hi(what), %o0; \
92: ld [%o0 + %lo(what)], %o1; \
93: inc %o1; \
94: st %o1, [%o0 + %lo(what)]
95:
96: /*
97: * Another handy macro: load one register window, given `base' address.
98: * This can be either a simple register (e.g., %sp) or include an initial
99: * offset (e.g., %g6 + PCB_RW).
100: */
101: #define LOADWIN(addr) \
102: ldd [addr], %l0; \
103: ldd [addr + 8], %l2; \
104: ldd [addr + 16], %l4; \
105: ldd [addr + 24], %l6; \
106: ldd [addr + 32], %i0; \
107: ldd [addr + 40], %i2; \
108: ldd [addr + 48], %i4; \
109: ldd [addr + 56], %i6
110:
111: /*
112: * To return from trap we need the two-instruction sequence
113: * `jmp %l1; rett %l2', which is defined here for convenience.
114: */
115: #define RETT jmp %l1; rett %l2
116:
117: .data
118: /*
119: * The interrupt stack.
120: *
121: * This is the very first thing in the data segment, and therefore has
122: * the lowest kernel stack address. We count on this in the interrupt
123: * trap-frame setup code, since we may need to switch from the kernel
124: * stack to the interrupt stack (iff we are not already on the interrupt
125: * stack). One sethi+cmp is all we need since this is so carefully
126: * arranged.
127: */
128: .globl _intstack
129: .globl _eintstack
130: _intstack:
1.13 deraadt 131: .skip 128 * 128 ! 16k = 128 128-byte stack frames
1.1 deraadt 132: _eintstack:
133:
134: /*
135: * When a process exits and its u. area goes away, we set cpcb to point
136: * to this `u.', leaving us with something to use for an interrupt stack,
137: * and letting all the register save code have a pcb_uw to examine.
138: * This is also carefully arranged (to come just before u0, so that
139: * process 0's kernel stack can quietly overrun into it during bootup, if
140: * we feel like doing that).
141: */
142: .globl _idle_u
143: _idle_u:
1.13 deraadt 144: .skip USPACE
1.1 deraadt 145:
146: /*
147: * Process 0's u.
148: *
149: * This must be aligned on an 8 byte boundary.
150: */
151: .globl _u0
1.13 deraadt 152: _u0: .skip USPACE
1.1 deraadt 153: estack0:
154:
155: #ifdef KGDB
156: /*
157: * Another item that must be aligned, easiest to put it here.
158: */
159: KGDB_STACK_SIZE = 2048
160: .globl _kgdb_stack
161: _kgdb_stack:
162: .skip KGDB_STACK_SIZE ! hope this is enough
163: #endif
164:
165: /*
166: * _cpcb points to the current pcb (and hence u. area).
167: * Initially this is the special one.
168: */
169: .globl _cpcb
170: _cpcb: .word _u0
171:
1.9 deraadt 172: /*
1.13 deraadt 173: * _cputyp is the current cpu type, used to distinguish between
174: * the many variations of different sun4* machines. It contains
175: * the value CPU_SUN4, CPU_SUN4C, or CPU_SUN4M.
1.9 deraadt 176: */
177: .globl _cputyp
178: _cputyp:
179: .word 1
1.18 deraadt 180: #if defined(SUN4C) || defined(SUN4M)
181: _cputypval:
182: .asciz "sun4c"
183: .ascii " "
184: _cputypvar:
185: .asciz "compatibility"
186: _cputypvallen = _cputypvar - _cputypval
187: ALIGN
188: #endif
189:
1.13 deraadt 190: /*
191: * There variables are pointed to by the cpp symbols PGSHIFT, NBPG,
192: * and PGOFSET.
193: */
194: .globl _pgshift, _nbpg, _pgofset
195: _pgshift:
196: .word 1
197: _nbpg:
198: .word 1
199: _pgofset:
200: .word 1
1.9 deraadt 201:
202: #if defined(SUN4M)
203: _mapme:
204: .asciz "0 0 f8000000 15c6a0 map-pages"
205: #endif
206:
207: #if !defined(SUN4M)
208: sun4m_notsup:
1.20 deraadt 209: .asciz "cr .( NetBSD/sparc: this kernel does not support the sun4m) cr"
1.9 deraadt 210: #endif
1.13 deraadt 211: #if !defined(SUN4C)
1.9 deraadt 212: sun4c_notsup:
1.20 deraadt 213: .asciz "cr .( NetBSD/sparc: this kernel does not support the sun4c) cr"
1.13 deraadt 214: #endif
215: #if !defined(SUN4)
216: sun4_notsup:
1.20 deraadt 217: ! the extra characters at the end are to ensure the zs fifo drains
218: ! before we halt. Sick, eh?
219: .asciz "NetBSD/sparc: this kernel does not support the sun4\n\r \b"
1.9 deraadt 220: #endif
221: ALIGN
222:
1.1 deraadt 223: .text
224:
225: /*
1.26 deraadt 226: * The first thing in the real text segment is the trap vector table,
227: * which must be aligned on a 4096 byte boundary. The text segment
228: * starts beyond page 0 of KERNBASE so that there is a red zone
229: * between user and kernel space. Since the boot ROM loads us at
230: * 0x4000, it is far easier to start at KERNBASE+0x4000 than to
231: * buck the trend. This is two or four pages in (depending on if
232: * pagesize is 8192 or 4096). We place two items in this area:
233: * the message buffer (phys addr 0) and the IE_reg (phys addr 0x2000).
234: * because the message buffer is in our "red zone" between user and
235: * kernel space we remap it in configure() to another location and
236: * invalidate the mapping at KERNBASE.
237: */
238: .globl _msgbuf
239: _msgbuf = KERNBASE
240:
241: /*
242: * We need to map the interrupt enable register very early on in the
243: * boot process, so that we can handle NMIs (parity errors) halfway
244: * sensibly during boot. We use virtual address f8002000 (`page 2')
245: * for this, wasting a page of physical memory.
1.1 deraadt 246: */
1.20 deraadt 247: IE_reg_addr = KERNBASE + 8192 ! this page not used; points to IEreg
1.1 deraadt 248:
249: /*
250: * Each trap has room for four instructions, of which one perforce must
251: * be a branch. On entry the hardware has copied pc and npc to %l1 and
252: * %l2 respectively. We use two more to read the psr into %l0, and to
253: * put the trap type value into %l3 (with a few exceptions below).
254: * We could read the trap type field of %tbr later in the code instead,
255: * but there is no need, and that would require more instructions
256: * (read+mask, vs 1 `mov' here).
257: *
258: * I used to generate these numbers by address arithmetic, but gas's
259: * expression evaluator has about as much sense as your average slug
260: * (oddly enough, the code looks about as slimy too). Thus, all the
261: * trap numbers are given as arguments to the trap macros. This means
262: * there is one line per trap. Sigh.
263: *
264: * Note that only the local registers may be used, since the trap
265: * window is potentially the last window. Its `in' registers are
266: * the previous window's outs (as usual), but more important, its
267: * `out' registers may be in use as the `topmost' window's `in' registers.
268: * The global registers are of course verboten (well, until we save
269: * them away).
270: *
271: * Hardware interrupt vectors can be `linked'---the linkage is to regular
272: * C code---or rewired to fast in-window handlers. The latter are good
273: * for unbuffered hardware like the Zilog serial chip and the AMD audio
274: * chip, where many interrupts can be handled trivially with pseudo-DMA or
275: * similar. Only one `fast' interrupt can be used per level, however, and
276: * direct and `fast' interrupts are incompatible. Routines in intr.c
277: * handle setting these, with optional paranoia.
278: */
279:
280: /* regular vectored traps */
281: #define VTRAP(type, label) \
282: mov (type), %l3; b label; mov %psr, %l0; nop
283:
284: /* hardware interrupts (can be linked or made `fast') */
285: #define HARDINT(lev) \
286: mov (lev), %l3; b _sparc_interrupt; mov %psr, %l0; nop
287:
288: /* software interrupts (may not be made direct, sorry---but you
289: should not be using them trivially anyway) */
290: #define SOFTINT(lev, bit) \
291: mov (lev), %l3; mov (bit), %l4; b softintr; mov %psr, %l0
292:
293: /* traps that just call trap() */
294: #define TRAP(type) VTRAP(type, slowtrap)
295:
296: /* architecturally undefined traps (cause panic) */
297: #define UTRAP(type) VTRAP(type, slowtrap)
298:
299: /* software undefined traps (may be replaced) */
300: #define STRAP(type) VTRAP(type, slowtrap)
301:
302: /* breakpoint acts differently under kgdb */
303: #ifdef KGDB
304: #define BPT VTRAP(T_BREAKPOINT, bpt)
305: #define BPT_KGDB_EXEC VTRAP(T_KGDB_EXEC, bpt)
306: #else
307: #define BPT TRAP(T_BREAKPOINT)
308: #define BPT_KGDB_EXEC TRAP(T_KGDB_EXEC)
309: #endif
310:
311: /* special high-speed 1-instruction-shaved-off traps (get nothing in %l3) */
312: #define SYSCALL b syscall; mov %psr, %l0; nop; nop
313: #define WINDOW_OF b window_of; mov %psr, %l0; nop; nop
314: #define WINDOW_UF b window_uf; mov %psr, %l0; nop; nop
315: #ifdef notyet
316: #define ZS_INTERRUPT b zshard; mov %psr, %l0; nop; nop
317: #else
318: #define ZS_INTERRUPT HARDINT(12)
319: #endif
320:
321: .globl start
322: .globl _trapbase
323: start:
324: _trapbase:
325: /* trap 0 is special since we cannot receive it */
326: b dostart; nop; nop; nop ! 00 = reset (fake)
327: VTRAP(T_TEXTFAULT, memfault) ! 01 = instr. fetch fault
328: TRAP(T_ILLINST) ! 02 = illegal instruction
329: TRAP(T_PRIVINST) ! 03 = privileged instruction
330: TRAP(T_FPDISABLED) ! 04 = fp instr, but EF bit off in psr
331: WINDOW_OF ! 05 = window overflow
332: WINDOW_UF ! 06 = window underflow
333: TRAP(T_ALIGN) ! 07 = address alignment error
334: VTRAP(T_FPE, fp_exception) ! 08 = fp exception
335: VTRAP(T_DATAFAULT, memfault) ! 09 = data fetch fault
336: TRAP(T_TAGOF) ! 0a = tag overflow
337: UTRAP(0x0b)
338: UTRAP(0x0c)
339: UTRAP(0x0d)
340: UTRAP(0x0e)
341: UTRAP(0x0f)
342: UTRAP(0x10)
343: SOFTINT(1, IE_L1) ! 11 = level 1 interrupt
344: HARDINT(2) ! 12 = level 2 interrupt
345: HARDINT(3) ! 13 = level 3 interrupt
346: SOFTINT(4, IE_L4) ! 14 = level 4 interrupt
347: HARDINT(5) ! 15 = level 5 interrupt
348: SOFTINT(6, IE_L6) ! 16 = level 6 interrupt
349: HARDINT(7) ! 17 = level 7 interrupt
350: HARDINT(8) ! 18 = level 8 interrupt
351: HARDINT(9) ! 19 = level 9 interrupt
352: HARDINT(10) ! 1a = level 10 interrupt
353: HARDINT(11) ! 1b = level 11 interrupt
354: ZS_INTERRUPT ! 1c = level 12 (zs) interrupt
355: HARDINT(13) ! 1d = level 13 interrupt
356: HARDINT(14) ! 1e = level 14 interrupt
357: VTRAP(15, nmi) ! 1f = nonmaskable interrupt
358: UTRAP(0x20)
359: UTRAP(0x21)
360: UTRAP(0x22)
361: UTRAP(0x23)
1.25 deraadt 362: TRAP(T_CPDISABLED) ! 24 = coprocessor instr, EC bit off in psr
1.1 deraadt 363: UTRAP(0x25)
364: UTRAP(0x26)
365: UTRAP(0x27)
1.25 deraadt 366: TRAP(T_CPEXCEPTION) ! 28 = coprocessor exception
1.1 deraadt 367: UTRAP(0x29)
368: UTRAP(0x2a)
369: UTRAP(0x2b)
370: UTRAP(0x2c)
371: UTRAP(0x2d)
372: UTRAP(0x2e)
373: UTRAP(0x2f)
374: UTRAP(0x30)
375: UTRAP(0x31)
376: UTRAP(0x32)
377: UTRAP(0x33)
378: UTRAP(0x34)
379: UTRAP(0x35)
1.25 deraadt 380: UTRAP(0x36)
1.1 deraadt 381: UTRAP(0x37)
382: UTRAP(0x38)
383: UTRAP(0x39)
384: UTRAP(0x3a)
385: UTRAP(0x3b)
386: UTRAP(0x3c)
387: UTRAP(0x3d)
388: UTRAP(0x3e)
389: UTRAP(0x3f)
1.25 deraadt 390: UTRAP(0x40)
1.1 deraadt 391: UTRAP(0x41)
392: UTRAP(0x42)
393: UTRAP(0x43)
394: UTRAP(0x44)
395: UTRAP(0x45)
396: UTRAP(0x46)
397: UTRAP(0x47)
398: UTRAP(0x48)
399: UTRAP(0x49)
400: UTRAP(0x4a)
401: UTRAP(0x4b)
402: UTRAP(0x4c)
403: UTRAP(0x4d)
404: UTRAP(0x4e)
405: UTRAP(0x4f)
406: UTRAP(0x50)
407: UTRAP(0x51)
408: UTRAP(0x52)
409: UTRAP(0x53)
410: UTRAP(0x54)
411: UTRAP(0x55)
412: UTRAP(0x56)
413: UTRAP(0x57)
414: UTRAP(0x58)
415: UTRAP(0x59)
416: UTRAP(0x5a)
417: UTRAP(0x5b)
418: UTRAP(0x5c)
419: UTRAP(0x5d)
420: UTRAP(0x5e)
421: UTRAP(0x5f)
422: UTRAP(0x60)
423: UTRAP(0x61)
424: UTRAP(0x62)
425: UTRAP(0x63)
426: UTRAP(0x64)
427: UTRAP(0x65)
428: UTRAP(0x66)
429: UTRAP(0x67)
430: UTRAP(0x68)
431: UTRAP(0x69)
432: UTRAP(0x6a)
433: UTRAP(0x6b)
434: UTRAP(0x6c)
435: UTRAP(0x6d)
436: UTRAP(0x6e)
437: UTRAP(0x6f)
438: UTRAP(0x70)
439: UTRAP(0x71)
440: UTRAP(0x72)
441: UTRAP(0x73)
442: UTRAP(0x74)
443: UTRAP(0x75)
444: UTRAP(0x76)
445: UTRAP(0x77)
446: UTRAP(0x78)
447: UTRAP(0x79)
448: UTRAP(0x7a)
449: UTRAP(0x7b)
450: UTRAP(0x7c)
451: UTRAP(0x7d)
452: UTRAP(0x7e)
453: UTRAP(0x7f)
1.3 deraadt 454: SYSCALL ! 80 = sun syscall
1.1 deraadt 455: BPT ! 81 = pseudo breakpoint instruction
456: TRAP(T_DIV0) ! 82 = divide by zero
457: TRAP(T_FLUSHWIN) ! 83 = flush windows
458: TRAP(T_CLEANWIN) ! 84 = provide clean windows
459: TRAP(T_RANGECHECK) ! 85 = ???
460: TRAP(T_FIXALIGN) ! 86 = fix up unaligned accesses
461: TRAP(T_INTOF) ! 87 = integer overflow
1.33 christos 462: SYSCALL ! 88 = svr4 syscall
1.1 deraadt 463: SYSCALL ! 89 = bsd syscall
1.33 christos 464: BPT_KGDB_EXEC ! 8a = enter kernel gdb on kernel startup
1.1 deraadt 465: STRAP(0x8b)
466: STRAP(0x8c)
467: STRAP(0x8d)
468: STRAP(0x8e)
469: STRAP(0x8f)
470: STRAP(0x90)
471: STRAP(0x91)
472: STRAP(0x92)
473: STRAP(0x93)
474: STRAP(0x94)
475: STRAP(0x95)
476: STRAP(0x96)
477: STRAP(0x97)
478: STRAP(0x98)
479: STRAP(0x99)
480: STRAP(0x9a)
481: STRAP(0x9b)
482: STRAP(0x9c)
483: STRAP(0x9d)
484: STRAP(0x9e)
485: STRAP(0x9f)
486: STRAP(0xa0)
487: STRAP(0xa1)
488: STRAP(0xa2)
489: STRAP(0xa3)
490: STRAP(0xa4)
491: STRAP(0xa5)
492: STRAP(0xa6)
493: STRAP(0xa7)
494: STRAP(0xa8)
495: STRAP(0xa9)
496: STRAP(0xaa)
497: STRAP(0xab)
498: STRAP(0xac)
499: STRAP(0xad)
500: STRAP(0xae)
501: STRAP(0xaf)
502: STRAP(0xb0)
503: STRAP(0xb1)
504: STRAP(0xb2)
505: STRAP(0xb3)
506: STRAP(0xb4)
507: STRAP(0xb5)
508: STRAP(0xb6)
509: STRAP(0xb7)
510: STRAP(0xb8)
511: STRAP(0xb9)
512: STRAP(0xba)
513: STRAP(0xbb)
514: STRAP(0xbc)
515: STRAP(0xbd)
516: STRAP(0xbe)
517: STRAP(0xbf)
518: STRAP(0xc0)
519: STRAP(0xc1)
520: STRAP(0xc2)
521: STRAP(0xc3)
522: STRAP(0xc4)
523: STRAP(0xc5)
524: STRAP(0xc6)
525: STRAP(0xc7)
526: STRAP(0xc8)
527: STRAP(0xc9)
528: STRAP(0xca)
529: STRAP(0xcb)
530: STRAP(0xcc)
531: STRAP(0xcd)
532: STRAP(0xce)
533: STRAP(0xcf)
534: STRAP(0xd0)
535: STRAP(0xd1)
536: STRAP(0xd2)
537: STRAP(0xd3)
538: STRAP(0xd4)
539: STRAP(0xd5)
540: STRAP(0xd6)
541: STRAP(0xd7)
542: STRAP(0xd8)
543: STRAP(0xd9)
544: STRAP(0xda)
545: STRAP(0xdb)
546: STRAP(0xdc)
547: STRAP(0xdd)
548: STRAP(0xde)
549: STRAP(0xdf)
550: STRAP(0xe0)
551: STRAP(0xe1)
552: STRAP(0xe2)
553: STRAP(0xe3)
554: STRAP(0xe4)
555: STRAP(0xe5)
556: STRAP(0xe6)
557: STRAP(0xe7)
558: STRAP(0xe8)
559: STRAP(0xe9)
560: STRAP(0xea)
561: STRAP(0xeb)
562: STRAP(0xec)
563: STRAP(0xed)
564: STRAP(0xee)
565: STRAP(0xef)
566: STRAP(0xf0)
567: STRAP(0xf1)
568: STRAP(0xf2)
569: STRAP(0xf3)
570: STRAP(0xf4)
571: STRAP(0xf5)
572: STRAP(0xf6)
573: STRAP(0xf7)
574: STRAP(0xf8)
575: STRAP(0xf9)
576: STRAP(0xfa)
577: STRAP(0xfb)
578: STRAP(0xfc)
579: STRAP(0xfd)
580: STRAP(0xfe)
581: STRAP(0xff)
582:
1.20 deraadt 583: /*
1.26 deraadt 584: * pad the trap table to max page size
1.20 deraadt 585: * trap table size is 0x100 * 4instr * 4byte/instr = 4096 bytes
586: * need to .skip 4096 to pad to page size
587: */
588: .skip 4096
589:
1.1 deraadt 590: /* the message buffer is always mapped */
591: _msgbufmapped:
592: .word 1
593:
594: #ifdef DEBUG
595: /*
596: * A hardware red zone is impossible. We simulate one in software by
597: * keeping a `red zone' pointer; if %sp becomes less than this, we panic.
598: * This is expensive and is only enabled when debugging.
599: */
600: #define REDSIZE (8*96) /* some room for bouncing */
601: #define REDSTACK 2048 /* size of `panic: stack overflow' region */
602: .data
603: _redzone:
604: .word _idle_u + REDSIZE
605: _redstack:
606: .skip REDSTACK
607: .text
608: Lpanic_red:
609: .asciz "stack overflow"
610: ALIGN
611:
612: /* set stack pointer redzone to base+minstack; alters base */
613: #define SET_SP_REDZONE(base, tmp) \
614: add base, REDSIZE, base; \
615: sethi %hi(_redzone), tmp; \
616: st base, [tmp + %lo(_redzone)]
617:
618: /* variant with a constant */
619: #define SET_SP_REDZONE_CONST(const, tmp1, tmp2) \
620: set (const) + REDSIZE, tmp1; \
621: sethi %hi(_redzone), tmp2; \
622: st tmp1, [tmp2 + %lo(_redzone)]
623:
624: /* check stack pointer against redzone (uses two temps) */
625: #define CHECK_SP_REDZONE(t1, t2) \
626: sethi %hi(_redzone), t1; \
627: ld [t1 + %lo(_redzone)], t2; \
628: cmp %sp, t2; /* if sp >= t2, not in red zone */ \
629: bgeu 7f; nop; /* and can continue normally */ \
630: /* move to panic stack */ \
631: st %g0, [t1 + %lo(_redzone)]; \
632: set _redstack + REDSTACK - 96, %sp; \
633: /* prevent panic() from lowering ipl */ \
634: sethi %hi(_panicstr), t2; \
635: set Lpanic_red, t2; \
636: st t2, [t1 + %lo(_panicstr)]; \
637: rd %psr, t1; /* t1 = splhigh() */ \
638: or t1, PSR_PIL, t2; \
639: wr t2, 0, %psr; \
640: wr t2, PSR_ET, %psr; /* turn on traps */ \
641: nop; nop; nop; \
1.4 deraadt 642: save %sp, -CCFSZ, %sp; /* preserve current window */ \
1.1 deraadt 643: sethi %hi(Lpanic_red), %o0; \
644: call _panic; or %o0, %lo(Lpanic_red), %o0; \
645: 7:
646:
647: #else
648:
649: #define SET_SP_REDZONE(base, tmp)
650: #define SET_SP_REDZONE_CONST(const, t1, t2)
651: #define CHECK_SP_REDZONE(t1, t2)
652: #endif
653:
1.9 deraadt 654: #if defined(SUN4) || defined(SUN4C)
1.1 deraadt 655: /*
656: * The window code must verify user stack addresses before using them.
657: * A user stack pointer is invalid if:
658: * - it is not on an 8 byte boundary;
659: * - its pages (a register window, being 64 bytes, can occupy
660: * two pages) are not readable or writable.
661: * We define three separate macros here for testing user stack addresses.
662: *
663: * PTE_OF_ADDR locates a PTE, branching to a `bad address'
664: * handler if the stack pointer points into the hole in the
665: * address space (i.e., top 3 bits are not either all 1 or all 0);
666: * CMP_PTE_USER_READ compares the located PTE against `user read' mode;
667: * CMP_PTE_USER_WRITE compares the located PTE against `user write' mode.
668: * The compares give `equal' if read or write is OK.
669: *
670: * Note that the user stack pointer usually points into high addresses
671: * (top 3 bits all 1), so that is what we check first.
672: *
673: * The code below also assumes that PTE_OF_ADDR is safe in a delay
674: * slot; it is, at it merely sets its `pte' register to a temporary value.
675: */
676: /* input: addr, output: pte; aux: bad address label */
1.13 deraadt 677: #define PTE_OF_ADDR(addr, pte, bad, page_offset) \
1.1 deraadt 678: sra addr, PG_VSHIFT, pte; \
679: cmp pte, -1; \
1.13 deraadt 680: be,a 1f; andn addr, page_offset, pte; \
1.1 deraadt 681: tst pte; \
682: bne bad; EMPTY; \
1.13 deraadt 683: andn addr, page_offset, pte; \
1.1 deraadt 684: 1:
685:
686: /* input: pte; output: condition codes */
687: #define CMP_PTE_USER_READ(pte) \
688: lda [pte] ASI_PTE, pte; \
689: srl pte, PG_PROTSHIFT, pte; \
690: andn pte, (PG_W >> PG_PROTSHIFT), pte; \
691: cmp pte, PG_PROTUREAD
692:
693: /* input: pte; output: condition codes */
694: #define CMP_PTE_USER_WRITE(pte) \
695: lda [pte] ASI_PTE, pte; \
696: srl pte, PG_PROTSHIFT, pte; \
697: cmp pte, PG_PROTUWRITE
1.9 deraadt 698: #endif
1.1 deraadt 699:
700: /*
701: * The calculations in PTE_OF_ADDR and CMP_PTE_USER_* are rather slow:
702: * in particular, according to Gordon Irlam of the University of Adelaide
703: * in Australia, these consume at least 18 cycles on an SS1 and 37 on an
704: * SS2. Hence, we try to avoid them in the common case.
705: *
706: * A chunk of 64 bytes is on a single page if and only if:
707: *
1.13 deraadt 708: * ((base + 64 - 1) & ~(NBPG-1)) == (base & ~(NBPG-1))
1.1 deraadt 709: *
710: * Equivalently (and faster to test), the low order bits (base & 4095) must
711: * be small enough so that the sum (base + 63) does not carry out into the
712: * upper page-address bits, i.e.,
713: *
1.13 deraadt 714: * (base & (NBPG-1)) < (NBPG - 63)
1.1 deraadt 715: *
716: * so we allow testing that here. This macro is also assumed to be safe
717: * in a delay slot (modulo overwriting its temporary).
718: */
1.13 deraadt 719: #define SLT_IF_1PAGE_RW(addr, tmp, page_offset) \
720: and addr, page_offset, tmp; \
721: sub page_offset, 62, page_offset; \
722: cmp tmp, page_offset
1.1 deraadt 723:
724: /*
725: * Every trap that enables traps must set up stack space.
726: * If the trap is from user mode, this involves switching to the kernel
727: * stack for the current process, and we must also set cpcb->pcb_uw
728: * so that the window overflow handler can tell user windows from kernel
729: * windows.
730: *
731: * The number of user windows is:
732: *
733: * cpcb->pcb_uw = (cpcb->pcb_wim - 1 - CWP) % nwindows
734: *
735: * (where pcb_wim = log2(current %wim) and CWP = low 5 bits of %psr).
736: * We compute this expression by table lookup in uwtab[CWP - pcb_wim],
737: * which has been set up as:
738: *
739: * for i in [-nwin+1 .. nwin-1]
740: * uwtab[i] = (nwin - 1 - i) % nwin;
741: *
742: * (If you do not believe this works, try it for yourself.)
743: *
744: * We also keep one or two more tables:
745: *
746: * for i in 0..nwin-1
747: * wmask[i] = 1 << ((i + 1) % nwindows);
748: *
749: * wmask[CWP] tells whether a `rett' would return into the invalid window.
750: */
751: .data
752: .skip 32 ! alignment byte & negative indicies
753: uwtab: .skip 32 ! u_char uwtab[-31..31];
754: wmask: .skip 32 ! u_char wmask[0..31];
755:
756: .text
757: /*
758: * Things begin to grow uglier....
759: *
760: * Each trap handler may (always) be running in the trap window.
761: * If this is the case, it cannot enable further traps until it writes
762: * the register windows into the stack (or, if the stack is no good,
763: * the current pcb).
764: *
765: * ASSUMPTIONS: TRAP_SETUP() is called with:
766: * %l0 = %psr
767: * %l1 = return pc
768: * %l2 = return npc
769: * %l3 = (some value that must not be altered)
770: * which means we have 4 registers to work with.
771: *
772: * The `stackspace' argument is the number of stack bytes to allocate
773: * for register-saving, and must be at least -64 (and typically more,
774: * for global registers and %y).
775: *
776: * Trapframes should use -CCFSZ-80. (80 = sizeof(struct trapframe);
777: * see trap.h. This basically means EVERYONE. Interrupt frames could
778: * get away with less, but currently do not.)
779: *
780: * The basic outline here is:
781: *
782: * if (trap came from kernel mode) {
783: * if (we are in the trap window)
784: * save it away;
785: * %sp = %fp - stackspace;
786: * } else {
787: * compute the number of user windows;
788: * if (we are in the trap window)
789: * save it away;
790: * %sp = (top of kernel stack) - stackspace;
791: * }
792: *
793: * Again, the number of user windows is:
794: *
795: * cpcb->pcb_uw = (cpcb->pcb_wim - 1 - CWP) % nwindows
796: *
797: * (where pcb_wim = log2(current %wim) and CWP is the low 5 bits of %psr),
798: * and this is computed as `uwtab[CWP - pcb_wim]'.
799: *
800: * NOTE: if you change this code, you will have to look carefully
801: * at the window overflow and underflow handlers and make sure they
802: * have similar changes made as needed.
803: */
804: #define CALL_CLEAN_TRAP_WINDOW \
805: sethi %hi(clean_trap_window), %l7; \
806: jmpl %l7 + %lo(clean_trap_window), %l4; \
807: mov %g7, %l7 /* save %g7 in %l7 for clean_trap_window */
808:
809: #define TRAP_SETUP(stackspace) \
810: rd %wim, %l4; \
811: mov 1, %l5; \
812: sll %l5, %l0, %l5; \
813: btst PSR_PS, %l0; \
814: bz 1f; \
815: btst %l5, %l4; \
816: /* came from kernel mode; cond codes indicate trap window */ \
817: bz,a 3f; \
818: add %fp, stackspace, %sp; /* want to just set %sp */ \
819: CALL_CLEAN_TRAP_WINDOW; /* but maybe need to clean first */ \
820: b 3f; \
821: add %fp, stackspace, %sp; \
822: 1: \
823: /* came from user mode: compute pcb_nw */ \
824: sethi %hi(_cpcb), %l6; \
825: ld [%l6 + %lo(_cpcb)], %l6; \
826: ld [%l6 + PCB_WIM], %l5; \
827: and %l0, 31, %l4; \
828: sub %l4, %l5, %l5; \
829: set uwtab, %l4; \
830: ldub [%l4 + %l5], %l5; \
831: st %l5, [%l6 + PCB_UW]; \
832: /* cond codes still indicate whether in trap window */ \
833: bz,a 2f; \
1.13 deraadt 834: sethi %hi(USPACE+(stackspace)), %l5; \
1.1 deraadt 835: /* yes, in trap window; must clean it */ \
836: CALL_CLEAN_TRAP_WINDOW; \
837: sethi %hi(_cpcb), %l6; \
838: ld [%l6 + %lo(_cpcb)], %l6; \
1.13 deraadt 839: sethi %hi(USPACE+(stackspace)), %l5; \
1.1 deraadt 840: 2: \
841: /* trap window is (now) clean: set %sp */ \
1.13 deraadt 842: or %l5, %lo(USPACE+(stackspace)), %l5; \
1.1 deraadt 843: add %l6, %l5, %sp; \
844: SET_SP_REDZONE(%l6, %l5); \
845: 3: \
846: CHECK_SP_REDZONE(%l6, %l5)
847:
848: /*
849: * Interrupt setup is almost exactly like trap setup, but we need to
850: * go to the interrupt stack if (a) we came from user mode or (b) we
851: * came from kernel mode on the kernel stack.
852: */
853: #define INTR_SETUP(stackspace) \
854: rd %wim, %l4; \
855: mov 1, %l5; \
856: sll %l5, %l0, %l5; \
857: btst PSR_PS, %l0; \
858: bz 1f; \
859: btst %l5, %l4; \
860: /* came from kernel mode; cond codes still indicate trap window */ \
861: bz,a 0f; \
862: sethi %hi(_eintstack), %l7; \
863: CALL_CLEAN_TRAP_WINDOW; \
864: sethi %hi(_eintstack), %l7; \
865: 0: /* now if %fp >= eintstack, we were on the kernel stack */ \
866: cmp %fp, %l7; \
867: bge,a 3f; \
868: add %l7, stackspace, %sp; /* so switch to intstack */ \
869: b 4f; \
870: add %fp, stackspace, %sp; /* else stay on intstack */ \
871: 1: \
872: /* came from user mode: compute pcb_nw */ \
873: sethi %hi(_cpcb), %l6; \
874: ld [%l6 + %lo(_cpcb)], %l6; \
875: ld [%l6 + PCB_WIM], %l5; \
876: and %l0, 31, %l4; \
877: sub %l4, %l5, %l5; \
878: set uwtab, %l4; \
879: ldub [%l4 + %l5], %l5; \
880: st %l5, [%l6 + PCB_UW]; \
881: /* cond codes still indicate whether in trap window */ \
882: bz,a 2f; \
883: sethi %hi(_eintstack), %l7; \
884: /* yes, in trap window; must save regs */ \
885: CALL_CLEAN_TRAP_WINDOW; \
886: sethi %hi(_eintstack), %l7; \
887: 2: \
888: add %l7, stackspace, %sp; \
889: 3: \
890: SET_SP_REDZONE_CONST(_intstack, %l6, %l5); \
891: 4: \
892: CHECK_SP_REDZONE(%l6, %l5)
893:
894: /*
895: * Handler for making the trap window shiny clean.
896: *
897: * On entry:
898: * cpcb->pcb_nw = number of user windows
899: * %l0 = %psr
900: * %l1 must not be clobbered
901: * %l2 must not be clobbered
902: * %l3 must not be clobbered
903: * %l4 = address for `return'
904: * %l7 = saved %g7 (we put this in a delay slot above, to save work)
905: *
906: * On return:
907: * %wim has changed, along with cpcb->pcb_wim
908: * %g7 has been restored
909: *
910: * Normally, we push only one window.
911: */
912: clean_trap_window:
913: mov %g5, %l5 ! save %g5
914: mov %g6, %l6 ! ... and %g6
915: /* mov %g7, %l7 ! ... and %g7 (already done for us) */
916: sethi %hi(_cpcb), %g6 ! get current pcb
917: ld [%g6 + %lo(_cpcb)], %g6
918:
919: /* Figure out whether it is a user window (cpcb->pcb_uw > 0). */
920: ld [%g6 + PCB_UW], %g7
921: deccc %g7
922: bge ctw_user
923: save %g0, %g0, %g0 ! in any case, enter window to save
924:
925: /* The window to be pushed is a kernel window. */
926: std %l0, [%sp + (0*8)]
927: ctw_merge:
928: std %l2, [%sp + (1*8)]
929: std %l4, [%sp + (2*8)]
930: std %l6, [%sp + (3*8)]
931: std %i0, [%sp + (4*8)]
932: std %i2, [%sp + (5*8)]
933: std %i4, [%sp + (6*8)]
934: std %i6, [%sp + (7*8)]
935:
936: /* Set up new window invalid mask, and update cpcb->pcb_wim. */
937: rd %psr, %g7 ! g7 = (junk << 5) + new_cwp
938: mov 1, %g5 ! g5 = 1 << new_cwp;
939: sll %g5, %g7, %g5
940: wr %g5, 0, %wim ! setwim(g5);
941: and %g7, 31, %g7 ! cpcb->pcb_wim = g7 & 31;
1.13 deraadt 942: sethi %hi(_cpcb), %g6 ! re-get current pcb
943: ld [%g6 + %lo(_cpcb)], %g6
1.1 deraadt 944: st %g7, [%g6 + PCB_WIM]
945: nop
946: restore ! back to trap window
947:
948: mov %l5, %g5 ! restore g5
949: mov %l6, %g6 ! ... and g6
950: jmp %l4 + 8 ! return to caller
951: mov %l7, %g7 ! ... and g7
952: /* NOTREACHED */
953:
954: ctw_user:
955: /*
956: * The window to be pushed is a user window.
957: * We must verify the stack pointer (alignment & permissions).
958: * See comments above definition of PTE_OF_ADDR.
959: */
960: st %g7, [%g6 + PCB_UW] ! cpcb->pcb_uw--;
961: btst 7, %sp ! if not aligned,
962: bne ctw_invalid ! choke on it
963: EMPTY
1.13 deraadt 964:
965: sethi %hi(_pgofset), %g6 ! trash %g6=curpcb
966: ld [%g6 + %lo(_pgofset)], %g6
967: PTE_OF_ADDR(%sp, %g7, ctw_invalid, %g6)
1.1 deraadt 968: CMP_PTE_USER_WRITE(%g7) ! likewise if not writable
969: bne ctw_invalid
970: EMPTY
1.13 deraadt 971: SLT_IF_1PAGE_RW(%sp, %g7, %g6)
1.1 deraadt 972: bl,a ctw_merge ! all ok if only 1
973: std %l0, [%sp]
974: add %sp, 7*8, %g5 ! check last addr too
1.13 deraadt 975: add %g6, 62, %g6
976: PTE_OF_ADDR(%g5, %g7, ctw_invalid, %g6)
1.1 deraadt 977: CMP_PTE_USER_WRITE(%g7)
978: be,a ctw_merge ! all ok: store <l0,l1> and merge
979: std %l0, [%sp]
980:
981: /*
982: * The window we wanted to push could not be pushed.
983: * Instead, save ALL user windows into the pcb.
984: * We will notice later that we did this, when we
985: * get ready to return from our trap or syscall.
986: *
987: * The code here is run rarely and need not be optimal.
988: */
989: ctw_invalid:
990: /*
991: * Reread cpcb->pcb_uw. We decremented this earlier,
992: * so it is off by one.
993: */
1.13 deraadt 994: sethi %hi(_cpcb), %g6 ! re-get current pcb
995: ld [%g6 + %lo(_cpcb)], %g6
996:
1.1 deraadt 997: ld [%g6 + PCB_UW], %g7 ! (number of user windows) - 1
998: add %g6, PCB_RW, %g5
999:
1000: /* save g7+1 windows, starting with the current one */
1001: 1: ! do {
1002: std %l0, [%g5 + (0*8)] ! rw->rw_local[0] = l0;
1003: std %l2, [%g5 + (1*8)] ! ...
1004: std %l4, [%g5 + (2*8)]
1005: std %l6, [%g5 + (3*8)]
1006: std %i0, [%g5 + (4*8)]
1007: std %i2, [%g5 + (5*8)]
1008: std %i4, [%g5 + (6*8)]
1009: std %i6, [%g5 + (7*8)]
1010: deccc %g7 ! if (n > 0) save(), rw++;
1011: bge,a 1b ! } while (--n >= 0);
1012: save %g5, 64, %g5
1013:
1014: /* stash sp for bottommost window */
1015: st %sp, [%g5 + 64 + (7*8)]
1016:
1017: /* set up new wim */
1018: rd %psr, %g7 ! g7 = (junk << 5) + new_cwp;
1019: mov 1, %g5 ! g5 = 1 << new_cwp;
1020: sll %g5, %g7, %g5
1021: wr %g5, 0, %wim ! wim = g5;
1022: and %g7, 31, %g7
1023: st %g7, [%g6 + PCB_WIM] ! cpcb->pcb_wim = new_cwp;
1024:
1025: /* fix up pcb fields */
1026: ld [%g6 + PCB_UW], %g7 ! n = cpcb->pcb_uw;
1027: add %g7, 1, %g5
1028: st %g5, [%g6 + PCB_NSAVED] ! cpcb->pcb_nsaved = n + 1;
1029: st %g0, [%g6 + PCB_UW] ! cpcb->pcb_uw = 0;
1030:
1031: /* return to trap window */
1032: 1: deccc %g7 ! do {
1033: bge 1b ! restore();
1034: restore ! } while (--n >= 0);
1035:
1036: mov %l5, %g5 ! restore g5, g6, & g7, and return
1037: mov %l6, %g6
1038: jmp %l4 + 8
1039: mov %l7, %g7
1040: /* NOTREACHED */
1041:
1042:
1043: /*
1044: * Each memory access (text or data) fault, from user or kernel mode,
1045: * comes here. We read the error register and figure out what has
1046: * happened.
1047: *
1048: * This cannot be done from C code since we must not enable traps (and
1049: * hence may not use the `save' instruction) until we have decided that
1050: * the error is or is not an asynchronous one that showed up after a
1051: * synchronous error, but which must be handled before the sync err.
1052: *
1053: * Most memory faults are user mode text or data faults, which can cause
1054: * signal delivery or ptracing, for which we must build a full trapframe.
1055: * It does not seem worthwhile to work to avoid this in the other cases,
1056: * so we store all the %g registers on the stack immediately.
1057: *
1058: * On entry:
1059: * %l0 = %psr
1060: * %l1 = return pc
1061: * %l2 = return npc
1062: * %l3 = T_TEXTFAULT or T_DATAFAULT
1063: *
1064: * Internal:
1065: * %l4 = %y, until we call mem_access_fault (then onto trapframe)
1066: * %l5 = IE_reg_addr, if async mem error
1067: *
1068: * We know about the layout of the error registers here.
1069: * addr reg
1070: * ---- ---
1071: * a AC_SYNC_ERR
1072: * a+4 AC_SYNC_VA
1073: * a+8 AC_ASYNC_ERR
1074: * a+12 AC_ASYNC_VA
1075: */
1076: memfault:
1077: TRAP_SETUP(-CCFSZ-80)
1078: INCR(_cnt+V_FAULTS) ! cnt.v_faults++ (clobbers %o0,%o1)
1079:
1080: st %g1, [%sp + CCFSZ + 20] ! save g1
1081: rd %y, %l4 ! save y
1082:
1.19 deraadt 1083: #if defined(SUN4) && (defined(SUN4C) || defined(SUN4M))
1084: sethi %hi(_cputyp), %o0 ! what cpu are we running on?
1085: ld [%o0 + %lo(_cputyp)], %o0
1086: cmp %o0, CPU_SUN4
1087: bne 9f
1088: nop
1089: #endif
1090: #if defined(SUN4)
1091: /*
1092: * registers:
1093: * memerr.ctrl = memory error control reg., error if 0x80 set
1094: * memerr.vaddr = address of memory error
1095: * buserr = basically just like sun4c sync error reg but
1096: * no SER_WRITE bit (have to figure out from code).
1097: */
1.20 deraadt 1098: set _par_err_reg, %o0 ! memerr ctrl addr -- XXX mapped?
1099: ld [%o0], %o0 ! get it
1.19 deraadt 1100: std %g2, [%sp + CCFSZ + 24] ! save g2, g3
1101: ld [%o0], %o1 ! memerr ctrl register
1102: inc 4, %o0 ! now VA of memerr vaddr register
1103: std %g4, [%sp + CCFSZ + 32] ! (sneak g4,g5 in here)
1104: ld [%o0], %o2 ! memerr virt addr
1105: st %g0, [%o0] ! NOTE: this clears latching!!!
1106: btst ME_REG_IERR, %o1 ! memory error?
1107: ! XXX this value may not be correct
1108: ! as I got some parity errors and the
1109: ! correct bits were not on?
1110: std %g6, [%sp + CCFSZ + 40]
1111: bz,a xnormal_mem_fault ! no, just a regular fault
1112: wr %l0, PSR_ET, %psr ! (and reenable traps)
1113:
1114: /* memory error = death for now XXX */
1115: clr %o3
1116: clr %o4
1.20 deraadt 1117: call _memerr ! (0, ser, sva, 0, 0)
1.19 deraadt 1118: clr %o0
1119: call _callrom
1120: nop
1121:
1122: xnormal_mem_fault:
1123: /*
1124: * have to make SUN4 emulate SUN4C. 4C code expects
1125: * SER in %o1 and the offending VA in %o2, everything else is ok.
1126: * (must figure out if SER_WRITE should be set)
1127: */
1128: set AC_BUS_ERR, %o0 ! bus error register
1129: cmp %l3, T_TEXTFAULT ! text fault always on PC
1130: beq normal_mem_fault ! go
1.21 deraadt 1131: lduba [%o0] ASI_CONTROL, %o1 ! get its value
1.19 deraadt 1132:
1133: #define STORE_BIT 21 /* bit that indicates a store instruction for sparc */
1134: ld [%l1], %o3 ! offending instruction in %o3 [l1=pc]
1135: srl %o3, STORE_BIT, %o3 ! get load/store bit (wont fit simm13)
1136: btst 1, %o3 ! test for store operation
1137:
1138: bz normal_mem_fault ! if (z) is a load (so branch)
1139: sethi %hi(SER_WRITE), %o5 ! damn SER_WRITE wont fit simm13
1140: ! or %lo(SER_WRITE), %o5, %o5! not necessary since %lo is zero
1141: or %o5, %o1, %o1 ! set SER_WRITE
1142: #if defined(SUN4C) || defined(SUN4M)
1143: ba normal_mem_fault
1144: nop ! XXX make efficient later
1145: #endif /* SUN4C || SUN4M */
1146: #endif /* SUN4 */
1147: 9:
1148: #if defined(SUN4C) || defined(SUN4M)
1149:
1.1 deraadt 1150: #if AC_SYNC_ERR + 4 != AC_SYNC_VA || \
1151: AC_SYNC_ERR + 8 != AC_ASYNC_ERR || AC_SYNC_ERR + 12 != AC_ASYNC_VA
1152: help help help ! I, I, I wanna be a lifeguard
1153: #endif
1154: set AC_SYNC_ERR, %o0
1155: std %g2, [%sp + CCFSZ + 24] ! save g2, g3
1156: lda [%o0] ASI_CONTROL, %o1 ! sync err reg
1157: inc 4, %o0
1158: std %g4, [%sp + CCFSZ + 32] ! (sneak g4,g5 in here)
1159: lda [%o0] ASI_CONTROL, %o2 ! sync virt addr
1160: btst SER_MEMERR, %o1 ! memory error?
1161: std %g6, [%sp + CCFSZ + 40]
1162: bz,a normal_mem_fault ! no, just a regular fault
1163: wr %l0, PSR_ET, %psr ! (and reenable traps)
1164:
1165: /*
1166: * We got a synchronous memory error. It could be one that
1167: * happened because there were two stores in a row, and the
1168: * first went into the write buffer, and the second caused this
1169: * synchronous trap; so there could now be a pending async error.
1170: * This is in fact the case iff the two va's differ.
1171: */
1172: inc 4, %o0
1173: lda [%o0] ASI_CONTROL, %o3 ! async err reg
1174: inc 4, %o0
1175: lda [%o0] ASI_CONTROL, %o4 ! async virt addr
1176: cmp %o2, %o4
1177: be,a 1f ! no, not an async err
1178: wr %l0, PSR_ET, %psr ! (and reenable traps)
1179:
1180: /*
1181: * Handle the async error; ignore the sync error for now
1182: * (we may end up getting it again, but so what?).
1183: * This code is essentially the same as that at `nmi' below,
1184: * but the register usage is different and we cannot merge.
1185: */
1186: sethi %hi(IE_reg_addr), %l5 ! ienab_bic(IE_ALLIE);
1187: ldub [%l5 + %lo(IE_reg_addr)], %o0
1188: andn %o0, IE_ALLIE, %o0
1189: stb %o0, [%l5 + %lo(IE_reg_addr)]
1190:
1191: /*
1192: * Now reenable traps and call C code.
1193: * %o1 through %o4 still hold the error reg contents.
1194: * If memerr() returns, return from the trap.
1195: */
1196: wr %l0, PSR_ET, %psr
1197: call _memerr ! memerr(0, ser, sva, aer, ava)
1198: clr %o0
1199:
1200: ld [%sp + CCFSZ + 20], %g1 ! restore g1 through g7
1201: wr %l0, 0, %psr ! and disable traps, 3 instr delay
1202: ldd [%sp + CCFSZ + 24], %g2
1203: ldd [%sp + CCFSZ + 32], %g4
1204: ldd [%sp + CCFSZ + 40], %g6
1205: /* now safe to set IE_ALLIE again */
1206: ldub [%l5 + %lo(IE_reg_addr)], %o1
1207: or %o1, IE_ALLIE, %o1
1208: stb %o1, [%l5 + %lo(IE_reg_addr)]
1209: b return_from_trap
1210: wr %l4, 0, %y ! restore y
1211:
1212: /*
1213: * Trap was a synchronous memory error.
1214: * %o1 through %o4 still hold the error reg contents.
1215: */
1216: 1:
1217: call _memerr ! memerr(1, ser, sva, aer, ava)
1218: mov 1, %o0
1219:
1220: ld [%sp + CCFSZ + 20], %g1 ! restore g1 through g7
1221: ldd [%sp + CCFSZ + 24], %g2
1222: ldd [%sp + CCFSZ + 32], %g4
1223: ldd [%sp + CCFSZ + 40], %g6
1224: wr %l4, 0, %y ! restore y
1225: b return_from_trap
1226: wr %l0, 0, %psr
1227: /* NOTREACHED */
1.19 deraadt 1228: #endif /* SUN4C || SUN4M */
1.1 deraadt 1229:
1230: normal_mem_fault:
1231: /*
1232: * Trap was some other error; call C code to deal with it.
1233: * Must finish trap frame (psr,pc,npc,%y,%o0..%o7) in case
1234: * we decide to deliver a signal or ptrace the process.
1235: * %g1..%g7 were already set up above.
1236: */
1237: std %l0, [%sp + CCFSZ + 0] ! set tf.tf_psr, tf.tf_pc
1238: mov %l3, %o0 ! (argument: type)
1239: st %l2, [%sp + CCFSZ + 8] ! set tf.tf_npc
1240: st %l4, [%sp + CCFSZ + 12] ! set tf.tf_y
1241: mov %l1, %o3 ! (argument: pc)
1242: std %i0, [%sp + CCFSZ + 48] ! tf.tf_out[0], etc
1243: std %i2, [%sp + CCFSZ + 56]
1244: mov %l0, %o4 ! (argument: psr)
1245: std %i4, [%sp + CCFSZ + 64]
1246: std %i6, [%sp + CCFSZ + 72]
1247: call _mem_access_fault ! mem_access_fault(type, ser, sva,
1248: ! pc, psr, &tf);
1249: add %sp, CCFSZ, %o5 ! (argument: &tf)
1250:
1251: ldd [%sp + CCFSZ + 0], %l0 ! load new values
1252: ldd [%sp + CCFSZ + 8], %l2
1253: wr %l3, 0, %y
1254: ld [%sp + CCFSZ + 20], %g1
1255: ldd [%sp + CCFSZ + 24], %g2
1256: ldd [%sp + CCFSZ + 32], %g4
1257: ldd [%sp + CCFSZ + 40], %g6
1258: ldd [%sp + CCFSZ + 48], %i0
1259: ldd [%sp + CCFSZ + 56], %i2
1260: ldd [%sp + CCFSZ + 64], %i4
1261: ldd [%sp + CCFSZ + 72], %i6
1262:
1263: b return_from_trap ! go return
1264: wr %l0, 0, %psr ! (but first disable traps again)
1265:
1266:
1267: /*
1268: * fp_exception has to check to see if we are trying to save
1269: * the FP state, and if so, continue to save the FP state.
1270: *
1271: * We do not even bother checking to see if we were in kernel mode,
1272: * since users have no access to the special_fp_store instruction.
1273: *
1274: * This whole idea was stolen from Sprite.
1275: */
1276: fp_exception:
1277: set special_fp_store, %l4 ! see if we came from the special one
1278: cmp %l1, %l4 ! pc == special_fp_store?
1279: bne slowtrap ! no, go handle per usual
1280: EMPTY
1281: sethi %hi(savefpcont), %l4 ! yes, "return" to the special code
1282: or %lo(savefpcont), %l4, %l4
1283: jmp %l4
1284: rett %l4 + 4
1285:
1286: /*
1287: * slowtrap() builds a trap frame and calls trap().
1288: * This is called `slowtrap' because it *is*....
1289: * We have to build a full frame for ptrace(), for instance.
1290: *
1291: * Registers:
1292: * %l0 = %psr
1293: * %l1 = return pc
1294: * %l2 = return npc
1295: * %l3 = trap code
1296: */
1297: slowtrap:
1298: TRAP_SETUP(-CCFSZ-80)
1299: /*
1300: * Phew, ready to enable traps and call C code.
1301: */
1302: mov %l3, %o0 ! put type in %o0 for later
1303: Lslowtrap_reenter:
1304: wr %l0, PSR_ET, %psr ! traps on again
1305: std %l0, [%sp + CCFSZ] ! tf.tf_psr = psr; tf.tf_pc = ret_pc;
1306: rd %y, %l3
1307: std %l2, [%sp + CCFSZ + 8] ! tf.tf_npc = return_npc; tf.tf_y = %y;
1308: st %g1, [%sp + CCFSZ + 20]
1309: std %g2, [%sp + CCFSZ + 24]
1310: std %g4, [%sp + CCFSZ + 32]
1311: std %g6, [%sp + CCFSZ + 40]
1312: std %i0, [%sp + CCFSZ + 48]
1313: mov %l0, %o1 ! (psr)
1314: std %i2, [%sp + CCFSZ + 56]
1315: mov %l1, %o2 ! (pc)
1316: std %i4, [%sp + CCFSZ + 64]
1317: add %sp, CCFSZ, %o3 ! (&tf)
1318: call _trap ! trap(type, psr, pc, &tf)
1319: std %i6, [%sp + CCFSZ + 72]
1320:
1321: ldd [%sp + CCFSZ], %l0 ! load new values
1322: ldd [%sp + CCFSZ + 8], %l2
1323: wr %l3, 0, %y
1324: ld [%sp + CCFSZ + 20], %g1
1325: ldd [%sp + CCFSZ + 24], %g2
1326: ldd [%sp + CCFSZ + 32], %g4
1327: ldd [%sp + CCFSZ + 40], %g6
1328: ldd [%sp + CCFSZ + 48], %i0
1329: ldd [%sp + CCFSZ + 56], %i2
1330: ldd [%sp + CCFSZ + 64], %i4
1331: ldd [%sp + CCFSZ + 72], %i6
1332: b return_from_trap
1333: wr %l0, 0, %psr
1334:
1335: /*
1336: * Do a `software' trap by re-entering the trap code, possibly first
1337: * switching from interrupt stack to kernel stack. This is used for
1338: * scheduling and signal ASTs (which generally occur from softclock or
1339: * tty or net interrupts) and register window saves (which might occur
1340: * from anywhere).
1341: *
1342: * The current window is the trap window, and it is by definition clean.
1343: * We enter with the trap type in %o0. All we have to do is jump to
1344: * Lslowtrap_reenter above, but maybe after switching stacks....
1345: */
1346: softtrap:
1347: sethi %hi(_eintstack), %l7
1348: cmp %sp, %l7
1349: bge Lslowtrap_reenter
1350: EMPTY
1351: sethi %hi(_cpcb), %l6
1352: ld [%l6 + %lo(_cpcb)], %l6
1.13 deraadt 1353: set USPACE-CCFSZ-80, %l5
1.1 deraadt 1354: add %l6, %l5, %l7
1355: SET_SP_REDZONE(%l6, %l5)
1356: b Lslowtrap_reenter
1357: mov %l7, %sp
1358:
1359: #ifdef KGDB
1360: /*
1361: * bpt is entered on all breakpoint traps.
1362: * If this is a kernel breakpoint, we do not want to call trap().
1363: * Among other reasons, this way we can set breakpoints in trap().
1364: */
1365: bpt:
1366: btst PSR_PS, %l0 ! breakpoint from kernel?
1367: bz slowtrap ! no, go do regular trap
1368: nop
1369:
1370: /*
1371: * Build a trap frame for kgdb_trap_glue to copy.
1372: * Enable traps but set ipl high so that we will not
1373: * see interrupts from within breakpoints.
1374: */
1375: TRAP_SETUP(-CCFSZ-80)
1376: or %l0, PSR_PIL, %l4 ! splhigh()
1377: wr %l4, 0, %psr ! the manual claims that this
1378: wr %l4, PSR_ET, %psr ! song and dance is necessary
1379: std %l0, [%sp + CCFSZ + 0] ! tf.tf_psr, tf.tf_pc
1380: mov %l3, %o0 ! trap type arg for kgdb_trap_glue
1381: rd %y, %l3
1382: std %l2, [%sp + CCFSZ + 8] ! tf.tf_npc, tf.tf_y
1383: rd %wim, %l3
1384: st %l3, [%sp + CCFSZ + 16] ! tf.tf_wim (a kgdb-only r/o field)
1385: st %g1, [%sp + CCFSZ + 20] ! tf.tf_global[1]
1386: std %g2, [%sp + CCFSZ + 24] ! etc
1387: std %g4, [%sp + CCFSZ + 32]
1388: std %g6, [%sp + CCFSZ + 40]
1389: std %i0, [%sp + CCFSZ + 48] ! tf.tf_in[0..1]
1390: std %i2, [%sp + CCFSZ + 56] ! etc
1391: std %i4, [%sp + CCFSZ + 64]
1392: std %i6, [%sp + CCFSZ + 72]
1393:
1394: /*
1395: * Now call kgdb_trap_glue(); if it returns, call trap().
1396: */
1397: mov %o0, %l3 ! gotta save trap type
1398: call _kgdb_trap_glue ! kgdb_trap_glue(type, &trapframe)
1399: add %sp, CCFSZ, %o1 ! (&trapframe)
1400:
1401: /*
1402: * Use slowtrap to call trap---but first erase our tracks
1403: * (put the registers back the way they were).
1404: */
1405: mov %l3, %o0 ! slowtrap will need trap type
1406: ld [%sp + CCFSZ + 12], %l3
1407: wr %l3, 0, %y
1408: ld [%sp + CCFSZ + 20], %g1
1409: ldd [%sp + CCFSZ + 24], %g2
1410: ldd [%sp + CCFSZ + 32], %g4
1411: b Lslowtrap_reenter
1412: ldd [%sp + CCFSZ + 40], %g6
1413:
1414: /*
1415: * Enter kernel breakpoint. Write all the windows (not including the
1416: * current window) into the stack, so that backtrace works. Copy the
1417: * supplied trap frame to the kgdb stack and switch stacks.
1418: *
1419: * kgdb_trap_glue(type, tf0)
1420: * int type;
1421: * struct trapframe *tf0;
1422: */
1423: .globl _kgdb_trap_glue
1424: _kgdb_trap_glue:
1425: save %sp, -CCFSZ, %sp
1426:
1427: call _write_all_windows
1428: mov %sp, %l4 ! %l4 = current %sp
1429:
1430: /* copy trapframe to top of kgdb stack */
1431: set _kgdb_stack + KGDB_STACK_SIZE - 80, %l0
1432: ! %l0 = tfcopy -> end_of_kgdb_stack
1433: mov 80, %l1
1434: 1: ldd [%i1], %l2
1435: inc 8, %i1
1436: deccc 8, %l1
1437: std %l2, [%l0]
1438: bg 1b
1439: inc 8, %l0
1440:
1441: #ifdef DEBUG
1442: /* save old red zone and then turn it off */
1443: sethi %hi(_redzone), %l7
1444: ld [%l7 + %lo(_redzone)], %l6
1445: st %g0, [%l7 + %lo(_redzone)]
1446: #endif
1447: /* switch to kgdb stack */
1448: add %l0, -CCFSZ-80, %sp
1449:
1450: /* if (kgdb_trap(type, tfcopy)) kgdb_rett(tfcopy); */
1451: mov %i0, %o0
1452: call _kgdb_trap
1453: add %l0, -80, %o1
1454: tst %o0
1455: bnz,a kgdb_rett
1456: add %l0, -80, %g1
1457:
1458: /*
1459: * kgdb_trap() did not handle the trap at all so the stack is
1460: * still intact. A simple `restore' will put everything back,
1461: * after we reset the stack pointer.
1462: */
1463: mov %l4, %sp
1464: #ifdef DEBUG
1465: st %l6, [%l7 + %lo(_redzone)] ! restore red zone
1466: #endif
1467: ret
1468: restore
1469:
1470: /*
1471: * Return from kgdb trap. This is sort of special.
1472: *
1473: * We know that kgdb_trap_glue wrote the window above it, so that we will
1474: * be able to (and are sure to have to) load it up. We also know that we
1475: * came from kernel land and can assume that the %fp (%i6) we load here
1476: * is proper. We must also be sure not to lower ipl (it is at splhigh())
1477: * until we have traps disabled, due to the SPARC taking traps at the
1478: * new ipl before noticing that PSR_ET has been turned off. We are on
1479: * the kgdb stack, so this could be disastrous.
1480: *
1481: * Note that the trapframe argument in %g1 points into the current stack
1482: * frame (current window). We abandon this window when we move %g1->tf_psr
1483: * into %psr, but we will not have loaded the new %sp yet, so again traps
1484: * must be disabled.
1485: */
1486: kgdb_rett:
1487: rd %psr, %g4 ! turn off traps
1488: wr %g4, PSR_ET, %psr
1489: /* use the three-instruction delay to do something useful */
1490: ld [%g1], %g2 ! pick up new %psr
1491: ld [%g1 + 12], %g3 ! set %y
1492: wr %g3, 0, %y
1493: #ifdef DEBUG
1494: st %l6, [%l7 + %lo(_redzone)] ! and restore red zone
1495: #endif
1496: wr %g0, 0, %wim ! enable window changes
1497: nop; nop; nop
1498: /* now safe to set the new psr (changes CWP, leaves traps disabled) */
1499: wr %g2, 0, %psr ! set rett psr (including cond codes)
1500: /* 3 instruction delay before we can use the new window */
1501: /*1*/ ldd [%g1 + 24], %g2 ! set new %g2, %g3
1502: /*2*/ ldd [%g1 + 32], %g4 ! set new %g4, %g5
1503: /*3*/ ldd [%g1 + 40], %g6 ! set new %g6, %g7
1504:
1505: /* now we can use the new window */
1506: mov %g1, %l4
1507: ld [%l4 + 4], %l1 ! get new pc
1508: ld [%l4 + 8], %l2 ! get new npc
1509: ld [%l4 + 20], %g1 ! set new %g1
1510:
1511: /* set up returnee's out registers, including its %sp */
1512: ldd [%l4 + 48], %i0
1513: ldd [%l4 + 56], %i2
1514: ldd [%l4 + 64], %i4
1515: ldd [%l4 + 72], %i6
1516:
1517: /* load returnee's window, making the window above it be invalid */
1518: restore
1519: restore %g0, 1, %l1 ! move to inval window and set %l1 = 1
1520: rd %psr, %l0
1521: sll %l1, %l0, %l1
1522: wr %l1, 0, %wim ! %wim = 1 << (%psr & 31)
1523: sethi %hi(_cpcb), %l1
1524: ld [%l1 + %lo(_cpcb)], %l1
1525: and %l0, 31, %l0 ! CWP = %psr & 31;
1526: st %l0, [%l1 + PCB_WIM] ! cpcb->pcb_wim = CWP;
1527: save %g0, %g0, %g0 ! back to window to reload
1528: LOADWIN(%sp)
1529: save %g0, %g0, %g0 ! back to trap window
1530: /* note, we have not altered condition codes; safe to just rett */
1531: RETT
1532: #endif
1533:
1534: /*
1535: * syscall() builds a trap frame and calls syscall().
1536: * sun_syscall is same but delivers sun system call number
1537: * XXX should not have to save&reload ALL the registers just for
1538: * ptrace...
1539: */
1540: syscall:
1541: TRAP_SETUP(-CCFSZ-80)
1542: wr %l0, PSR_ET, %psr
1543: std %l0, [%sp + CCFSZ + 0] ! tf_psr, tf_pc
1544: rd %y, %l3
1545: std %l2, [%sp + CCFSZ + 8] ! tf_npc, tf_y
1546: st %g1, [%sp + CCFSZ + 20] ! tf_g[1]
1547: std %g2, [%sp + CCFSZ + 24] ! tf_g[2], tf_g[3]
1548: std %g4, [%sp + CCFSZ + 32] ! etc
1549: std %g6, [%sp + CCFSZ + 40]
1550: mov %g1, %o0 ! (code)
1551: std %i0, [%sp + CCFSZ + 48]
1552: add %sp, CCFSZ, %o1 ! (&tf)
1553: std %i2, [%sp + CCFSZ + 56]
1554: mov %l1, %o2 ! (pc)
1555: std %i4, [%sp + CCFSZ + 64]
1556: call _syscall ! syscall(code, &tf, pc, suncompat)
1557: std %i6, [%sp + CCFSZ + 72]
1558: ! now load em all up again, sigh
1559: ldd [%sp + CCFSZ + 0], %l0 ! new %psr, new pc
1560: ldd [%sp + CCFSZ + 8], %l2 ! new npc, new %y
1561: wr %l3, 0, %y
1.11 deraadt 1562: /* see `dostart' for the reason for this label */
1563: init_syscall_ret:
1.1 deraadt 1564: ld [%sp + CCFSZ + 20], %g1
1565: ldd [%sp + CCFSZ + 24], %g2
1566: ldd [%sp + CCFSZ + 32], %g4
1567: ldd [%sp + CCFSZ + 40], %g6
1568: ldd [%sp + CCFSZ + 48], %i0
1569: ldd [%sp + CCFSZ + 56], %i2
1570: ldd [%sp + CCFSZ + 64], %i4
1571: ldd [%sp + CCFSZ + 72], %i6
1572: b return_from_trap
1573: wr %l0, 0, %psr
1574:
1575: /*
1576: * Interrupts. Software interrupts must be cleared from the software
1577: * interrupt enable register. Rather than calling ienab_bic for each,
1578: * we do them in-line before enabling traps.
1579: *
1580: * After preliminary setup work, the interrupt is passed to each
1581: * registered handler in turn. These are expected to return nonzero if
1582: * they took care of the interrupt. If a handler claims the interrupt,
1583: * we exit (hardware interrupts are latched in the requestor so we'll
1584: * just take another interrupt in the unlikely event of simultaneous
1585: * interrupts from two different devices at the same level). If we go
1586: * through all the registered handlers and no one claims it, we report a
1587: * stray interrupt. This is more or less done as:
1588: *
1589: * for (ih = intrhand[intlev]; ih; ih = ih->ih_next)
1590: * if ((*ih->ih_fun)(ih->ih_arg ? ih->ih_arg : &frame))
1591: * return;
1592: * strayintr(&frame);
1593: *
1594: * Software interrupts are almost the same with three exceptions:
1595: * (1) we clear the interrupt from the software interrupt enable
1596: * register before calling any handler (we have to clear it first
1597: * to avoid an interrupt-losing race),
1598: * (2) we always call all the registered handlers (there is no way
1599: * to tell if the single bit in the software interrupt register
1600: * represents one or many requests)
1601: * (3) we never announce a stray interrupt (because of (1), another
1602: * interrupt request can come in while we're in the handler. If
1603: * the handler deal with everything for both the original & the
1604: * new request, we'll erroneously report a stray interrupt when
1605: * we take the software interrupt for the new request.
1606: *
1607: * Inputs:
1608: * %l0 = %psr
1609: * %l1 = return pc
1610: * %l2 = return npc
1611: * %l3 = interrupt level
1612: * (software interrupt only) %l4 = bits to clear in interrupt register
1613: *
1614: * Internal:
1615: * %l4, %l5: local variables
1616: * %l6 = %y
1617: * %l7 = %g1
1618: * %g2..%g7 go to stack
1619: *
1620: * An interrupt frame is built in the space for a full trapframe;
1621: * this contains the psr, pc, npc, and interrupt level.
1622: */
1623: .comm _intrhand, 15 * 8 ! intrhand[0..14]; 0 => error
1624: softintr:
1625: sethi %hi(IE_reg_addr), %l6
1626: ldub [%l6 + %lo(IE_reg_addr)], %l5
1627: andn %l5, %l4, %l5
1628: stb %l5, [%l6 + %lo(IE_reg_addr)]
1629: INTR_SETUP(-CCFSZ-80)
1630: std %g2, [%sp + CCFSZ + 24] ! save registers
1631: INCR(_cnt+V_INTR) ! cnt.v_intr++; (clobbers %o0,%o1)
1632: mov %g1, %l7
1633: rd %y, %l6
1634: std %g4, [%sp + CCFSZ + 32]
1635: andn %l0, PSR_PIL, %l4 ! %l4 = psr & ~PSR_PIL |
1636: sll %l3, 8, %l5 ! intlev << IPLSHIFT
1637: std %g6, [%sp + CCFSZ + 40]
1638: or %l5, %l4, %l4 ! ;
1639: wr %l4, 0, %psr ! the manual claims this
1640: wr %l4, PSR_ET, %psr ! song and dance is necessary
1641: std %l0, [%sp + CCFSZ + 0] ! set up intrframe/clockframe
1642: sll %l3, 2, %l5
1643: set _intrcnt, %l4 ! intrcnt[intlev]++;
1644: ld [%l4 + %l5], %o0
1645: std %l2, [%sp + CCFSZ + 8]
1646: inc %o0
1647: st %o0, [%l4 + %l5]
1648: set _intrhand, %l4 ! %l4 = intrhand[intlev];
1649: ld [%l4 + %l5], %l4
1650: b 3f
1651: st %fp, [%sp + CCFSZ + 16]
1652:
1653: 1: ld [%l4], %o1
1654: ld [%l4 + 4], %o0
1655: tst %o0
1656: bz,a 2f
1657: add %sp, CCFSZ, %o0
1658: 2: jmpl %o1, %o7 ! (void)(*ih->ih_fun)(...)
1659: ld [%l4 + 8], %l4 ! and ih = ih->ih_next
1660: 3: tst %l4 ! while ih != NULL
1661: bnz 1b
1662: nop
1663: mov %l7, %g1
1664: wr %l6, 0, %y
1665: ldd [%sp + CCFSZ + 24], %g2
1666: ldd [%sp + CCFSZ + 32], %g4
1667: ldd [%sp + CCFSZ + 40], %g6
1668: b return_from_trap
1669: wr %l0, 0, %psr
1670:
1671: /*
1672: * _sparc_interrupt is exported for paranoia checking (see intr.c).
1673: */
1674: .globl _sparc_interrupt
1675: _sparc_interrupt:
1676: INTR_SETUP(-CCFSZ-80)
1677: std %g2, [%sp + CCFSZ + 24] ! save registers
1678: INCR(_cnt+V_INTR) ! cnt.v_intr++; (clobbers %o0,%o1)
1679: mov %g1, %l7
1680: rd %y, %l6
1681: std %g4, [%sp + CCFSZ + 32]
1682: andn %l0, PSR_PIL, %l4 ! %l4 = psr & ~PSR_PIL |
1683: sll %l3, 8, %l5 ! intlev << IPLSHIFT
1684: std %g6, [%sp + CCFSZ + 40]
1685: or %l5, %l4, %l4 ! ;
1686: wr %l4, 0, %psr ! the manual claims this
1687: wr %l4, PSR_ET, %psr ! song and dance is necessary
1688: std %l0, [%sp + CCFSZ + 0] ! set up intrframe/clockframe
1689: sll %l3, 2, %l5
1690: set _intrcnt, %l4 ! intrcnt[intlev]++;
1691: ld [%l4 + %l5], %o0
1692: std %l2, [%sp + CCFSZ + 8] ! set up intrframe/clockframe
1693: inc %o0
1694: st %o0, [%l4 + %l5]
1695: set _intrhand, %l4 ! %l4 = intrhand[intlev];
1696: ld [%l4 + %l5], %l4
1697: b 3f
1698: st %fp, [%sp + CCFSZ + 16]
1699:
1700: 1: ld [%l4], %o1
1701: ld [%l4 + 4], %o0
1702: tst %o0
1703: bz,a 2f
1704: add %sp, CCFSZ, %o0
1705: 2: jmpl %o1, %o7 ! handled = (*ih->ih_fun)(...)
1706: ld [%l4 + 8], %l4 ! and ih = ih->ih_next
1707: tst %o0
1708: bnz 4f ! if (handled) break
1709: nop
1710: 3: tst %l4
1711: bnz 1b ! while (ih)
1712: nop
1713: call _strayintr ! strayintr(&intrframe)
1714: add %sp, CCFSZ, %o0
1715: /* all done: restore registers and go return */
1716: 4: mov %l7, %g1
1717: wr %l6, 0, %y
1718: ldd [%sp + CCFSZ + 24], %g2
1719: ldd [%sp + CCFSZ + 32], %g4
1720: ldd [%sp + CCFSZ + 40], %g6
1721: b return_from_trap
1722: wr %l0, 0, %psr
1723:
1724: #ifdef notyet
1725: /*
1726: * Level 12 (ZS serial) interrupt. Handle it quickly, schedule a
1727: * software interrupt, and get out. Do the software interrupt directly
1728: * if we would just take it on the way out.
1729: *
1730: * Input:
1731: * %l0 = %psr
1732: * %l1 = return pc
1733: * %l2 = return npc
1734: * Internal:
1735: * %l3 = zs device
1736: * %l4, %l5 = temporary
1737: * %l6 = rr3 (or temporary data) + 0x100 => need soft int
1738: * %l7 = zs soft status
1739: */
1740: zshard:
1741: #endif /* notyet */
1742:
1743: /*
1744: * Level 15 interrupt. An async memory error has occurred;
1745: * take care of it (typically by panicking, but hey...).
1746: * %l0 = %psr
1747: * %l1 = return pc
1748: * %l2 = return npc
1749: * %l3 = 15 * 4 (why? just because!)
1750: *
1751: * Internal:
1752: * %l4 = %y
1753: * %l5 = %g1
1754: * %l6 = %g6
1755: * %l7 = %g7
1756: * g2, g3, g4, g5 go to stack
1757: *
1758: * This code is almost the same as that in mem_access_fault,
1759: * except that we already know the problem is not a `normal' fault,
1760: * and that we must be extra-careful with interrupt enables.
1761: */
1762: nmi:
1763: INTR_SETUP(-CCFSZ-80)
1764: INCR(_cnt+V_INTR) ! cnt.v_intr++; (clobbers %o0,%o1)
1765: /*
1766: * Level 15 interrupts are nonmaskable, so with traps off,
1767: * disable all interrupts to prevent recursion.
1768: */
1769: sethi %hi(IE_reg_addr), %o0
1770: ldub [%o0 + %lo(IE_reg_addr)], %o1
1771: andn %o1, IE_ALLIE, %o1
1772: stb %o1, [%o0 + %lo(IE_reg_addr)]
1773: wr %l0, PSR_ET, %psr ! okay, turn traps on again
1774:
1775: std %g2, [%sp + CCFSZ + 0] ! save g2, g3
1776: rd %y, %l4 ! save y
1777:
1778: ! must read the sync error register too.
1.19 deraadt 1779: #if defined(SUN4) && (defined(SUN4C) || defined(SUN4M))
1780: sethi %hi(_cputyp), %o0 ! what cpu are we running on?
1781: ld [%o0 + %lo(_cputyp)], %o0
1782: cmp %o0, CPU_SUN4
1783: bne 1f
1784: nop
1785: #endif
1786: #if defined(SUN4)
1787: std %g4, [%sp + CCFSZ + 8] ! save g4, g5
1788: mov %g1, %l5 ! save g1, g6, g7
1789: mov %g6, %l6
1790: mov %g7, %l7
1791: #if defined(SUN4C) || defined(SUN4M)
1792: b 2f
1793: nop
1794: #endif /* SUN4C || SUN4M */
1795: #endif /* SUN4 */
1796: 1:
1797: #if defined(SUN4C) || defined(SUN4M)
1.1 deraadt 1798: set AC_SYNC_ERR, %o0
1799: lda [%o0] ASI_CONTROL, %o1 ! sync err reg
1800: inc 4, %o0
1801: lda [%o0] ASI_CONTROL, %o2 ! sync virt addr
1802: std %g4, [%sp + CCFSZ + 8] ! save g4,g5
1803: mov %g1, %l5 ! save g1,g6,g7
1804: mov %g6, %l6
1805: mov %g7, %l7
1806: inc 4, %o0
1807: lda [%o0] ASI_CONTROL, %o3 ! async err reg
1808: inc 4, %o0
1809: lda [%o0] ASI_CONTROL, %o4 ! async virt addr
1.19 deraadt 1810: #endif /* SUN4C || SUN4M */
1811: 2:
1.1 deraadt 1812: ! and call C code
1813: call _memerr ! memerr(0, ser, sva, aer, ava)
1814: clr %o0
1815:
1816: mov %l5, %g1 ! restore g1 through g7
1817: ldd [%sp + CCFSZ + 0], %g2
1818: ldd [%sp + CCFSZ + 8], %g4
1819: wr %l0, 0, %psr ! re-disable traps
1820: mov %l6, %g6
1821: mov %l7, %g7
1822:
1823: ! set IE_ALLIE again (safe, we disabled traps again above)
1824: sethi %hi(IE_reg_addr), %o0
1825: ldub [%o0 + %lo(IE_reg_addr)], %o1
1826: or %o1, IE_ALLIE, %o1
1827: stb %o1, [%o0 + %lo(IE_reg_addr)]
1828: b return_from_trap
1829: wr %l4, 0, %y ! restore y
1830:
1831:
1832: /*
1833: * Window overflow trap handler.
1834: * %l0 = %psr
1835: * %l1 = return pc
1836: * %l2 = return npc
1837: */
1838: window_of:
1839: #ifdef TRIVIAL_WINDOW_OVERFLOW_HANDLER
1840: /* a trivial version that assumes %sp is ok */
1841: /* (for testing only!) */
1842: save %g0, %g0, %g0
1843: std %l0, [%sp + (0*8)]
1844: rd %psr, %l0
1845: mov 1, %l1
1846: sll %l1, %l0, %l0
1847: wr %l0, 0, %wim
1848: std %l2, [%sp + (1*8)]
1849: std %l4, [%sp + (2*8)]
1850: std %l6, [%sp + (3*8)]
1851: std %i0, [%sp + (4*8)]
1852: std %i2, [%sp + (5*8)]
1853: std %i4, [%sp + (6*8)]
1854: std %i6, [%sp + (7*8)]
1855: restore
1856: RETT
1857: #else
1858: /*
1859: * This is similar to TRAP_SETUP, but we do not want to spend
1860: * a lot of time, so we have separate paths for kernel and user.
1861: * We also know for sure that the window has overflowed.
1862: */
1863: btst PSR_PS, %l0
1864: bz winof_user
1865: sethi %hi(clean_trap_window), %l7
1866:
1867: /*
1868: * Overflow from kernel mode. Call clean_trap_window to
1869: * do the dirty work, then just return, since we know prev
1870: * window is valid. clean_trap_windows might dump all *user*
1871: * windows into the pcb, but we do not care: there is at
1872: * least one kernel window (a trap or interrupt frame!)
1873: * above us.
1874: */
1875: jmpl %l7 + %lo(clean_trap_window), %l4
1876: mov %g7, %l7 ! for clean_trap_window
1877:
1878: wr %l0, 0, %psr ! put back the @%*! cond. codes
1879: nop ! (let them settle in)
1880: RETT
1881:
1882: winof_user:
1883: /*
1884: * Overflow from user mode.
1885: * If clean_trap_window dumps the registers into the pcb,
1886: * rft_user will need to call trap(), so we need space for
1887: * a trap frame. We also have to compute pcb_nw.
1888: *
1889: * SHOULD EXPAND IN LINE TO AVOID BUILDING TRAP FRAME ON
1890: * `EASY' SAVES
1891: */
1892: sethi %hi(_cpcb), %l6
1893: ld [%l6 + %lo(_cpcb)], %l6
1894: ld [%l6 + PCB_WIM], %l5
1895: and %l0, 31, %l3
1896: sub %l3, %l5, %l5 /* l5 = CWP - pcb_wim */
1897: set uwtab, %l4
1898: ldub [%l4 + %l5], %l5 /* l5 = uwtab[l5] */
1899: st %l5, [%l6 + PCB_UW]
1900: jmpl %l7 + %lo(clean_trap_window), %l4
1901: mov %g7, %l7 ! for clean_trap_window
1902: sethi %hi(_cpcb), %l6
1903: ld [%l6 + %lo(_cpcb)], %l6
1.13 deraadt 1904: set USPACE-CCFSZ-80, %l5
1.1 deraadt 1905: add %l6, %l5, %sp /* over to kernel stack */
1906: CHECK_SP_REDZONE(%l6, %l5)
1907:
1908: /*
1909: * Copy return_from_trap far enough to allow us
1910: * to jump directly to rft_user_or_recover_pcb_windows
1911: * (since we know that is where we are headed).
1912: */
1913: ! and %l0, 31, %l3 ! still set (clean_trap_window
1914: ! leaves this register alone)
1915: set wmask, %l6
1916: ldub [%l6 + %l3], %l5 ! %l5 = 1 << ((CWP + 1) % nwindows)
1917: b rft_user_or_recover_pcb_windows
1918: rd %wim, %l4 ! (read %wim first)
1919: #endif /* end `real' version of window overflow trap handler */
1920:
1921: /*
1922: * Window underflow trap handler.
1923: * %l0 = %psr
1924: * %l1 = return pc
1925: * %l2 = return npc
1926: *
1927: * A picture:
1928: *
1929: * T R I X
1930: * 0 0 0 1 0 0 0 (%wim)
1931: * [bit numbers increase towards the right;
1932: * `restore' moves right & `save' moves left]
1933: *
1934: * T is the current (Trap) window, R is the window that attempted
1935: * a `Restore' instruction, I is the Invalid window, and X is the
1936: * window we want to make invalid before we return.
1937: *
1938: * Since window R is valid, we cannot use rft_user to restore stuff
1939: * for us. We have to duplicate its logic. YUCK.
1940: *
1941: * Incidentally, TRIX are for kids. Silly rabbit!
1942: */
1943: window_uf:
1944: #ifdef TRIVIAL_WINDOW_UNDERFLOW_HANDLER
1945: wr %g0, 0, %wim ! allow us to enter I
1946: restore ! to R
1947: nop
1948: nop
1949: restore ! to I
1950: restore %g0, 1, %l1 ! to X
1951: rd %psr, %l0
1952: sll %l1, %l0, %l0
1953: wr %l0, 0, %wim
1954: save %g0, %g0, %g0 ! back to I
1955: LOADWIN(%sp)
1956: save %g0, %g0, %g0 ! back to R
1957: save %g0, %g0, %g0 ! back to T
1958: RETT
1959: #else
1960: wr %g0, 0, %wim ! allow us to enter I
1961: btst PSR_PS, %l0
1962: restore ! enter window R
1963: bz winuf_user
1964: restore ! enter window I
1965:
1966: /*
1967: * Underflow from kernel mode. Just recover the
1968: * registers and go (except that we have to update
1969: * the blasted user pcb fields).
1970: */
1971: restore %g0, 1, %l1 ! enter window X, then set %l1 to 1
1972: rd %psr, %l0 ! cwp = %psr & 31;
1973: and %l0, 31, %l0
1974: sll %l1, %l0, %l1 ! wim = 1 << cwp;
1975: wr %l1, 0, %wim ! setwim(wim);
1976: sethi %hi(_cpcb), %l1
1977: ld [%l1 + %lo(_cpcb)], %l1
1978: st %l0, [%l1 + PCB_WIM] ! cpcb->pcb_wim = cwp;
1979: save %g0, %g0, %g0 ! back to window I
1980: LOADWIN(%sp)
1981: save %g0, %g0, %g0 ! back to R
1982: save %g0, %g0, %g0 ! and then to T
1983: wr %l0, 0, %psr ! fix those cond codes....
1984: nop ! (let them settle in)
1985: RETT
1986:
1987: winuf_user:
1988: /*
1989: * Underflow from user mode.
1990: *
1991: * We cannot use rft_user (as noted above) because
1992: * we must re-execute the `restore' instruction.
1993: * Since it could be, e.g., `restore %l0,0,%l0',
1994: * it is not okay to touch R's registers either.
1995: *
1996: * We are now in window I.
1997: */
1998: btst 7, %sp ! if unaligned, it is invalid
1999: bne winuf_invalid
2000: EMPTY
2001:
1.13 deraadt 2002: sethi %hi(_pgofset), %l4
2003: ld [%l4 + %lo(_pgofset)], %l4
2004: PTE_OF_ADDR(%sp, %l7, winuf_invalid, %l4)
1.1 deraadt 2005: CMP_PTE_USER_READ(%l7) ! if first page not readable,
2006: bne winuf_invalid ! it is invalid
2007: EMPTY
1.13 deraadt 2008: SLT_IF_1PAGE_RW(%sp, %l7, %l4) ! first page is readable
1.1 deraadt 2009: bl,a winuf_ok ! if only one page, enter window X
2010: restore %g0, 1, %l1 ! and goto ok, & set %l1 to 1
2011: add %sp, 7*8, %l5
1.13 deraadt 2012: add %l4, 62, %l4
2013: PTE_OF_ADDR(%l5, %l7, winuf_invalid, %l4)
1.1 deraadt 2014: CMP_PTE_USER_READ(%l7) ! check second page too
2015: be,a winuf_ok ! enter window X and goto ok
2016: restore %g0, 1, %l1 ! (and then set %l1 to 1)
2017:
2018: winuf_invalid:
2019: /*
2020: * We were unable to restore the window because %sp
2021: * is invalid or paged out. Return to the trap window
2022: * and call trap(T_WINUF). This will save R to the user
2023: * stack, then load both R and I into the pcb rw[] area,
2024: * and return with pcb_nsaved set to -1 for success, 0 for
2025: * failure. `Failure' indicates that someone goofed with the
2026: * trap registers (e.g., signals), so that we need to return
2027: * from the trap as from a syscall (probably to a signal handler)
2028: * and let it retry the restore instruction later. Note that
2029: * window R will have been pushed out to user space, and thus
2030: * be the invalid window, by the time we get back here. (We
2031: * continue to label it R anyway.) We must also set %wim again,
2032: * and set pcb_uw to 1, before enabling traps. (Window R is the
2033: * only window, and it is a user window).
2034: */
2035: save %g0, %g0, %g0 ! back to R
1.12 pk 2036: #ifdef SUN_AS /* this gives `as' mild heartburn */
1.1 deraadt 2037: save %g0, 1, %l4 ! back to T, then %l4 = 1
2038: #else
2039: save %g0, %g0, %g0 ! back to T
2040: mov 1, %l4 ! and set %l4 = 1
2041: #endif
2042: sethi %hi(_cpcb), %l6
2043: ld [%l6 + %lo(_cpcb)], %l6
2044: st %l4, [%l6 + PCB_UW] ! pcb_uw = 1
2045: ld [%l6 + PCB_WIM], %l5 ! get log2(%wim)
2046: sll %l4, %l5, %l4 ! %l4 = old %wim
2047: wr %l4, 0, %wim ! window I is now invalid again
1.13 deraadt 2048: set USPACE-CCFSZ-80, %l5
1.1 deraadt 2049: add %l6, %l5, %sp ! get onto kernel stack
2050: CHECK_SP_REDZONE(%l6, %l5)
2051:
2052: /*
2053: * Okay, call trap(T_WINUF, psr, pc, &tf).
2054: * See `slowtrap' above for operation.
2055: */
2056: wr %l0, PSR_ET, %psr
2057: std %l0, [%sp + CCFSZ + 0] ! tf.tf_psr, tf.tf_pc
2058: rd %y, %l3
2059: std %l2, [%sp + CCFSZ + 8] ! tf.tf_npc, tf.tf_y
2060: mov T_WINUF, %o0
2061: st %g1, [%sp + CCFSZ + 20] ! tf.tf_global[1]
2062: mov %l0, %o1
2063: std %g2, [%sp + CCFSZ + 24] ! etc
2064: mov %l1, %o2
2065: std %g4, [%sp + CCFSZ + 32]
2066: add %sp, CCFSZ, %o3
2067: std %g6, [%sp + CCFSZ + 40]
2068: std %i0, [%sp + CCFSZ + 48] ! tf.tf_out[0], etc
2069: std %i2, [%sp + CCFSZ + 56]
2070: std %i4, [%sp + CCFSZ + 64]
2071: call _trap ! trap(T_WINUF, pc, psr, &tf)
2072: std %i6, [%sp + CCFSZ + 72] ! tf.tf_out[6]
2073:
2074: ldd [%sp + CCFSZ + 0], %l0 ! new psr, pc
2075: ldd [%sp + CCFSZ + 8], %l2 ! new npc, %y
2076: wr %l3, 0, %y
2077: ld [%sp + CCFSZ + 20], %g1
2078: ldd [%sp + CCFSZ + 24], %g2
2079: ldd [%sp + CCFSZ + 32], %g4
2080: ldd [%sp + CCFSZ + 40], %g6
2081: ldd [%sp + CCFSZ + 48], %i0 ! %o0 for window R, etc
2082: ldd [%sp + CCFSZ + 56], %i2
2083: ldd [%sp + CCFSZ + 64], %i4
2084: wr %l0, 0, %psr ! disable traps: test must be atomic
2085: ldd [%sp + CCFSZ + 72], %i6
2086: sethi %hi(_cpcb), %l6
2087: ld [%l6 + %lo(_cpcb)], %l6
2088: ld [%l6 + PCB_NSAVED], %l7 ! if nsaved is -1, we have our regs
2089: tst %l7
2090: bl,a 1f ! got them
2091: wr %g0, 0, %wim ! allow us to enter windows R, I
2092: b,a return_from_trap
2093:
2094: /*
2095: * Got 'em. Load 'em up.
2096: */
2097: 1:
2098: mov %g6, %l3 ! save %g6; set %g6 = cpcb
2099: mov %l6, %g6
2100: st %g0, [%g6 + PCB_NSAVED] ! and clear magic flag
2101: restore ! from T to R
2102: restore ! from R to I
2103: restore %g0, 1, %l1 ! from I to X, then %l1 = 1
2104: rd %psr, %l0 ! cwp = %psr;
2105: sll %l1, %l0, %l1
2106: wr %l1, 0, %wim ! make window X invalid
2107: and %l0, 31, %l0
2108: st %l0, [%g6 + PCB_WIM] ! cpcb->pcb_wim = cwp;
2109: nop ! unnecessary? old wim was 0...
2110: save %g0, %g0, %g0 ! back to I
2111: LOADWIN(%g6 + PCB_RW + 64) ! load from rw[1]
2112: save %g0, %g0, %g0 ! back to R
2113: LOADWIN(%g6 + PCB_RW) ! load from rw[0]
2114: save %g0, %g0, %g0 ! back to T
2115: wr %l0, 0, %psr ! restore condition codes
2116: mov %l3, %g6 ! fix %g6
2117: RETT
2118:
2119: /*
2120: * Restoring from user stack, but everything has checked out
2121: * as good. We are now in window X, and %l1 = 1. Window R
2122: * is still valid and holds user values.
2123: */
2124: winuf_ok:
2125: rd %psr, %l0
2126: sll %l1, %l0, %l1
2127: wr %l1, 0, %wim ! make this one invalid
2128: sethi %hi(_cpcb), %l2
2129: ld [%l2 + %lo(_cpcb)], %l2
2130: and %l0, 31, %l0
2131: st %l0, [%l2 + PCB_WIM] ! cpcb->pcb_wim = cwp;
2132: save %g0, %g0, %g0 ! back to I
2133: LOADWIN(%sp)
2134: save %g0, %g0, %g0 ! back to R
2135: save %g0, %g0, %g0 ! back to T
2136: wr %l0, 0, %psr ! restore condition codes
2137: nop ! it takes three to tangle
2138: RETT
2139: #endif /* end `real' version of window underflow trap handler */
2140:
2141: /*
2142: * Various return-from-trap routines (see return_from_trap).
2143: */
2144:
2145: /*
2146: * Return from trap, to kernel.
2147: * %l0 = %psr
2148: * %l1 = return pc
2149: * %l2 = return npc
2150: * %l4 = %wim
2151: * %l5 = bit for previous window
2152: */
2153: rft_kernel:
2154: btst %l5, %l4 ! if (wim & l5)
2155: bnz 1f ! goto reload;
2156: wr %l0, 0, %psr ! but first put !@#*% cond codes back
2157:
2158: /* previous window is valid; just rett */
2159: nop ! wait for cond codes to settle in
2160: RETT
2161:
2162: /*
2163: * Previous window is invalid.
2164: * Update %wim and then reload l0..i7 from frame.
2165: *
2166: * T I X
2167: * 0 0 1 0 0 (%wim)
2168: * [see picture in window_uf handler]
2169: *
2170: * T is the current (Trap) window, I is the Invalid window,
2171: * and X is the window we want to make invalid. Window X
2172: * currently has no useful values.
2173: */
2174: 1:
2175: wr %g0, 0, %wim ! allow us to enter window I
2176: nop; nop; nop ! (it takes a while)
2177: restore ! enter window I
2178: restore %g0, 1, %l1 ! enter window X, then %l1 = 1
2179: rd %psr, %l0 ! CWP = %psr & 31;
2180: and %l0, 31, %l0
2181: sll %l1, %l0, %l1 ! wim = 1 << CWP;
2182: wr %l1, 0, %wim ! setwim(wim);
2183: sethi %hi(_cpcb), %l1
2184: ld [%l1 + %lo(_cpcb)], %l1
2185: st %l0, [%l1 + PCB_WIM] ! cpcb->pcb_wim = l0 & 31;
2186: save %g0, %g0, %g0 ! back to window I
2187: LOADWIN(%sp)
2188: save %g0, %g0, %g0 ! back to window T
2189: /*
2190: * Note that the condition codes are still set from
2191: * the code at rft_kernel; we can simply return.
2192: */
2193: RETT
2194:
2195: /*
2196: * Return from trap, to user. Checks for scheduling trap (`ast') first;
2197: * will re-enter trap() if set. Note that we may have to switch from
2198: * the interrupt stack to the kernel stack in this case.
2199: * %l0 = %psr
2200: * %l1 = return pc
2201: * %l2 = return npc
2202: * %l4 = %wim
2203: * %l5 = bit for previous window
2204: * %l6 = cpcb
2205: * If returning to a valid window, just set psr and return.
2206: */
2207: rft_user:
2208: ! sethi %hi(_want_ast), %l7 ! (done below)
2209: ld [%l7 + %lo(_want_ast)], %l7
2210: tst %l7 ! want AST trap?
2211: bne,a softtrap ! yes, re-enter trap with type T_AST
2212: mov T_AST, %o0
2213:
2214: btst %l5, %l4 ! if (wim & l5)
2215: bnz 1f ! goto reload;
2216: wr %l0, 0, %psr ! restore cond codes
2217: nop ! (three instruction delay)
2218: RETT
2219:
2220: /*
2221: * Previous window is invalid.
2222: * Before we try to load it, we must verify its stack pointer.
2223: * This is much like the underflow handler, but a bit easier
2224: * since we can use our own local registers.
2225: */
2226: 1:
2227: btst 7, %fp ! if unaligned, address is invalid
2228: bne rft_invalid
2229: EMPTY
2230:
1.13 deraadt 2231: sethi %hi(_pgofset), %l3
2232: ld [%l3 + %lo(_pgofset)], %l3
2233: PTE_OF_ADDR(%fp, %l7, rft_invalid, %l3)
1.1 deraadt 2234: CMP_PTE_USER_READ(%l7) ! try first page
2235: bne rft_invalid ! no good
2236: EMPTY
1.13 deraadt 2237: SLT_IF_1PAGE_RW(%fp, %l7, %l3)
1.1 deraadt 2238: bl,a rft_user_ok ! only 1 page: ok
2239: wr %g0, 0, %wim
2240: add %fp, 7*8, %l5
1.13 deraadt 2241: add %l3, 62, %l3
2242: PTE_OF_ADDR(%l5, %l7, rft_invalid, %l3)
1.1 deraadt 2243: CMP_PTE_USER_READ(%l7) ! check 2nd page too
2244: be,a rft_user_ok
2245: wr %g0, 0, %wim
2246:
2247: /*
2248: * The window we wanted to pull could not be pulled. Instead,
2249: * re-enter trap with type T_RWRET. This will pull the window
2250: * into cpcb->pcb_rw[0] and set cpcb->pcb_nsaved to -1, which we
2251: * will detect when we try to return again.
2252: */
2253: rft_invalid:
2254: b softtrap
2255: mov T_RWRET, %o0
2256:
2257: /*
2258: * The window we want to pull can be pulled directly.
2259: */
2260: rft_user_ok:
2261: ! wr %g0, 0, %wim ! allow us to get into it
2262: wr %l0, 0, %psr ! fix up the cond codes now
2263: nop; nop; nop
2264: restore ! enter window I
2265: restore %g0, 1, %l1 ! enter window X, then %l1 = 1
2266: rd %psr, %l0 ! l0 = (junk << 5) + CWP;
2267: sll %l1, %l0, %l1 ! %wim = 1 << CWP;
2268: wr %l1, 0, %wim
2269: sethi %hi(_cpcb), %l1
2270: ld [%l1 + %lo(_cpcb)], %l1
2271: and %l0, 31, %l0
2272: st %l0, [%l1 + PCB_WIM] ! cpcb->pcb_wim = l0 & 31;
2273: save %g0, %g0, %g0 ! back to window I
2274: LOADWIN(%sp) ! suck hard
2275: save %g0, %g0, %g0 ! back to window T
2276: RETT
2277:
2278: /*
2279: * Return from trap. Entered after a
2280: * wr %l0, 0, %psr
2281: * which disables traps so that we can rett; registers are:
2282: *
2283: * %l0 = %psr
2284: * %l1 = return pc
2285: * %l2 = return npc
2286: *
2287: * (%l3..%l7 anything).
2288: *
2289: * If we are returning to user code, we must:
2290: * 1. Check for register windows in the pcb that belong on the stack.
2291: * If there are any, reenter trap with type T_WINOF.
2292: * 2. Make sure the register windows will not underflow. This is
2293: * much easier in kernel mode....
2294: */
2295: return_from_trap:
2296: ! wr %l0, 0, %psr ! disable traps so we can rett
2297: ! (someone else did this already)
2298: and %l0, 31, %l5
2299: set wmask, %l6
2300: ldub [%l6 + %l5], %l5 ! %l5 = 1 << ((CWP + 1) % nwindows)
2301: btst PSR_PS, %l0 ! returning to userland?
2302: bnz rft_kernel ! no, go return to kernel
2303: rd %wim, %l4 ! (read %wim in any case)
2304:
2305: rft_user_or_recover_pcb_windows:
2306: /*
2307: * (entered with %l4=%wim, %l5=wmask[cwp]; %l0..%l2 as usual)
2308: *
2309: * check cpcb->pcb_nsaved:
2310: * if 0, do a `normal' return to user (see rft_user);
2311: * if > 0, cpcb->pcb_rw[] holds registers to be copied to stack;
2312: * if -1, cpcb->pcb_rw[0] holds user registers for rett window
2313: * from an earlier T_RWRET pseudo-trap.
2314: */
2315: sethi %hi(_cpcb), %l6
2316: ld [%l6 + %lo(_cpcb)], %l6
2317: ld [%l6 + PCB_NSAVED], %l7
2318: tst %l7
2319: bz,a rft_user
2320: sethi %hi(_want_ast), %l7 ! first instr of rft_user
2321:
2322: bg,a softtrap ! if (pcb_nsaved > 0)
2323: mov T_WINOF, %o0 ! trap(T_WINOF);
2324:
2325: /*
2326: * To get here, we must have tried to return from a previous
2327: * trap and discovered that it would cause a window underflow.
2328: * We then must have tried to pull the registers out of the
2329: * user stack (from the address in %fp==%i6) and discovered
2330: * that it was either unaligned or not loaded in memory, and
2331: * therefore we ran a trap(T_RWRET), which loaded one set of
2332: * registers into cpcb->pcb_pcb_rw[0] (if it had killed the
2333: * process due to a bad stack, we would not be here).
2334: *
2335: * We want to load pcb_rw[0] into the previous window, which
2336: * we know is currently invalid. In other words, we want
2337: * %wim to be 1 << ((cwp + 2) % nwindows).
2338: */
2339: wr %g0, 0, %wim ! enable restores
2340: mov %g6, %l3 ! save g6 in l3
2341: mov %l6, %g6 ! set g6 = &u
2342: st %g0, [%g6 + PCB_NSAVED] ! clear cpcb->pcb_nsaved
2343: restore ! enter window I
2344: restore %g0, 1, %l1 ! enter window X, then %l1 = 1
2345: rd %psr, %l0
2346: sll %l1, %l0, %l1 ! %wim = 1 << CWP;
2347: wr %l1, 0, %wim
2348: and %l0, 31, %l0
2349: st %l0, [%g6 + PCB_WIM] ! cpcb->pcb_wim = CWP;
2350: nop ! unnecessary? old wim was 0...
2351: save %g0, %g0, %g0 ! back to window I
2352: LOADWIN(%g6 + PCB_RW)
2353: save %g0, %g0, %g0 ! back to window T (trap window)
2354: wr %l0, 0, %psr ! cond codes, cond codes everywhere
2355: mov %l3, %g6 ! restore g6
2356: RETT
2357:
2358: ! exported end marker for kernel gdb
2359: .globl _endtrapcode
2360: _endtrapcode:
2361:
2362: /*
2363: * init_tables(nwin) int nwin;
2364: *
2365: * Set up the uwtab and wmask tables.
2366: * We know nwin > 1.
2367: */
2368: init_tables:
2369: /*
2370: * for (i = -nwin, j = nwin - 2; ++i < 0; j--)
2371: * uwtab[i] = j;
2372: * (loop runs at least once)
2373: */
2374: set uwtab, %o3
2375: sub %g0, %o0, %o1 ! i = -nwin + 1
2376: inc %o1
2377: add %o0, -2, %o2 ! j = nwin - 2;
2378: 0:
2379: stb %o2, [%o3 + %o1] ! uwtab[i] = j;
2380: 1:
2381: inccc %o1 ! ++i < 0?
2382: bl 0b ! yes, continue loop
2383: dec %o2 ! in any case, j--
2384:
2385: /*
2386: * (i now equals 0)
2387: * for (j = nwin - 1; i < nwin; i++, j--)
2388: * uwtab[i] = j;
2389: * (loop runs at least twice)
2390: */
2391: sub %o0, 1, %o2 ! j = nwin - 1
2392: 0:
2393: stb %o2, [%o3 + %o1] ! uwtab[i] = j
2394: inc %o1 ! i++
2395: 1:
2396: cmp %o1, %o0 ! i < nwin?
2397: bl 0b ! yes, continue
2398: dec %o2 ! in any case, j--
2399:
2400: /*
2401: * We observe that, for i in 0..nwin-2, (i+1)%nwin == i+1;
2402: * for i==nwin-1, (i+1)%nwin == 0.
2403: * To avoid adding 1, we run i from 1 to nwin and set
2404: * wmask[i-1].
2405: *
2406: * for (i = j = 1; i < nwin; i++) {
2407: * j <<= 1; (j now == 1 << i)
2408: * wmask[i - 1] = j;
2409: * }
2410: * (loop runs at least once)
2411: */
2412: set wmask - 1, %o3
2413: mov 1, %o1 ! i = 1;
2414: mov 2, %o2 ! j = 2;
2415: 0:
2416: stb %o2, [%o3 + %o1] ! (wmask - 1)[i] = j;
2417: inc %o1 ! i++
2418: cmp %o1, %o0 ! i < nwin?
2419: bl,a 0b ! yes, continue
2420: sll %o2, 1, %o2 ! (and j <<= 1)
2421:
2422: /*
2423: * Now i==nwin, so we want wmask[i-1] = 1.
2424: */
2425: mov 1, %o2 ! j = 1;
2426: retl
2427: stb %o2, [%o3 + %o1] ! (wmask - 1)[i] = j;
2428:
1.13 deraadt 2429: #ifdef SUN4
2430: /*
2431: * getidprom(struct idprom *, sizeof(struct idprom))
2432: */
2433: .global _getidprom
2434: _getidprom:
2435: set AC_IDPROM, %o2
2436: 1: lduba [%o2] ASI_CONTROL, %o3
2437: stb %o3, [%o0]
2438: inc %o0
2439: inc %o2
2440: dec %o1
2441: cmp %o1, 0
2442: bne 1b
2443: nop
2444: retl
2445: nop
2446: #endif
2447:
1.1 deraadt 2448: dostart:
1.32 pk 2449: /*
2450: * Startup.
2451: *
2452: * We have been loaded in low RAM, at some address which
2453: * is page aligned (0x4000 actually) rather than where we
2454: * want to run (0xf8004000). Until we get everything set,
2455: * we have to be sure to use only pc-relative addressing.
2456: */
2457:
1.27 pk 2458: #ifdef DDB
2459: /*
2460: * First, check for DDB arguments. The loader passes `_esym' in %o1.
2461: * A DDB magic number is passed in %o2 to allow for bootloaders
2462: * that know nothing about DDB symbol loading conventions.
2463: */
2464: set 0x44444230, %l3
2465: cmp %o2, %l3 ! chk magic
2466: bne 1f
2467: tst %o1 ! do we have the symbols?
2468: bz 1f
2469: nop
2470: sethi %hi(_esym - KERNBASE), %l3 ! store _esym
2471: st %o1, [%l3 + %lo(_esym - KERNBASE)]
2472: 1:
2473: #endif
1.13 deraadt 2474: /*
2475: * Sun4 passes in the `load address'. Although possible, its highly
2476: * unlikely that OpenBoot would place the prom vector there.
2477: */
1.17 pk 2478: set 0x4000, %g7
2479: cmp %o0, %g7
1.13 deraadt 2480: beq is_sun4
1.14 deraadt 2481: nop
2482:
1.20 deraadt 2483: #if defined(SUN4C) || defined(SUN4M)
1.14 deraadt 2484: mov %o0, %g7 ! save prom vector pointer
1.9 deraadt 2485:
1.13 deraadt 2486: /*
2487: * are we on a sun4c or a sun4m?
2488: */
1.28 deraadt 2489: ld [%g7 + PV_NODEOPS], %o4 ! node = pv->pv_nodeops->no_nextnode(0)
2490: ld [%o4 + NO_NEXTNODE], %o4
1.18 deraadt 2491: call %o4
2492: mov 0, %o0 ! node
2493: set _cputypvar, %o1 ! name = "compatibility"
2494: set _cputypval, %o2 ! buffer ptr (assume buffer long enough)
1.28 deraadt 2495: ld [%g7 + PV_NODEOPS], %o4 ! (void)pv->pv_nodeops->no_getprop(...)
2496: ld [%o4 + NO_GETPROP], %o4
1.18 deraadt 2497: call %o4
2498: nop
2499:
2500: set _cputypval, %o2 ! buffer ptr
2501: ldub [%o2 + 4], %o0 ! which is it... "sun4c", "sun4m", "sun4d"?
2502: cmp %o0, 'c'
2503: beq is_sun4c
1.13 deraadt 2504: nop
1.18 deraadt 2505: cmp %o0, 'm'
2506: beq is_sun4m
2507: nop
1.20 deraadt 2508: #endif /* SUN4C || SUN4M */
1.18 deraadt 2509:
2510: ! ``on a sun4d?! hell no!''
1.28 deraadt 2511: ld [%g7 + PV_HALT], %o1 ! by this kernel, then halt
1.18 deraadt 2512: call %o1
2513: nop
2514:
2515: is_sun4m:
1.13 deraadt 2516: #if defined(SUN4M)
2517: mov SUN4CM_PGSHIFT, %g5
2518: b start_havetype
2519: mov CPU_SUN4M, %g4
2520: #else
1.9 deraadt 2521: set sun4m_notsup-KERNBASE, %o0
1.28 deraadt 2522: ld [%g7 + PV_EVAL], %o1
1.9 deraadt 2523: call %o1 ! print a message saying that the
2524: nop ! sun4m architecture is not supported
1.28 deraadt 2525: ld [%g7 + PV_HALT], %o1 ! by this kernel, then halt
1.9 deraadt 2526: call %o1
2527: nop
1.13 deraadt 2528: /*NOTREACHED*/
2529: #endif
2530: is_sun4c:
2531: #if defined(SUN4C)
2532: mov SUN4CM_PGSHIFT, %g5
2533:
2534: set AC_CONTEXT, %g1 ! paranoia: set context to kernel
2535: stba %g0, [%g1] ASI_CONTROL
2536:
2537: b start_havetype
2538: mov CPU_SUN4C, %g4 ! XXX CPU_SUN4
1.9 deraadt 2539: #else
2540: set sun4c_notsup-KERNBASE, %o0
1.28 deraadt 2541:
2542: ld [%g7 + PV_ROMVEC_VERS], %o1
2543: cmp %o1, 0
2544: bne 1f
2545: nop
2546:
2547: ! stupid version 0 rom interface is pv_eval(int length, char *string)
2548: mov %o0, %o1
2549: 2: ldub [%o0], %o4
2550: bne 2b
2551: inc %o0
2552: dec %o0
2553: sub %o0, %o1, %o0
2554:
2555: 1: ld [%g7 + PV_EVAL], %o2
2556: call %o2 ! print a message saying that the
1.9 deraadt 2557: nop ! sun4c architecture is not supported
1.28 deraadt 2558: ld [%g7 + PV_HALT], %o1 ! by this kernel, then halt
1.9 deraadt 2559: call %o1
2560: nop
1.13 deraadt 2561: /*NOTREACHED*/
1.9 deraadt 2562: #endif
1.13 deraadt 2563: is_sun4:
2564: #if defined(SUN4)
2565: mov SUN4_PGSHIFT, %g5
1.1 deraadt 2566:
1.13 deraadt 2567: set AC_CONTEXT, %g1 ! paranoia: set context to kernel
2568: stba %g0, [%g1] ASI_CONTROL
2569:
2570: b start_havetype
1.14 deraadt 2571: mov CPU_SUN4, %g4
1.13 deraadt 2572: #else
1.14 deraadt 2573: set PROM_BASE, %g7
2574:
1.13 deraadt 2575: set sun4_notsup-KERNBASE, %o0
1.28 deraadt 2576: ld [%g7 + OLDMON_PRINTF], %o1
1.13 deraadt 2577: call %o1 ! print a message saying that the
2578: nop ! sun4 architecture is not supported
1.28 deraadt 2579: ld [%g7 + OLDMON_HALT], %o1 ! by this kernel, then halt
1.13 deraadt 2580: call %o1
2581: nop
2582: /*NOTREACHED*/
2583: #endif
2584:
2585: start_havetype:
1.1 deraadt 2586: /*
2587: * Step 1: double map low RAM (addresses [0.._end-start-1])
2588: * to KERNBASE (addresses [KERNBASE.._end-1]). None of these
2589: * are `bad' aliases (since they are all on segment boundaries)
2590: * so we do not have to worry about cache aliasing.
2591: *
2592: * We map in another couple of segments just to have some
2593: * more memory (512K, actually) guaranteed available for
2594: * bootstrap code (pmap_bootstrap needs memory to hold MMU
2595: * and context data structures).
2596: */
2597: clr %l0 ! lowva
2598: set KERNBASE, %l1 ! highva
2599: set _end + (2 << 18), %l2 ! last va that must be remapped
1.8 pk 2600: #ifdef DDB
1.27 pk 2601: sethi %hi(_esym - KERNBASE), %o1
2602: ld [%o1+%lo(_esym - KERNBASE)], %o1
2603: tst %o1
1.8 pk 2604: bz 1f
2605: nop
1.27 pk 2606: set (2 << 18), %l2
2607: add %l2, %o1, %l2 ! last va that must be remapped
1.8 pk 2608: 1:
2609: #endif
1.13 deraadt 2610: /*
2611: * Need different initial mapping functions for different
2612: * types of machines.
2613: */
2614: #if defined(SUN4C)
2615: cmp %g4, CPU_SUN4C
1.9 deraadt 2616: bne 1f
1.14 deraadt 2617: set 1 << 18, %l3 ! segment size in bytes
1.1 deraadt 2618: 0:
2619: lduba [%l0] ASI_SEGMAP, %l4 ! segmap[highva] = segmap[lowva];
2620: stba %l4, [%l1] ASI_SEGMAP
2621: add %l3, %l1, %l1 ! highva += segsiz;
2622: cmp %l1, %l2 ! done?
1.34 pk 2623: blu 0b ! no, loop
1.1 deraadt 2624: add %l3, %l0, %l0 ! (and lowva += segsz)
2625:
2626: /*
2627: * Now map the interrupt enable register and clear any interrupts,
2628: * enabling NMIs. Note that we will not take NMIs until we change
2629: * %tbr.
2630: */
2631: set IE_reg_addr, %l0
1.13 deraadt 2632:
2633: set IE_REG_PTE_PG, %l1
2634: set INT_ENABLE_REG_PHYSADR, %l2
2635: srl %l2, %g5, %l2
2636: or %l2, %l1, %l1
2637:
1.1 deraadt 2638: sta %l1, [%l0] ASI_PTE
2639: mov IE_ALLIE, %l1
2640: nop; nop ! paranoia
2641: stb %l1, [%l0]
1.13 deraadt 2642: b startmap_done
1.9 deraadt 2643: nop
1.13 deraadt 2644: #endif /* SUN4C */
1.9 deraadt 2645: 1:
1.13 deraadt 2646: #if defined(SUN4)
2647: cmp %g4, CPU_SUN4
2648: bne 2f
1.34 pk 2649: #if defined(MMU_3L)
2650: set AC_IDPROM+1, %l3
2651: lduba [%l3] ASI_CONTROL, %l3
2652: cmp %l3, 0x24 ! XXX - SUN4_400
2653: bne no_3mmu
2654: set 1 << 24, %l3 ! region size in bytes
2655: add %l0, 2, %l0 ! get to proper half-word in RG space
2656: add %l1, 2, %l1
2657: 0:
2658: lduha [%l0] ASI_REGMAP, %l4 ! regmap[highva] = regmap[lowva];
2659: stha %l4, [%l1] ASI_REGMAP
2660: add %l3, %l1, %l1 ! highva += regsiz;
2661: cmp %l1, %l2 ! done?
2662: blu 0b ! no, loop
2663: add %l3, %l0, %l0 ! (and lowva += regsz)
2664: b,a remap_done
2665:
2666: no_3mmu:
2667: #endif
1.14 deraadt 2668: set 1 << 18, %l3 ! segment size in bytes
1.13 deraadt 2669: 0:
2670: lduha [%l0] ASI_SEGMAP, %l4 ! segmap[highva] = segmap[lowva];
2671: stha %l4, [%l1] ASI_SEGMAP
2672: add %l3, %l1, %l1 ! highva += segsiz;
2673: cmp %l1, %l2 ! done?
1.34 pk 2674: blu 0b ! no, loop
1.13 deraadt 2675: add %l3, %l0, %l0 ! (and lowva += segsz)
2676:
1.34 pk 2677: remap_done:
1.13 deraadt 2678: /*
2679: * Now map the interrupt enable register and clear any interrupts,
2680: * enabling NMIs. Note that we will not take NMIs until we change
2681: * %tbr.
2682: */
2683: set IE_reg_addr, %l0
2684:
2685: set IE_REG_PTE_PG, %l1
2686: set INT_ENABLE_REG_PHYSADR, %l2
2687: srl %l2, %g5, %l2
2688: or %l2, %l1, %l1
2689:
2690: sta %l1, [%l0] ASI_PTE
2691: mov IE_ALLIE, %l1
2692: nop; nop ! paranoia
2693: stb %l1, [%l0]
2694: b startmap_done
2695: nop
2696: #endif /* SUN4 */
2697: 2:
1.9 deraadt 2698: #if defined(SUN4M)
1.13 deraadt 2699: cmp %g4, CPU_SUN4M ! skip for sun4m!
2700: bne 3f
1.14 deraadt 2701: set _mapme-KERNBASE, %o0
1.13 deraadt 2702:
1.9 deraadt 2703: ! rominterpret("0 0 f8000000 15c6a0 map-pages");
1.28 deraadt 2704: ld [%g7 + PV_EVAL], %o1
1.9 deraadt 2705: call %o1 ! forth eval
2706: nop
1.13 deraadt 2707: b startmap_done
2708: nop
1.9 deraadt 2709: #endif /* SUN4M */
1.13 deraadt 2710: 3:
2711: ! botch! We should blow up.
2712:
2713: startmap_done:
1.1 deraadt 2714: /*
2715: * All set, fix pc and npc. Once we are where we should be,
2716: * we can give ourselves a stack and enable traps.
2717: */
1.9 deraadt 2718: set 1f, %g1
2719: jmp %g1
1.1 deraadt 2720: nop
2721: 1:
1.13 deraadt 2722: sethi %hi(_cputyp), %o0 ! what type of cpu we are on
1.9 deraadt 2723: st %g4, [%o0 + %lo(_cputyp)]
2724:
1.13 deraadt 2725: sethi %hi(_pgshift), %o0 ! pgshift = log2(nbpg)
2726: st %g5, [%o0 + %lo(_pgshift)]
2727:
2728: mov 1, %o0 ! nbpg = 1 << pgshift
2729: sll %o0, %g5, %g5
2730: sethi %hi(_nbpg), %o0 ! nbpg = bytes in a page
2731: st %g5, [%o0 + %lo(_nbpg)]
2732:
2733: sub %g5, 1, %g5
2734: sethi %hi(_pgofset), %o0 ! page offset = bytes in a page - 1
2735: st %g5, [%o0 + %lo(_pgofset)]
2736:
1.9 deraadt 2737: rd %psr, %g3 ! paranoia: make sure ...
2738: andn %g3, PSR_ET, %g3 ! we have traps off
2739: wr %g3, 0, %psr ! so that we can fiddle safely
2740: nop; nop; nop
2741:
2742: wr %g0, 0, %wim ! make sure we can set psr
2743: nop; nop; nop
2744: wr %g0, PSR_S|PSR_PS|PSR_PIL, %psr ! set initial psr
2745: nop; nop; nop
2746:
2747: wr %g0, 2, %wim ! set initial %wim (w1 invalid)
2748: mov 1, %g1 ! set pcb_wim (log2(%wim) = 1)
2749: sethi %hi(_u0 + PCB_WIM), %g2
2750: st %g1, [%g2 + %lo(_u0 + PCB_WIM)]
2751:
1.1 deraadt 2752: set USRSTACK - CCFSZ, %fp ! as if called from user code
2753: set estack0 - CCFSZ - 80, %sp ! via syscall(boot_me_up) or somesuch
2754: rd %psr, %l0
2755: wr %l0, PSR_ET, %psr
1.9 deraadt 2756: nop; nop; nop
1.1 deraadt 2757:
2758: /*
2759: * Step 2: clear BSS. This may just be paranoia; the boot
2760: * loader might already do it for us; but what the hell.
2761: */
2762: set _edata, %o0 ! bzero(edata, end - edata)
2763: set _end, %o1
2764: call _bzero
2765: sub %o1, %o0, %o1
2766:
2767: /*
2768: * Stash prom vectors now, after bzero, as it lives in bss
2769: * (which we just zeroed).
2770: * This depends on the fact that bzero does not use %g7.
2771: */
2772: sethi %hi(_promvec), %l0
2773: st %g7, [%l0 + %lo(_promvec)]
2774:
2775: /*
2776: * Step 3: compute number of windows and set up tables.
2777: * We could do some of this later.
2778: */
2779: save %sp, -64, %sp
2780: rd %psr, %g1
2781: restore
2782: and %g1, 31, %g1 ! want just the CWP bits
2783: add %g1, 1, %o0 ! compute nwindows
2784: sethi %hi(_nwindows), %o1 ! may as well tell everyone
2785: call init_tables
2786: st %o0, [%o1 + %lo(_nwindows)]
2787:
1.29 deraadt 2788: #ifdef SUN4
2789: /*
2790: * Some sun4 models have fewer than 8 windows. For extra
2791: * speed, we do not need to save/restore those windows
2792: * The save/restore code has 7 "save"'s followed by 7
2793: * "restore"'s -- we "nop" out the last "save" and first
2794: * "restore"
2795: */
2796: cmp %o0, 8
2797: beq 1f
2798: noplab: nop
2799: set noplab, %l0
2800: ld [%l0], %l1
2801: set wb1, %l0
2802: st %l1, [%l0 + 6*4]
2803: st %l1, [%l0 + 7*4]
2804: set wb2, %l0
2805: st %l1, [%l0 + 6*4]
2806: st %l1, [%l0 + 7*4]
2807: 1:
2808: #endif
2809:
1.1 deraadt 2810: /*
2811: * Step 4: change the trap base register, now that our trap handlers
2812: * will function (they need the tables we just set up).
2813: */
2814: set _trapbase, %l0
2815: wr %l0, 0, %tbr
1.9 deraadt 2816: nop; nop; nop ! paranoia
1.1 deraadt 2817:
2818: /*
1.11 deraadt 2819: * Ready to run C code; finish bootstrap.
1.1 deraadt 2820: */
2821: call _bootstrap
2822: nop
1.11 deraadt 2823:
2824: /*
2825: * Call main. This returns to us after loading /sbin/init into
2826: * user space. (If the exec fails, main() does not return.)
2827: */
1.1 deraadt 2828: call _main
1.11 deraadt 2829: clr %o0 ! our frame arg is ignored
1.1 deraadt 2830:
2831: /*
1.11 deraadt 2832: * Here we finish up as in syscall, but simplified. We need to
2833: * fiddle pc and npc a bit, as execve() / setregs() have only set
2834: * npc, in anticipation that trap.c will advance past the trap
2835: * instruction; but we bypass that, so we must do it manually.
2836: */
2837: mov PSR_S, %l0 ! user psr (no need to load it)
2838: ld [%sp + CCFSZ + 8], %l1 ! pc = npc from execve
2839: b init_syscall_ret
2840: add %l1, 4, %l2 ! npc = pc+4
1.1 deraadt 2841:
2842: /*
2843: * The following code is copied to the top of the user stack when each
2844: * process is exec'ed, and signals are `trampolined' off it.
2845: *
2846: * When this code is run, the stack looks like:
2847: * [%sp] 64 bytes to which registers can be dumped
2848: * [%sp + 64] signal number (goes in %o0)
2849: * [%sp + 64 + 4] signal code (goes in %o1)
2850: * [%sp + 64 + 8] placeholder
2851: * [%sp + 64 + 12] argument for %o3, currently unsupported (always 0)
2852: * [%sp + 64 + 16] first word of saved state (sigcontext)
2853: * .
2854: * .
2855: * .
2856: * [%sp + NNN] last word of saved state
2857: * (followed by previous stack contents or top of signal stack).
2858: * The address of the function to call is in %g1; the old %g1 and %o0
2859: * have already been saved in the sigcontext. We are running in a clean
2860: * window, all previous windows now being saved to the stack.
2861: *
2862: * Note that [%sp + 64 + 8] == %sp + 64 + 16. The copy at %sp+64+8
2863: * will eventually be removed, with a hole left in its place, if things
2864: * work out.
2865: */
2866: .globl _sigcode
2867: .globl _esigcode
2868: _sigcode:
2869: /*
2870: * XXX the `save' and `restore' below are unnecessary: should
2871: * replace with simple arithmetic on %sp
2872: *
2873: * Make room on the stack for 32 %f registers + %fsr. This comes
2874: * out to 33*4 or 132 bytes, but this must be aligned to a multiple
2875: * of 8, or 136 bytes.
2876: */
2877: save %sp, -CCFSZ - 136, %sp
2878: mov %g2, %l2 ! save globals in %l registers
2879: mov %g3, %l3
2880: mov %g4, %l4
2881: mov %g5, %l5
2882: mov %g6, %l6
2883: mov %g7, %l7
2884: /*
2885: * Saving the fpu registers is expensive, so do it iff the fsr
2886: * stored in the sigcontext shows that the fpu is enabled.
2887: */
2888: ld [%fp + 64 + 16 + SC_PSR_OFFSET], %l0
2889: sethi %hi(PSR_EF), %l1 ! FPU enable bit is too high for andcc
2890: andcc %l0, %l1, %l0 ! %l0 = fpu enable bit
2891: be 1f ! if not set, skip the saves
2892: rd %y, %l1 ! in any case, save %y
2893:
2894: ! fpu is enabled, oh well
2895: st %fsr, [%sp + CCFSZ + 0]
2896: std %f0, [%sp + CCFSZ + 8]
2897: std %f2, [%sp + CCFSZ + 16]
2898: std %f4, [%sp + CCFSZ + 24]
2899: std %f6, [%sp + CCFSZ + 32]
2900: std %f8, [%sp + CCFSZ + 40]
2901: std %f10, [%sp + CCFSZ + 48]
2902: std %f12, [%sp + CCFSZ + 56]
2903: std %f14, [%sp + CCFSZ + 64]
2904: std %f16, [%sp + CCFSZ + 72]
2905: std %f18, [%sp + CCFSZ + 80]
2906: std %f20, [%sp + CCFSZ + 88]
2907: std %f22, [%sp + CCFSZ + 96]
2908: std %f24, [%sp + CCFSZ + 104]
2909: std %f26, [%sp + CCFSZ + 112]
2910: std %f28, [%sp + CCFSZ + 120]
2911: std %f30, [%sp + CCFSZ + 128]
2912:
2913: 1:
2914: ldd [%fp + 64], %o0 ! sig, code
2915: ld [%fp + 76], %o3 ! arg3
2916: call %g1 ! (*sa->sa_handler)(sig,code,scp,arg3)
2917: add %fp, 64 + 16, %o2 ! scp
2918:
2919: /*
2920: * Now that the handler has returned, re-establish all the state
2921: * we just saved above, then do a sigreturn.
2922: */
2923: tst %l0 ! reload fpu registers?
2924: be 1f ! if not, skip the loads
2925: wr %l1, %g0, %y ! in any case, restore %y
2926:
2927: ld [%sp + CCFSZ + 0], %fsr
2928: ldd [%sp + CCFSZ + 8], %f0
2929: ldd [%sp + CCFSZ + 16], %f2
2930: ldd [%sp + CCFSZ + 24], %f4
2931: ldd [%sp + CCFSZ + 32], %f6
2932: ldd [%sp + CCFSZ + 40], %f8
2933: ldd [%sp + CCFSZ + 48], %f10
2934: ldd [%sp + CCFSZ + 56], %f12
2935: ldd [%sp + CCFSZ + 64], %f14
2936: ldd [%sp + CCFSZ + 72], %f16
2937: ldd [%sp + CCFSZ + 80], %f18
2938: ldd [%sp + CCFSZ + 88], %f20
2939: ldd [%sp + CCFSZ + 96], %f22
2940: ldd [%sp + CCFSZ + 104], %f24
2941: ldd [%sp + CCFSZ + 112], %f26
2942: ldd [%sp + CCFSZ + 120], %f28
2943: ldd [%sp + CCFSZ + 128], %f30
2944:
2945: 1:
2946: mov %l2, %g2
2947: mov %l3, %g3
2948: mov %l4, %g4
2949: mov %l5, %g5
2950: mov %l6, %g6
2951: mov %l7, %g7
2952:
2953: restore %g0, SYS_sigreturn, %g1 ! get registers back & set syscall #
2954: add %sp, 64 + 16, %o0 ! compute scp
2955: t ST_SYSCALL ! sigreturn(scp)
2956: ! sigreturn does not return unless it fails
2957: mov SYS_exit, %g1 ! exit(errno)
2958: t ST_SYSCALL
2959: _esigcode:
2960:
2961: /*
2962: * Primitives
2963: */
2964:
2965: #ifdef GPROF
2966: .globl mcount
2967: #define ENTRY(x) \
1.7 pk 2968: .globl _##x; _##x: ; \
1.1 deraadt 2969: save %sp, -CCFSZ, %sp; \
2970: call mcount; \
2971: nop; \
2972: restore
2973: #else
2974: #define ENTRY(x) .globl _##x; _##x:
2975: #endif
2976: #define ALTENTRY(x) .globl _##x; _##x:
2977:
2978: /*
1.24 deraadt 2979: * getfp() - get stack frame pointer
2980: */
2981: ENTRY(getfp)
2982: retl
2983: mov %fp, %o0
2984:
2985: /*
1.1 deraadt 2986: * copyinstr(fromaddr, toaddr, maxlength, &lencopied)
2987: *
2988: * Copy a null terminated string from the user address space into
2989: * the kernel address space.
2990: */
2991: ENTRY(copyinstr)
2992: ! %o0 = fromaddr, %o1 = toaddr, %o2 = maxlen, %o3 = &lencopied
2993: #ifdef DIAGNOSTIC
2994: tst %o2 ! kernel should never give maxlen <= 0
2995: ble 1f
2996: EMPTY
2997: #endif
2998: set KERNBASE, %o4
2999: cmp %o0, %o4 ! fromaddr < KERNBASE?
3000: blu,a Lcsdocopy ! yes, go do it
3001: sethi %hi(_cpcb), %o4 ! (first instr of copy)
3002:
3003: b Lcsdone ! no, return EFAULT
3004: mov EFAULT, %o0
3005:
3006: 1:
3007: sethi %hi(2f), %o0
3008: call _panic
3009: or %lo(2f), %o0, %o0
3010: 2: .asciz "copyinstr"
3011: ALIGN
3012:
3013: /*
3014: * copyoutstr(fromaddr, toaddr, maxlength, &lencopied)
3015: *
3016: * Copy a null terminated string from the kernel
3017: * address space to the user address space.
3018: */
3019: ENTRY(copyoutstr)
3020: ! %o0 = fromaddr, %o1 = toaddr, %o2 = maxlen, %o3 = &lencopied
3021: #ifdef DIAGNOSTIC
3022: tst %o2
3023: ble 1f
3024: EMPTY
3025: #endif
3026: set KERNBASE, %o4
3027: cmp %o1, %o4 ! toaddr < KERNBASE?
3028: blu,a Lcsdocopy ! yes, go do it
3029: sethi %hi(_cpcb), %o4 ! (first instr of copy)
3030:
3031: b Lcsdone ! no, return EFAULT
3032: mov EFAULT, %o0
3033:
3034: 1:
3035: sethi %hi(2f), %o0
3036: call _panic
3037: or %lo(2f), %o0, %o0
3038: 2: .asciz "copyoutstr"
3039: ALIGN
3040:
3041: Lcsdocopy:
3042: ! sethi %hi(_cpcb), %o4 ! (done earlier)
3043: ld [%o4 + %lo(_cpcb)], %o4 ! catch faults
3044: set Lcsfault, %o5
3045: st %o5, [%o4 + PCB_ONFAULT]
3046:
3047: mov %o1, %o5 ! save = toaddr;
3048: ! XXX should do this in bigger chunks when possible
3049: 0: ! loop:
3050: ldsb [%o0], %g1 ! c = *fromaddr;
3051: tst %g1
3052: stb %g1, [%o1] ! *toaddr++ = c;
3053: be 1f ! if (c == NULL)
3054: inc %o1 ! goto ok;
3055: deccc %o2 ! if (--len > 0) {
3056: bg 0b ! fromaddr++;
3057: inc %o0 ! goto loop;
3058: ! }
3059: !
3060: b Lcsdone ! error = ENAMETOOLONG;
3061: mov ENAMETOOLONG, %o0 ! goto done;
3062: 1: ! ok:
3063: clr %o0 ! error = 0;
3064: Lcsdone: ! done:
3065: sub %o1, %o5, %o1 ! len = to - save;
3066: tst %o3 ! if (lencopied)
3067: bnz,a 3f
3068: st %o1, [%o3] ! *lencopied = len;
3069: 3:
3070: retl ! cpcb->pcb_onfault = 0;
3071: st %g0, [%o4 + PCB_ONFAULT]! return (error);
3072:
3073: Lcsfault:
3074: b Lcsdone ! error = EFAULT;
3075: mov EFAULT, %o0 ! goto ret;
3076:
3077: /*
3078: * copystr(fromaddr, toaddr, maxlength, &lencopied)
3079: *
3080: * Copy a null terminated string from one point to another in
3081: * the kernel address space. (This is a leaf procedure, but
3082: * it does not seem that way to the C compiler.)
3083: */
3084: ENTRY(copystr)
3085: #ifdef DIAGNOSTIC
3086: tst %o2 ! if (maxlength <= 0)
3087: ble 4f ! panic(...);
3088: EMPTY
3089: #endif
3090: mov %o1, %o5 ! to0 = to;
3091: 0: ! loop:
3092: ldsb [%o0], %o4 ! c = *from;
3093: tst %o4
3094: stb %o4, [%o1] ! *to++ = c;
3095: be 1f ! if (c == 0)
3096: inc %o1 ! goto ok;
3097: deccc %o2 ! if (--len > 0) {
3098: bg,a 0b ! from++;
3099: inc %o0 ! goto loop;
3100: b 2f ! }
3101: mov ENAMETOOLONG, %o0 ! ret = ENAMETOOLONG; goto done;
3102: 1: ! ok:
3103: clr %o0 ! ret = 0;
3104: 2:
3105: sub %o1, %o5, %o1 ! len = to - to0;
3106: tst %o3 ! if (lencopied)
3107: bnz,a 3f
3108: st %o1, [%o3] ! *lencopied = len;
3109: 3:
3110: retl
3111: nop
3112: #ifdef DIAGNOSTIC
3113: 4:
3114: sethi %hi(5f), %o0
3115: call _panic
3116: or %lo(5f), %o0, %o0
3117: 5:
3118: .asciz "copystr"
3119: ALIGN
3120: #endif
3121:
3122: /*
3123: * Copyin(src, dst, len)
3124: *
3125: * Copy specified amount of data from user space into the kernel.
3126: */
3127: ENTRY(copyin)
3128: set KERNBASE, %o3
3129: cmp %o0, %o3 ! src < KERNBASE?
3130: blu,a Ldocopy ! yes, can try it
3131: sethi %hi(_cpcb), %o3
3132:
3133: /* source address points into kernel space: return EFAULT */
3134: retl
3135: mov EFAULT, %o0
3136:
3137: /*
3138: * Copyout(src, dst, len)
3139: *
3140: * Copy specified amount of data from kernel to user space.
3141: * Just like copyin, except that the `dst' addresses are user space
3142: * rather than the `src' addresses.
3143: */
3144: ENTRY(copyout)
3145: set KERNBASE, %o3
3146: cmp %o1, %o3 ! dst < KERBASE?
3147: blu,a Ldocopy
3148: sethi %hi(_cpcb), %o3
3149:
3150: /* destination address points into kernel space: return EFAULT */
3151: retl
3152: mov EFAULT, %o0
3153:
3154: /*
3155: * ******NOTE****** this depends on bcopy() not using %g7
3156: */
3157: Ldocopy:
3158: ! sethi %hi(_cpcb), %o3
3159: ld [%o3 + %lo(_cpcb)], %o3
3160: set Lcopyfault, %o4
3161: mov %o7, %g7 ! save return address
3162: call _bcopy ! bcopy(src, dst, len)
3163: st %o4, [%o3 + PCB_ONFAULT]
3164:
3165: sethi %hi(_cpcb), %o3
3166: ld [%o3 + %lo(_cpcb)], %o3
3167: st %g0, [%o3 + PCB_ONFAULT]
3168: jmp %g7 + 8
3169: clr %o0 ! return 0
3170:
3171: ! Copyin or copyout fault. Clear cpcb->pcb_onfault and return EFAULT.
3172: ! Note that although we were in bcopy, there is no state to clean up;
3173: ! the only special thing is that we have to return to [g7 + 8] rather than
3174: ! [o7 + 8].
3175: Lcopyfault:
3176: sethi %hi(_cpcb), %o3
3177: ld [%o3 + %lo(_cpcb)], %o3
3178: st %g0, [%o3 + PCB_ONFAULT]
3179: jmp %g7 + 8
3180: mov EFAULT, %o0
3181:
3182:
3183: /*
3184: * Write all user windows presently in the CPU back to the user's stack.
3185: * We just do `save' instructions until pcb_uw == 0.
3186: *
3187: * p = cpcb;
3188: * nsaves = 0;
3189: * while (p->pcb_uw > 0)
3190: * save(), nsaves++;
3191: * while (--nsaves >= 0)
3192: * restore();
3193: */
3194: ENTRY(write_user_windows)
3195: sethi %hi(_cpcb), %g6
3196: ld [%g6 + %lo(_cpcb)], %g6
3197: b 2f
3198: clr %g5
3199: 1:
3200: save %sp, -64, %sp
3201: 2:
3202: ld [%g6 + PCB_UW], %g7
3203: tst %g7
3204: bg,a 1b
3205: inc %g5
3206: 3:
3207: deccc %g5
3208: bge,a 3b
3209: restore
3210: retl
3211: nop
3212:
3213:
3214: .comm _want_resched,4
3215: /*
3216: * Masterpaddr is the p->p_addr of the last process on the processor.
3217: * XXX masterpaddr is almost the same as cpcb
3218: * XXX should delete this entirely
3219: */
3220: .comm _masterpaddr, 4
3221:
3222: /*
3223: * Switch statistics (for later tweaking):
3224: * nswitchdiff = p1 => p2 (i.e., chose different process)
1.10 deraadt 3225: * nswitchexit = number of calls to switchexit()
1.1 deraadt 3226: * _cnt.v_swtch = total calls to swtch+swtchexit
3227: */
3228: .comm _nswitchdiff, 4
3229: .comm _nswitchexit, 4
3230:
3231: /*
1.10 deraadt 3232: * REGISTER USAGE IN cpu_switch AND switchexit:
1.1 deraadt 3233: * This is split into two phases, more or less
3234: * `before we locate a new proc' and `after'.
3235: * Some values are the same in both phases.
3236: * Note that the %o0-registers are not preserved across
3237: * the psr change when entering a new process, since this
3238: * usually changes the CWP field (hence heavy usage of %g's).
3239: *
3240: * %g1 = oldpsr (excluding ipl bits)
3241: * %g2 = %hi(_whichqs); newpsr
3242: * %g3 = p
3243: * %g4 = lastproc
3244: * %g5 = <free>; newpcb
3245: * %g6 = %hi(_cpcb)
3246: * %g7 = %hi(_curproc)
3247: * %o0 = tmp 1
3248: * %o1 = tmp 2
3249: * %o2 = tmp 3
3250: * %o3 = tmp 4; whichqs; vm
3251: * %o4 = tmp 4; which; sswap
3252: * %o5 = tmp 5; q; <free>
3253: */
3254:
3255: /*
1.10 deraadt 3256: * switchexit is called only from cpu_exit() before the current process
1.1 deraadt 3257: * has freed its kernel stack; we must free it. (curproc is already NULL.)
3258: *
3259: * We lay the process to rest by changing to the `idle' kernel stack,
3260: * and note that the `last loaded process' is nonexistent.
3261: */
1.10 deraadt 3262: ENTRY(switchexit)
1.1 deraadt 3263: mov %o0, %g2 ! save the
3264: mov %o1, %g3 ! ... three parameters
3265: mov %o2, %g4 ! ... to kmem_free
3266:
3267: /*
3268: * Change pcb to idle u. area, i.e., set %sp to top of stack
3269: * and %psr to PSR_S|PSR_ET, and set cpcb to point to _idle_u.
3270: * Once we have left the old stack, we can call kmem_free to
3271: * destroy it. Call it any sooner and the register windows
3272: * go bye-bye.
3273: */
3274: set _idle_u, %g5
3275: sethi %hi(_cpcb), %g6
3276: mov 1, %g7
3277: wr %g0, PSR_S, %psr ! change to window 0, traps off
3278: wr %g0, 2, %wim ! and make window 1 the trap window
3279: st %g5, [%g6 + %lo(_cpcb)] ! cpcb = &idle_u
3280: st %g7, [%g5 + PCB_WIM] ! idle_u.pcb_wim = log2(2) = 1
1.13 deraadt 3281: set _idle_u + USPACE-CCFSZ, %sp ! set new %sp
1.1 deraadt 3282: #ifdef DEBUG
3283: set _idle_u, %l6
3284: SET_SP_REDZONE(%l6, %l5)
3285: #endif
3286: wr %g0, PSR_S|PSR_ET, %psr ! and then enable traps
3287: mov %g2, %o0 ! now ready to call kmem_free
3288: mov %g3, %o1
3289: call _kmem_free
3290: mov %g4, %o2
3291:
3292: /*
1.10 deraadt 3293: * Now fall through to `the last switch'. %g6 was set to
1.1 deraadt 3294: * %hi(_cpcb), but may have been clobbered in kmem_free,
3295: * so all the registers described below will be set here.
3296: *
3297: * REGISTER USAGE AT THIS POINT:
3298: * %g1 = oldpsr (excluding ipl bits)
3299: * %g2 = %hi(_whichqs)
3300: * %g4 = lastproc
3301: * %g6 = %hi(_cpcb)
3302: * %g7 = %hi(_curproc)
3303: * %o0 = tmp 1
3304: * %o1 = tmp 2
3305: * %o3 = whichqs
3306: */
3307:
3308: INCR(_nswitchexit) ! nswitchexit++;
3309: INCR(_cnt+V_SWTCH) ! cnt.v_switch++;
3310:
3311: mov PSR_S|PSR_ET, %g1 ! oldpsr = PSR_S | PSR_ET;
3312: sethi %hi(_whichqs), %g2
3313: clr %g4 ! lastproc = NULL;
3314: sethi %hi(_cpcb), %g6
3315: sethi %hi(_curproc), %g7
3316: /* FALLTHROUGH */
3317:
3318: /*
1.10 deraadt 3319: * When no processes are on the runq, switch
1.1 deraadt 3320: * idles here watiing for something to come ready.
3321: * The registers are set up as noted above.
3322: */
3323: .globl idle
3324: idle:
3325: st %g0, [%g7 + %lo(_curproc)] ! curproc = NULL;
3326: wr %g1, 0, %psr ! (void) spl0();
3327: 1: ! spin reading _whichqs until nonzero
3328: ld [%g2 + %lo(_whichqs)], %o3
3329: tst %o3
3330: bnz,a Lsw_scan
3331: wr %g1, PIL_CLOCK << 8, %psr ! (void) splclock();
3332: b,a 1b
3333:
3334: Lsw_panic_rq:
3335: sethi %hi(1f), %o0
3336: call _panic
3337: or %lo(1f), %o0, %o0
3338: Lsw_panic_wchan:
3339: sethi %hi(2f), %o0
3340: call _panic
3341: or %lo(2f), %o0, %o0
3342: Lsw_panic_srun:
3343: sethi %hi(3f), %o0
3344: call _panic
3345: or %lo(3f), %o0, %o0
1.10 deraadt 3346: 1: .asciz "switch rq"
3347: 2: .asciz "switch wchan"
3348: 3: .asciz "switch SRUN"
1.1 deraadt 3349: ALIGN
3350:
3351: /*
1.10 deraadt 3352: * cpu_switch() picks a process to run and runs it, saving the current
1.1 deraadt 3353: * one away. On the assumption that (since most workstations are
3354: * single user machines) the chances are quite good that the new
3355: * process will turn out to be the current process, we defer saving
3356: * it here until we have found someone to load. If that someone
3357: * is the current process we avoid both store and load.
3358: *
1.10 deraadt 3359: * cpu_switch() is always entered at splstatclock or splhigh.
1.1 deraadt 3360: *
3361: * IT MIGHT BE WORTH SAVING BEFORE ENTERING idle TO AVOID HAVING TO
3362: * SAVE LATER WHEN SOMEONE ELSE IS READY ... MUST MEASURE!
3363: */
1.10 deraadt 3364: .globl _runtime
3365: .globl _time
3366: ENTRY(cpu_switch)
1.1 deraadt 3367: /*
3368: * REGISTER USAGE AT THIS POINT:
3369: * %g1 = oldpsr (excluding ipl bits)
3370: * %g2 = %hi(_whichqs)
3371: * %g3 = p
3372: * %g4 = lastproc
3373: * %g5 = tmp 0
3374: * %g6 = %hi(_cpcb)
3375: * %g7 = %hi(_curproc)
3376: * %o0 = tmp 1
3377: * %o1 = tmp 2
3378: * %o2 = tmp 3
3379: * %o3 = tmp 4, then at Lsw_scan, whichqs
3380: * %o4 = tmp 5, then at Lsw_scan, which
3381: * %o5 = tmp 6, then at Lsw_scan, q
3382: */
3383: sethi %hi(_whichqs), %g2 ! set up addr regs
3384: sethi %hi(_cpcb), %g6
3385: ld [%g6 + %lo(_cpcb)], %o0
3386: std %o6, [%o0 + PCB_SP] ! cpcb->pcb_<sp,pc> = <sp,pc>;
3387: rd %psr, %g1 ! oldpsr = %psr;
3388: sethi %hi(_curproc), %g7
3389: ld [%g7 + %lo(_curproc)], %g4 ! lastproc = curproc;
3390: st %g1, [%o0 + PCB_PSR] ! cpcb->pcb_psr = oldpsr;
3391: andn %g1, PSR_PIL, %g1 ! oldpsr &= ~PSR_PIL;
3392:
1.10 deraadt 3393: /*
3394: * In all the fiddling we did to get this far, the thing we are
3395: * waiting for might have come ready, so let interrupts in briefly
3396: * before checking for other processes. Note that we still have
3397: * curproc set---we have to fix this or we can get in trouble with
3398: * the run queues below.
3399: */
3400: st %g0, [%g7 + %lo(_curproc)] ! curproc = NULL;
3401: wr %g1, 0, %psr ! (void) spl0();
3402: nop; nop; nop ! paranoia
1.1 deraadt 3403: wr %g1, PIL_CLOCK <<8 , %psr ! (void) splclock();
3404:
3405: Lsw_scan:
3406: nop; nop; nop ! paranoia
1.10 deraadt 3407: /*
3408: * We're about to run a (possibly) new process. Set runtime
3409: * to indicate its start time.
3410: */
3411: sethi %hi(_time), %o0
3412: ldd [%o0 + %lo(_time)], %o2
3413: sethi %hi(_runtime), %o0
3414: std %o2, [%o0 + %lo(_runtime)]
1.1 deraadt 3415:
3416: ld [%g2 + %lo(_whichqs)], %o3
3417:
3418: /*
3419: * Optimized inline expansion of `which = ffs(whichqs) - 1';
3420: * branches to idle if ffs(whichqs) was 0.
3421: */
3422: set ffstab, %o2
3423: andcc %o3, 0xff, %o1 ! byte 0 zero?
3424: bz,a 1f ! yes, try byte 1
3425: srl %o3, 8, %o0
3426: b 2f ! ffs = ffstab[byte0]; which = ffs - 1;
3427: ldsb [%o2 + %o1], %o0
3428: 1: andcc %o0, 0xff, %o1 ! byte 1 zero?
3429: bz,a 1f ! yes, try byte 2
3430: srl %o0, 8, %o0
3431: ldsb [%o2 + %o1], %o0 ! which = ffstab[byte1] + 7;
3432: b 3f
3433: add %o0, 7, %o4
3434: 1: andcc %o0, 0xff, %o1 ! byte 2 zero?
3435: bz,a 1f ! yes, try byte 3
3436: srl %o0, 8, %o0
3437: ldsb [%o2 + %o1], %o0 ! which = ffstab[byte2] + 15;
3438: b 3f
3439: add %o0, 15, %o4
3440: 1: ldsb [%o2 + %o0], %o0 ! ffs = ffstab[byte3] + 24
3441: addcc %o0, 24, %o0 ! (note that ffstab[0] == -24)
3442: bz idle ! if answer was 0, go idle
3443: EMPTY
3444: 2: sub %o0, 1, %o4 ! which = ffs(whichqs) - 1
3445: 3: /* end optimized inline expansion */
3446:
3447: /*
3448: * We found a nonempty run queue. Take its first process.
3449: */
3450: set _qs, %o5 ! q = &qs[which];
3451: sll %o4, 3, %o0
3452: add %o0, %o5, %o5
3453: ld [%o5], %g3 ! p = q->ph_link;
3454: cmp %g3, %o5 ! if (p == q)
1.10 deraadt 3455: be Lsw_panic_rq ! panic("switch rq");
1.1 deraadt 3456: EMPTY
1.10 deraadt 3457: ld [%g3], %o0 ! tmp0 = p->p_forw;
1.1 deraadt 3458: st %o0, [%o5] ! q->ph_link = tmp0;
1.10 deraadt 3459: st %o5, [%o0 + 4] ! tmp0->p_back = q;
1.1 deraadt 3460: cmp %o0, %o5 ! if (tmp0 == q)
3461: bne 1f
3462: EMPTY
3463: mov 1, %o1 ! whichqs &= ~(1 << which);
3464: sll %o1, %o4, %o1
3465: andn %o3, %o1, %o3
3466: st %o3, [%g2 + %lo(_whichqs)]
3467: 1:
3468: /*
3469: * PHASE TWO: NEW REGISTER USAGE:
3470: * %g1 = oldpsr (excluding ipl bits)
3471: * %g2 = newpsr
3472: * %g3 = p
3473: * %g4 = lastproc
3474: * %g5 = newpcb
3475: * %g6 = %hi(_cpcb)
3476: * %g7 = %hi(_curproc)
3477: * %o0 = tmp 1
3478: * %o1 = tmp 2
3479: * %o2 = tmp 3
3480: * %o3 = vm
3481: * %o4 = sswap
3482: * %o5 = <free>
3483: */
3484:
3485: /* firewalls */
3486: ld [%g3 + P_WCHAN], %o0 ! if (p->p_wchan)
3487: tst %o0
1.10 deraadt 3488: bne Lsw_panic_wchan ! panic("switch wchan");
1.1 deraadt 3489: EMPTY
3490: ldsb [%g3 + P_STAT], %o0 ! if (p->p_stat != SRUN)
3491: cmp %o0, SRUN
1.10 deraadt 3492: bne Lsw_panic_srun ! panic("switch SRUN");
1.1 deraadt 3493: EMPTY
3494:
3495: /*
3496: * Committed to running process p.
3497: * It may be the same as the one we were running before.
3498: */
3499: sethi %hi(_want_resched), %o0
3500: st %g0, [%o0 + %lo(_want_resched)] ! want_resched = 0;
3501: ld [%g3 + P_ADDR], %g5 ! newpcb = p->p_addr;
1.10 deraadt 3502: st %g0, [%g3 + 4] ! p->p_back = NULL;
1.1 deraadt 3503: ld [%g5 + PCB_PSR], %g2 ! newpsr = newpcb->pcb_psr;
3504: st %g3, [%g7 + %lo(_curproc)] ! curproc = p;
3505:
3506: cmp %g3, %g4 ! p == lastproc?
3507: be,a Lsw_sameproc ! yes, go return 0
3508: wr %g2, 0, %psr ! (after restoring ipl)
3509:
3510: /*
3511: * Not the old process. Save the old process, if any;
3512: * then load p.
3513: */
3514: tst %g4
3515: be,a Lsw_load ! if no old process, go load
3516: wr %g1, (PIL_CLOCK << 8) | PSR_ET, %psr
3517:
3518: INCR(_nswitchdiff) ! clobbers %o0,%o1
3519: /*
3520: * save: write back all windows (including the current one).
3521: * XXX crude; knows nwindows <= 8
3522: */
3523: #define SAVE save %sp, -64, %sp
1.29 deraadt 3524: wb1: SAVE; SAVE; SAVE; SAVE; SAVE; SAVE; SAVE /* 7 of each: */
1.1 deraadt 3525: restore; restore; restore; restore; restore; restore; restore
3526:
3527: /*
3528: * Load the new process. To load, we must change stacks and
3529: * alter cpcb and %wim, hence we must disable traps. %psr is
3530: * currently equal to oldpsr (%g1) ^ (PIL_CLOCK << 8);
3531: * this means that PSR_ET is on. Likewise, PSR_ET is on
3532: * in newpsr (%g2), although we do not know newpsr's ipl.
3533: *
3534: * We also must load up the `in' and `local' registers.
3535: */
3536: wr %g1, (PIL_CLOCK << 8) | PSR_ET, %psr
3537: Lsw_load:
3538: ! wr %g1, (PIL_CLOCK << 8) | PSR_ET, %psr ! done above
3539: /* compute new wim */
3540: ld [%g5 + PCB_WIM], %o0
3541: mov 1, %o1
3542: sll %o1, %o0, %o0
3543: wr %o0, 0, %wim ! %wim = 1 << newpcb->pcb_wim;
3544: /* now must not change %psr for 3 more instrs */
3545: /*1*/ set PSR_EF|PSR_EC, %o0
3546: /*2*/ andn %g2, %o0, %g2 ! newpsr &= ~(PSR_EF|PSR_EC);
3547: /*3*/ nop
3548: /* set new psr, but with traps disabled */
3549: wr %g2, PSR_ET, %psr ! %psr = newpsr ^ PSR_ET;
3550: /* set new cpcb */
3551: st %g5, [%g6 + %lo(_cpcb)] ! cpcb = newpcb;
3552: /* XXX update masterpaddr too */
3553: sethi %hi(_masterpaddr), %g7
3554: st %g5, [%g7 + %lo(_masterpaddr)]
3555: ldd [%g5 + PCB_SP], %o6 ! <sp,pc> = newpcb->pcb_<sp,pc>
3556: /* load window */
3557: ldd [%sp + (0*8)], %l0
3558: ldd [%sp + (1*8)], %l2
3559: ldd [%sp + (2*8)], %l4
3560: ldd [%sp + (3*8)], %l6
3561: ldd [%sp + (4*8)], %i0
3562: ldd [%sp + (5*8)], %i2
3563: ldd [%sp + (6*8)], %i4
3564: ldd [%sp + (7*8)], %i6
3565: #ifdef DEBUG
3566: mov %g5, %o0
3567: SET_SP_REDZONE(%o0, %o1)
3568: CHECK_SP_REDZONE(%o0, %o1)
3569: #endif
3570: /* finally, enable traps */
3571: wr %g2, 0, %psr ! psr = newpsr;
3572:
3573: /*
3574: * Now running p. Make sure it has a context so that it
3575: * can talk about user space stuff. (Its pcb_uw is currently
3576: * zero so it is safe to have interrupts going here.)
3577: */
3578: ld [%g3 + P_VMSPACE], %o3 ! vm = p->p_vmspace;
3579: ld [%o3 + VM_PMAP_CTX], %o0! if (vm->vm_pmap.pm_ctx != NULL)
3580: tst %o0
3581: bnz,a Lsw_havectx ! goto havecontext;
3582: ld [%o3 + VM_PMAP_CTXNUM], %o0
3583:
3584: /* p does not have a context: call ctx_alloc to get one */
3585: save %sp, -CCFSZ, %sp
3586: call _ctx_alloc ! ctx_alloc(&vm->vm_pmap);
3587: add %i3, VM_PMAP, %o0
3588: ret
3589: restore
3590:
3591: /* p does have a context: just switch to it */
3592: Lsw_havectx:
3593: ! ld [%o3 + VM_PMAP_CTXNUM], %o0 ! (done in delay slot)
1.9 deraadt 3594: #if (defined(SUN4) || defined(SUN4C)) && defined(SUN4M)
1.13 deraadt 3595: sethi %hi(_cputyp), %o1 ! what cpu are we running on?
1.15 pk 3596: ld [%o1 + %lo(_cputyp)], %o1
1.13 deraadt 3597: cmp %o1, CPU_SUN4M
1.9 deraadt 3598: bne 1f
3599: nop
3600: #endif
3601: #if defined(SUN4) || defined(SUN4C)
1.1 deraadt 3602: set AC_CONTEXT, %o1
3603: stba %o0, [%o1] ASI_CONTROL ! setcontext(vm->vm_pmap.pm_ctxnum);
3604: retl
3605: nop
1.9 deraadt 3606: #endif
3607: 1:
3608: #if defined(SUN4M)
3609: set SRMMU_CXR, %o1
3610: stba %o0, [%o1] ASI_SRMMU ! setcontext(vm->vm_pmap.pm_ctxnum);
3611: retl
3612: nop
3613: #endif
1.1 deraadt 3614:
3615: Lsw_sameproc:
3616: /*
3617: * We are resuming the process that was running at the
1.10 deraadt 3618: * call to switch(). Just set psr ipl and return.
1.1 deraadt 3619: */
3620: ! wr %g2, 0 %psr ! %psr = newpsr; (done earlier)
3621: nop
3622: retl
3623: nop
3624:
3625:
3626: /*
3627: * Snapshot the current process so that stack frames are up to date.
3628: * This is called from two places:
3629: * - just before a crash dump, for the stack update;
3630: * - in cpu_fork(), before copying the kernel stack.
3631: * In the latter case the pcb and stack will be copied to the child,
1.10 deraadt 3632: * and the child will be made runnable. Eventually switch() will run
1.1 deraadt 3633: * it. When it does, we want its pcb_pc set so that we can appear
3634: * to return 1 from cpu_fork(), so we store the current sp and psr
3635: * in the given pcb, and set its pcb_pc to our return-1 code (offset
3636: * by -8 due to call/ret conventions). This is not useful in the crash
3637: * dump code but it is easiest to do it anyway.
3638: */
3639: ENTRY(snapshot)
3640: st %o6, [%o0 + PCB_SP] ! save sp
3641: set 1f - 8, %o1 ! set child-return pc
3642: st %o1, [%o0 + PCB_PC]
3643: rd %psr, %o1 ! save psr
3644: st %o1, [%o0 + PCB_PSR]
3645:
3646: /*
1.10 deraadt 3647: * Just like switch(); same XXX comments apply.
1.1 deraadt 3648: * 7 of each. Minor tweak: the 7th restore is
3649: * done after a ret.
3650: */
1.29 deraadt 3651: wb2: SAVE; SAVE; SAVE; SAVE; SAVE; SAVE; SAVE
1.1 deraadt 3652: restore; restore; restore; restore; restore; restore; ret; restore
3653:
1.10 deraadt 3654: 1: /* this is reached only after a child gets chosen in switch() */
1.1 deraadt 3655: mov 1, %i0 ! return 1 from cpu_fork
3656: ret
3657: restore
3658:
3659: /*
3660: * {fu,su}{,i}{byte,word}
3661: */
3662: ALTENTRY(fuiword)
3663: ENTRY(fuword)
3664: set KERNBASE, %o2
3665: cmp %o0, %o2 ! if addr >= KERNBASE...
3666: bgeu Lfsbadaddr
3667: EMPTY
3668: btst 3, %o0 ! or has low bits set...
3669: bnz Lfsbadaddr ! go return -1
3670: EMPTY
3671: sethi %hi(_cpcb), %o2 ! cpcb->pcb_onfault = Lfserr;
3672: ld [%o2 + %lo(_cpcb)], %o2
3673: set Lfserr, %o3
3674: st %o3, [%o2 + PCB_ONFAULT]
3675: ld [%o0], %o0 ! fetch the word
3676: retl ! phew, made it, return the word
3677: st %g0, [%o2 + PCB_ONFAULT]! but first clear onfault
3678:
3679: Lfserr:
3680: st %g0, [%o2 + PCB_ONFAULT]! error in r/w, clear pcb_onfault
3681: Lfsbadaddr:
3682: retl ! and return error indicator
1.21 deraadt 3683: mov -1, %o0
1.1 deraadt 3684:
3685: /*
3686: * This is just like Lfserr, but it's a global label that allows
3687: * mem_access_fault() to check to see that we don't want to try to
3688: * page in the fault. It's used by fuswintr() etc.
3689: */
3690: .globl _Lfsbail
3691: _Lfsbail:
3692: st %g0, [%o2 + PCB_ONFAULT]! error in r/w, clear pcb_onfault
3693: retl ! and return error indicator
1.21 deraadt 3694: mov -1, %o0
1.1 deraadt 3695:
3696: /*
3697: * Like fusword but callable from interrupt context.
3698: * Fails if data isn't resident.
3699: */
3700: ENTRY(fuswintr)
3701: set KERNBASE, %o2
3702: cmp %o0, %o2 ! if addr >= KERNBASE
3703: bgeu Lfsbadaddr ! return error
3704: EMPTY
3705: sethi %hi(_cpcb), %o2 ! cpcb->pcb_onfault = _Lfsbail;
3706: ld [%o2 + %lo(_cpcb)], %o2
3707: set _Lfsbail, %o3
3708: st %o3, [%o2 + PCB_ONFAULT]
3709: lduh [%o0], %o0 ! fetch the halfword
3710: retl ! made it
3711: st %g0, [%o2 + PCB_ONFAULT]! but first clear onfault
3712:
3713: ENTRY(fusword)
3714: set KERNBASE, %o2
3715: cmp %o0, %o2 ! if addr >= KERNBASE
3716: bgeu Lfsbadaddr ! return error
3717: EMPTY
3718: sethi %hi(_cpcb), %o2 ! cpcb->pcb_onfault = Lfserr;
3719: ld [%o2 + %lo(_cpcb)], %o2
3720: set Lfserr, %o3
3721: st %o3, [%o2 + PCB_ONFAULT]
3722: lduh [%o0], %o0 ! fetch the halfword
3723: retl ! made it
3724: st %g0, [%o2 + PCB_ONFAULT]! but first clear onfault
3725:
3726: ALTENTRY(fuibyte)
3727: ENTRY(fubyte)
3728: set KERNBASE, %o2
3729: cmp %o0, %o2 ! if addr >= KERNBASE
3730: bgeu Lfsbadaddr ! return error
3731: EMPTY
3732: sethi %hi(_cpcb), %o2 ! cpcb->pcb_onfault = Lfserr;
3733: ld [%o2 + %lo(_cpcb)], %o2
3734: set Lfserr, %o3
3735: st %o3, [%o2 + PCB_ONFAULT]
3736: ldub [%o0], %o0 ! fetch the byte
3737: retl ! made it
3738: st %g0, [%o2 + PCB_ONFAULT]! but first clear onfault
3739:
3740: ALTENTRY(suiword)
3741: ENTRY(suword)
3742: set KERNBASE, %o2
3743: cmp %o0, %o2 ! if addr >= KERNBASE ...
3744: bgeu Lfsbadaddr
3745: EMPTY
3746: btst 3, %o0 ! or has low bits set ...
3747: bnz Lfsbadaddr ! go return error
3748: EMPTY
3749: sethi %hi(_cpcb), %o2 ! cpcb->pcb_onfault = Lfserr;
3750: ld [%o2 + %lo(_cpcb)], %o2
3751: set Lfserr, %o3
3752: st %o3, [%o2 + PCB_ONFAULT]
3753: st %o1, [%o0] ! store the word
3754: st %g0, [%o2 + PCB_ONFAULT]! made it, clear onfault
3755: retl ! and return 0
3756: clr %o0
3757:
3758: ENTRY(suswintr)
3759: set KERNBASE, %o2
3760: cmp %o0, %o2 ! if addr >= KERNBASE
3761: bgeu Lfsbadaddr ! go return error
3762: EMPTY
3763: sethi %hi(_cpcb), %o2 ! cpcb->pcb_onfault = _Lfsbail;
3764: ld [%o2 + %lo(_cpcb)], %o2
3765: set _Lfsbail, %o3
3766: st %o3, [%o2 + PCB_ONFAULT]
3767: sth %o1, [%o0] ! store the halfword
3768: st %g0, [%o2 + PCB_ONFAULT]! made it, clear onfault
3769: retl ! and return 0
3770: clr %o0
3771:
3772: ENTRY(susword)
3773: set KERNBASE, %o2
3774: cmp %o0, %o2 ! if addr >= KERNBASE
3775: bgeu Lfsbadaddr ! go return error
3776: EMPTY
3777: sethi %hi(_cpcb), %o2 ! cpcb->pcb_onfault = Lfserr;
3778: ld [%o2 + %lo(_cpcb)], %o2
3779: set Lfserr, %o3
3780: st %o3, [%o2 + PCB_ONFAULT]
3781: sth %o1, [%o0] ! store the halfword
3782: st %g0, [%o2 + PCB_ONFAULT]! made it, clear onfault
3783: retl ! and return 0
3784: clr %o0
3785:
3786: ALTENTRY(suibyte)
3787: ENTRY(subyte)
3788: set KERNBASE, %o2
3789: cmp %o0, %o2 ! if addr >= KERNBASE
3790: bgeu Lfsbadaddr ! go return error
3791: EMPTY
3792: sethi %hi(_cpcb), %o2 ! cpcb->pcb_onfault = Lfserr;
3793: ld [%o2 + %lo(_cpcb)], %o2
3794: set Lfserr, %o3
3795: st %o3, [%o2 + PCB_ONFAULT]
3796: stb %o1, [%o0] ! store the byte
3797: st %g0, [%o2 + PCB_ONFAULT]! made it, clear onfault
3798: retl ! and return 0
3799: clr %o0
3800:
3801: /* probeget and probeset are meant to be used during autoconfiguration */
3802:
3803: /*
3804: * probeget(addr, size) caddr_t addr; int size;
3805: *
3806: * Read or write a (byte,word,longword) from the given address.
3807: * Like {fu,su}{byte,halfword,word} but our caller is supposed
3808: * to know what he is doing... the address can be anywhere.
3809: *
3810: * We optimize for space, rather than time, here.
3811: */
3812: ENTRY(probeget)
3813: ! %o0 = addr, %o1 = (1,2,4)
3814: set KERNBASE, %o2
3815: cmp %o0, %o2 ! if addr < KERNBASE
3816: blu Lfsbadaddr ! go return error
3817: EMPTY
3818: sethi %hi(_cpcb), %o2
3819: ld [%o2 + %lo(_cpcb)], %o2 ! cpcb->pcb_onfault = Lfserr;
3820: set Lfserr, %o5
3821: st %o5, [%o2 + PCB_ONFAULT]
3822: btst 1, %o1
3823: bnz,a 0f ! if (len & 1)
3824: ldub [%o0], %o0 ! value = *(char *)addr;
3825: 0: btst 2, %o1
3826: bnz,a 0f ! if (len & 2)
3827: lduh [%o0], %o0 ! value = *(short *)addr;
3828: 0: btst 4, %o1
3829: bnz,a 0f ! if (len & 4)
3830: ld [%o0], %o0 ! value = *(int *)addr;
3831: 0: retl ! made it, clear onfault and return
3832: st %g0, [%o2 + PCB_ONFAULT]
3833:
3834: /*
3835: * probeset(addr, size, val) caddr_t addr; int size, val;
3836: *
3837: * As above, but we return 0 on success.
3838: */
3839: ENTRY(probeset)
3840: ! %o0 = addr, %o1 = (1,2,4), %o2 = val
1.35 ! pk 3841: set KERNBASE, %o3
! 3842: cmp %o0, %o3 ! if addr < KERNBASE
1.1 deraadt 3843: blu Lfsbadaddr ! go return error
3844: EMPTY
1.35 ! pk 3845: sethi %hi(_cpcb), %o3
! 3846: ld [%o3 + %lo(_cpcb)], %o3 ! cpcb->pcb_onfault = Lfserr;
1.1 deraadt 3847: set Lfserr, %o5
1.35 ! pk 3848: st %o5, [%o3 + PCB_ONFAULT]
1.1 deraadt 3849: btst 1, %o1
3850: bnz,a 0f ! if (len & 1)
3851: stb %o2, [%o0] ! *(char *)addr = value;
3852: 0: btst 2, %o1
3853: bnz,a 0f ! if (len & 2)
3854: sth %o2, [%o0] ! *(short *)addr = value;
3855: 0: btst 4, %o1
3856: bnz,a 0f ! if (len & 4)
3857: st %o2, [%o0] ! *(int *)addr = value;
3858: 0: clr %o0 ! made it, clear onfault and return 0
3859: retl
1.35 ! pk 3860: st %g0, [%o3 + PCB_ONFAULT]
1.21 deraadt 3861:
3862: /*
1.22 deraadt 3863: * int xldcontrolb(caddr_t, pcb)
3864: * %o0 %o1
1.21 deraadt 3865: *
3866: * read a byte from the specified address in ASI_CONTROL space.
3867: */
1.22 deraadt 3868: ENTRY(xldcontrolb)
3869: !sethi %hi(_cpcb), %o2
3870: !ld [%o2 + %lo(_cpcb)], %o2 ! cpcb->pcb_onfault = Lfsbail;
3871: or %o1, %g0, %o2 ! %o2 = %o1
1.21 deraadt 3872: set _Lfsbail, %o5
3873: st %o5, [%o2 + PCB_ONFAULT]
3874: lduba [%o0] ASI_CONTROL, %o0 ! read
3875: 0: retl
1.1 deraadt 3876: st %g0, [%o2 + PCB_ONFAULT]
3877:
3878: /*
3879: * Insert entry into doubly-linked queue.
3880: * We could just do this in C, but gcc does not do leaves well (yet).
3881: */
3882: ENTRY(_insque)
3883: ! %o0 = e = what to insert; %o1 = after = entry to insert after
3884: st %o1, [%o0 + 4] ! e->prev = after;
3885: ld [%o1], %o2 ! tmp = after->next;
3886: st %o2, [%o0] ! e->next = tmp;
3887: st %o0, [%o1] ! after->next = e;
3888: retl
3889: st %o0, [%o2 + 4] ! tmp->prev = e;
3890:
3891:
3892: /*
3893: * Remove entry from doubly-linked queue.
3894: */
3895: ENTRY(_remque)
3896: ! %o0 = e = what to remove
3897: ld [%o0], %o1 ! n = e->next;
3898: ld [%o0 + 4], %o2 ! p = e->prev;
3899: st %o2, [%o1 + 4] ! n->prev = p;
3900: retl
3901: st %o1, [%o2] ! p->next = n;
3902:
3903: /*
3904: * copywords(src, dst, nbytes)
3905: *
3906: * Copy `nbytes' bytes from src to dst, both of which are word-aligned;
3907: * nbytes is a multiple of four. It may, however, be zero, in which case
3908: * nothing is to be copied.
3909: */
3910: ENTRY(copywords)
3911: ! %o0 = src, %o1 = dst, %o2 = nbytes
3912: b 1f
3913: deccc 4, %o2
3914: 0:
3915: st %o3, [%o1 + %o2]
3916: deccc 4, %o2 ! while ((n -= 4) >= 0)
3917: 1:
3918: bge,a 0b ! *(int *)(dst+n) = *(int *)(src+n);
3919: ld [%o0 + %o2], %o3
3920: retl
3921: nop
3922:
3923: /*
3924: * qcopy(src, dst, nbytes)
3925: *
3926: * (q for `quad' or `quick', as opposed to b for byte/block copy)
3927: *
3928: * Just like copywords, but everything is multiples of 8.
3929: */
3930: ENTRY(qcopy)
3931: b 1f
3932: deccc 8, %o2
3933: 0:
3934: std %o4, [%o1 + %o2]
3935: deccc 8, %o2
3936: 1:
3937: bge,a 0b
3938: ldd [%o0 + %o2], %o4
3939: retl
3940: nop
3941:
3942: /*
3943: * qzero(addr, nbytes)
3944: *
3945: * Zeroes `nbytes' bytes of a quad-aligned virtual address,
3946: * where nbytes is itself a multiple of 8.
3947: */
3948: ENTRY(qzero)
3949: ! %o0 = addr, %o1 = len (in bytes)
3950: clr %g1
3951: 0:
3952: deccc 8, %o1 ! while ((n =- 8) >= 0)
3953: bge,a 0b
3954: std %g0, [%o0 + %o1] ! *(quad *)(addr + n) = 0;
3955: retl
3956: nop
3957:
3958: /*
3959: * bzero(addr, len)
3960: *
3961: * We should unroll the loop, but at the moment this would
3962: * gain nothing since the `std' instructions are what limits us.
3963: */
3964: ALTENTRY(blkclr)
3965: ENTRY(bzero)
3966: ! %o0 = addr, %o1 = len
3967:
3968: ! Optimize a common case: addr and len are both multiples of 8.
3969: or %o0, %o1, %o2
3970: btst 7, %o2 ! ((addr | len) & 7) != 0?
3971: bnz 1f ! if so, cannot optimize
3972: clr %g1 ! in any case, we want g1=0
3973:
3974: /* `Good' operands, can just store doubles. */
3975: 0:
3976: deccc 8, %o1 ! while ((len -= 8) >= 0)
3977: bge,a 0b
3978: std %g0, [%o0 + %o1] ! *(quad *)(addr + len) = 0;
3979: retl
3980: nop
3981:
3982: /*
3983: * Either the address is unaligned, or the count is not a
3984: * multiple of 8, or both. We will have to align the address
3985: * in order to use anything `better' than stb.
3986: */
3987: 1:
3988: cmp %o1, 15 ! len >= 15?
3989: bge,a Lstd ! yes, use std
3990: btst 1, %o0 ! (but first check alignment)
3991:
3992: ! not enough to bother: do byte-at-a-time loop.
3993: 2:
3994: deccc %o1 ! while (--len >= 0)
3995: bge,a 2b
3996: stb %g0, [%o0 + %o1] ! addr[len] = 0;
3997: retl
3998: nop
3999:
4000: Lstd:
4001: /*
4002: * There are at least 15 bytes to zero.
4003: * We may have to zero some initial stuff to align
4004: * the address.
4005: */
4006: bz,a 1f ! if (addr & 1) {
4007: btst 2, %o0
4008: stb %g0, [%o0] ! *addr = 0;
4009: inc %o0 ! addr++;
4010: dec %o1 ! len--;
4011: btst 2, %o0 ! }
4012: 1:
4013: bz,a 1f ! if (addr & 2) {
4014: btst 4, %o0
4015: sth %g0, [%o0] ! *(short *)addr = 0;
4016: inc 2, %o0 ! addr += 2;
4017: dec 2, %o1 ! len -= 2;
4018: btst 4, %o0 ! }
4019: 1:
4020: bz 1f ! if (addr & 4) {
4021: dec 8, %o1
4022: st %g0, [%o0] ! *(int *)addr = 0;
4023: inc 4, %o0 ! addr += 4;
4024: dec 4, %o1 ! len -= 4;
4025: ! }
4026: /*
4027: * Address is double word aligned; len is 8 less than
4028: * the number of bytes remaining (i.e., len is 0 if
4029: * the remaining count is 8, 1 if it is 9, etc.).
4030: */
4031: 1:
4032: std %g0, [%o0] ! do {
4033: 2: ! *(quad *)addr = 0;
4034: inc 8, %o0 ! addr += 8;
4035: deccc 8, %o1 ! } while ((len -= 8) >= 0);
4036: bge,a 2b
4037: std %g0, [%o0]
4038:
4039: /*
4040: * Len is in [-8..-1] where -8 => done, -7 => 1 byte to zero,
4041: * -6 => two bytes, etc. Mop up this remainder, if any.
4042: */
4043: btst 4, %o1
4044: bz 1f ! if (len & 4) {
4045: btst 2, %o1
4046: st %g0, [%o0] ! *(int *)addr = 0;
4047: inc 4, %o0 ! addr += 4;
4048: 1:
4049: bz 1f ! if (len & 2) {
4050: btst 1, %o1
4051: sth %g0, [%o0] ! *(short *)addr = 0;
4052: inc 2, %o0 ! addr += 2;
4053: 1:
4054: bnz,a 1f ! if (len & 1)
4055: stb %g0, [%o0] ! *addr = 0;
4056: 1:
4057: retl
4058: nop
4059:
4060: /*
4061: * kernel bcopy/memcpy
4062: * Assumes regions do not overlap; has no useful return value.
4063: *
4064: * Must not use %g7 (see copyin/copyout above).
4065: */
4066:
4067: #define BCOPY_SMALL 32 /* if < 32, copy by bytes */
4068:
4069: ENTRY(memcpy)
4070: /*
4071: * Swap args for bcopy. Gcc generates calls to memcpy for
4072: * structure assignments.
4073: */
4074: mov %o0, %o3
4075: mov %o1, %o0
4076: mov %o3, %o1
4077: ENTRY(bcopy)
4078: cmp %o2, BCOPY_SMALL
4079: Lbcopy_start:
4080: bge,a Lbcopy_fancy ! if >= this many, go be fancy.
4081: btst 7, %o0 ! (part of being fancy)
4082:
4083: /*
4084: * Not much to copy, just do it a byte at a time.
4085: */
4086: deccc %o2 ! while (--len >= 0)
4087: bl 1f
4088: EMPTY
4089: 0:
4090: inc %o0
4091: ldsb [%o0 - 1], %o4 ! (++dst)[-1] = *src++;
4092: stb %o4, [%o1]
4093: deccc %o2
4094: bge 0b
4095: inc %o1
4096: 1:
4097: retl
4098: nop
4099: /* NOTREACHED */
4100:
4101: /*
4102: * Plenty of data to copy, so try to do it optimally.
4103: */
4104: Lbcopy_fancy:
4105: ! check for common case first: everything lines up.
4106: ! btst 7, %o0 ! done already
4107: bne 1f
4108: EMPTY
4109: btst 7, %o1
4110: be,a Lbcopy_doubles
4111: dec 8, %o2 ! if all lined up, len -= 8, goto bcopy_doubes
4112:
4113: ! If the low bits match, we can make these line up.
4114: 1:
4115: xor %o0, %o1, %o3 ! t = src ^ dst;
4116: btst 1, %o3 ! if (t & 1) {
4117: be,a 1f
4118: btst 1, %o0 ! [delay slot: if (src & 1)]
4119:
4120: ! low bits do not match, must copy by bytes.
4121: 0:
4122: ldsb [%o0], %o4 ! do {
4123: inc %o0 ! (++dst)[-1] = *src++;
4124: inc %o1
4125: deccc %o2
4126: bnz 0b ! } while (--len != 0);
4127: stb %o4, [%o1 - 1]
4128: retl
4129: nop
4130: /* NOTREACHED */
4131:
4132: ! lowest bit matches, so we can copy by words, if nothing else
4133: 1:
4134: be,a 1f ! if (src & 1) {
4135: btst 2, %o3 ! [delay slot: if (t & 2)]
4136:
4137: ! although low bits match, both are 1: must copy 1 byte to align
4138: ldsb [%o0], %o4 ! *dst++ = *src++;
4139: stb %o4, [%o1]
4140: inc %o0
4141: inc %o1
4142: dec %o2 ! len--;
4143: btst 2, %o3 ! } [if (t & 2)]
4144: 1:
4145: be,a 1f ! if (t & 2) {
4146: btst 2, %o0 ! [delay slot: if (src & 2)]
4147: dec 2, %o2 ! len -= 2;
4148: 0:
4149: ldsh [%o0], %o4 ! do {
4150: sth %o4, [%o1] ! *(short *)dst = *(short *)src;
4151: inc 2, %o0 ! dst += 2, src += 2;
4152: deccc 2, %o2 ! } while ((len -= 2) >= 0);
4153: bge 0b
4154: inc 2, %o1
4155: b Lbcopy_mopb ! goto mop_up_byte;
4156: btst 1, %o2 ! } [delay slot: if (len & 1)]
4157: /* NOTREACHED */
4158:
4159: ! low two bits match, so we can copy by longwords
4160: 1:
4161: be,a 1f ! if (src & 2) {
4162: btst 4, %o3 ! [delay slot: if (t & 4)]
4163:
4164: ! although low 2 bits match, they are 10: must copy one short to align
4165: ldsh [%o0], %o4 ! (*short *)dst = *(short *)src;
4166: sth %o4, [%o1]
4167: inc 2, %o0 ! dst += 2;
4168: inc 2, %o1 ! src += 2;
4169: dec 2, %o2 ! len -= 2;
4170: btst 4, %o3 ! } [if (t & 4)]
4171: 1:
4172: be,a 1f ! if (t & 4) {
4173: btst 4, %o0 ! [delay slot: if (src & 4)]
4174: dec 4, %o2 ! len -= 4;
4175: 0:
4176: ld [%o0], %o4 ! do {
4177: st %o4, [%o1] ! *(int *)dst = *(int *)src;
4178: inc 4, %o0 ! dst += 4, src += 4;
4179: deccc 4, %o2 ! } while ((len -= 4) >= 0);
4180: bge 0b
4181: inc 4, %o1
4182: b Lbcopy_mopw ! goto mop_up_word_and_byte;
4183: btst 2, %o2 ! } [delay slot: if (len & 2)]
4184: /* NOTREACHED */
4185:
4186: ! low three bits match, so we can copy by doublewords
4187: 1:
4188: be 1f ! if (src & 4) {
4189: dec 8, %o2 ! [delay slot: len -= 8]
4190: ld [%o0], %o4 ! *(int *)dst = *(int *)src;
4191: st %o4, [%o1]
4192: inc 4, %o0 ! dst += 4, src += 4, len -= 4;
4193: inc 4, %o1
4194: dec 4, %o2 ! }
4195: 1:
4196: Lbcopy_doubles:
4197: ldd [%o0], %o4 ! do {
4198: std %o4, [%o1] ! *(double *)dst = *(double *)src;
4199: inc 8, %o0 ! dst += 8, src += 8;
4200: deccc 8, %o2 ! } while ((len -= 8) >= 0);
4201: bge Lbcopy_doubles
4202: inc 8, %o1
4203:
4204: ! check for a usual case again (save work)
4205: btst 7, %o2 ! if ((len & 7) == 0)
4206: be Lbcopy_done ! goto bcopy_done;
4207:
4208: btst 4, %o2 ! if ((len & 4)) == 0)
4209: be,a Lbcopy_mopw ! goto mop_up_word_and_byte;
4210: btst 2, %o2 ! [delay slot: if (len & 2)]
4211: ld [%o0], %o4 ! *(int *)dst = *(int *)src;
4212: st %o4, [%o1]
4213: inc 4, %o0 ! dst += 4;
4214: inc 4, %o1 ! src += 4;
4215: btst 2, %o2 ! } [if (len & 2)]
4216:
4217: 1:
4218: ! mop up trailing word (if present) and byte (if present).
4219: Lbcopy_mopw:
4220: be Lbcopy_mopb ! no word, go mop up byte
4221: btst 1, %o2 ! [delay slot: if (len & 1)]
4222: ldsh [%o0], %o4 ! *(short *)dst = *(short *)src;
4223: be Lbcopy_done ! if ((len & 1) == 0) goto done;
4224: sth %o4, [%o1]
4225: ldsb [%o0 + 2], %o4 ! dst[2] = src[2];
4226: retl
4227: stb %o4, [%o1 + 2]
4228: /* NOTREACHED */
4229:
4230: ! mop up trailing byte (if present).
4231: Lbcopy_mopb:
4232: bne,a 1f
4233: ldsb [%o0], %o4
4234:
4235: Lbcopy_done:
4236: retl
4237: nop
4238:
4239: 1:
4240: retl
4241: stb %o4,[%o1]
4242: /*
4243: * ovbcopy(src, dst, len): like bcopy, but regions may overlap.
4244: */
4245: ENTRY(ovbcopy)
4246: cmp %o0, %o1 ! src < dst?
4247: bgeu Lbcopy_start ! no, go copy forwards as via bcopy
4248: cmp %o2, BCOPY_SMALL! (check length for doublecopy first)
4249:
4250: /*
4251: * Since src comes before dst, and the regions might overlap,
4252: * we have to do the copy starting at the end and working backwards.
4253: */
4254: add %o2, %o0, %o0 ! src += len
4255: add %o2, %o1, %o1 ! dst += len
4256: bge,a Lback_fancy ! if len >= BCOPY_SMALL, go be fancy
4257: btst 3, %o0
4258:
4259: /*
4260: * Not much to copy, just do it a byte at a time.
4261: */
4262: deccc %o2 ! while (--len >= 0)
4263: bl 1f
4264: EMPTY
4265: 0:
4266: dec %o0 ! *--dst = *--src;
4267: ldsb [%o0], %o4
4268: dec %o1
4269: deccc %o2
4270: bge 0b
4271: stb %o4, [%o1]
4272: 1:
4273: retl
4274: nop
4275:
4276: /*
4277: * Plenty to copy, try to be optimal.
4278: * We only bother with word/halfword/byte copies here.
4279: */
4280: Lback_fancy:
4281: ! btst 3, %o0 ! done already
4282: bnz 1f ! if ((src & 3) == 0 &&
4283: btst 3, %o1 ! (dst & 3) == 0)
4284: bz,a Lback_words ! goto words;
4285: dec 4, %o2 ! (done early for word copy)
4286:
4287: 1:
4288: /*
4289: * See if the low bits match.
4290: */
4291: xor %o0, %o1, %o3 ! t = src ^ dst;
4292: btst 1, %o3
4293: bz,a 3f ! if (t & 1) == 0, can do better
4294: btst 1, %o0
4295:
4296: /*
4297: * Nope; gotta do byte copy.
4298: */
4299: 2:
4300: dec %o0 ! do {
4301: ldsb [%o0], %o4 ! *--dst = *--src;
4302: dec %o1
4303: deccc %o2 ! } while (--len != 0);
4304: bnz 2b
4305: stb %o4, [%o1]
4306: retl
4307: nop
4308:
4309: 3:
4310: /*
4311: * Can do halfword or word copy, but might have to copy 1 byte first.
4312: */
4313: ! btst 1, %o0 ! done earlier
4314: bz,a 4f ! if (src & 1) { /* copy 1 byte */
4315: btst 2, %o3 ! (done early)
4316: dec %o0 ! *--dst = *--src;
4317: ldsb [%o0], %o4
4318: dec %o1
4319: stb %o4, [%o1]
4320: dec %o2 ! len--;
4321: btst 2, %o3 ! }
4322:
4323: 4:
4324: /*
4325: * See if we can do a word copy ((t&2) == 0).
4326: */
4327: ! btst 2, %o3 ! done earlier
4328: bz,a 6f ! if (t & 2) == 0, can do word copy
4329: btst 2, %o0 ! (src&2, done early)
4330:
4331: /*
4332: * Gotta do halfword copy.
4333: */
4334: dec 2, %o2 ! len -= 2;
4335: 5:
4336: dec 2, %o0 ! do {
4337: ldsh [%o0], %o4 ! src -= 2;
4338: dec 2, %o1 ! dst -= 2;
4339: deccc 2, %o0 ! *(short *)dst = *(short *)src;
4340: bge 5b ! } while ((len -= 2) >= 0);
4341: sth %o4, [%o1]
4342: b Lback_mopb ! goto mop_up_byte;
4343: btst 1, %o2 ! (len&1, done early)
4344:
4345: 6:
4346: /*
4347: * We can do word copies, but we might have to copy
4348: * one halfword first.
4349: */
4350: ! btst 2, %o0 ! done already
4351: bz 7f ! if (src & 2) {
4352: dec 4, %o2 ! (len -= 4, done early)
4353: dec 2, %o0 ! src -= 2, dst -= 2;
4354: ldsh [%o0], %o4 ! *(short *)dst = *(short *)src;
4355: dec 2, %o1
4356: sth %o4, [%o1]
4357: dec 2, %o2 ! len -= 2;
4358: ! }
4359:
4360: 7:
4361: Lback_words:
4362: /*
4363: * Do word copies (backwards), then mop up trailing halfword
4364: * and byte if any.
4365: */
4366: ! dec 4, %o2 ! len -= 4, done already
4367: 0: ! do {
4368: dec 4, %o0 ! src -= 4;
4369: dec 4, %o1 ! src -= 4;
4370: ld [%o0], %o4 ! *(int *)dst = *(int *)src;
4371: deccc 4, %o2 ! } while ((len -= 4) >= 0);
4372: bge 0b
4373: st %o4, [%o1]
4374:
4375: /*
4376: * Check for trailing shortword.
4377: */
4378: btst 2, %o2 ! if (len & 2) {
4379: bz,a 1f
4380: btst 1, %o2 ! (len&1, done early)
4381: dec 2, %o0 ! src -= 2, dst -= 2;
4382: ldsh [%o0], %o4 ! *(short *)dst = *(short *)src;
4383: dec 2, %o1
4384: sth %o4, [%o1] ! }
4385: btst 1, %o2
4386:
4387: /*
4388: * Check for trailing byte.
4389: */
4390: 1:
4391: Lback_mopb:
4392: ! btst 1, %o2 ! (done already)
4393: bnz,a 1f ! if (len & 1) {
4394: ldsb [%o0 - 1], %o4 ! b = src[-1];
4395: retl
4396: nop
4397: 1:
4398: retl ! dst[-1] = b;
4399: stb %o4, [%o1 - 1] ! }
4400:
4401:
4402: /*
4403: * savefpstate(f) struct fpstate *f;
4404: *
4405: * Store the current FPU state. The first `st %fsr' may cause a trap;
4406: * our trap handler knows how to recover (by `returning' to savefpcont).
4407: */
4408: ENTRY(savefpstate)
4409: rd %psr, %o1 ! enable FP before we begin
4410: set PSR_EF, %o2
4411: or %o1, %o2, %o1
4412: wr %o1, 0, %psr
4413: /* do some setup work while we wait for PSR_EF to turn on */
4414: set FSR_QNE, %o5 ! QNE = 0x2000, too big for immediate
4415: clr %o3 ! qsize = 0;
4416: nop ! (still waiting for PSR_EF)
4417: special_fp_store:
4418: st %fsr, [%o0 + FS_FSR] ! f->fs_fsr = getfsr();
4419: /*
4420: * Even if the preceding instruction did not trap, the queue
4421: * is not necessarily empty: this state save might be happening
4422: * because user code tried to store %fsr and took the FPU
4423: * from `exception pending' mode to `exception' mode.
4424: * So we still have to check the blasted QNE bit.
4425: * With any luck it will usually not be set.
4426: */
4427: ld [%o0 + FS_FSR], %o4 ! if (f->fs_fsr & QNE)
4428: btst %o5, %o4
4429: bnz Lfp_storeq ! goto storeq;
4430: std %f0, [%o0 + FS_REGS + (4*0)] ! f->fs_f0 = etc;
4431: Lfp_finish:
4432: st %o3, [%o0 + FS_QSIZE] ! f->fs_qsize = qsize;
4433: std %f2, [%o0 + FS_REGS + (4*2)]
4434: std %f4, [%o0 + FS_REGS + (4*4)]
4435: std %f6, [%o0 + FS_REGS + (4*6)]
4436: std %f8, [%o0 + FS_REGS + (4*8)]
4437: std %f10, [%o0 + FS_REGS + (4*10)]
4438: std %f12, [%o0 + FS_REGS + (4*12)]
4439: std %f14, [%o0 + FS_REGS + (4*14)]
4440: std %f16, [%o0 + FS_REGS + (4*16)]
4441: std %f18, [%o0 + FS_REGS + (4*18)]
4442: std %f20, [%o0 + FS_REGS + (4*20)]
4443: std %f22, [%o0 + FS_REGS + (4*22)]
4444: std %f24, [%o0 + FS_REGS + (4*24)]
4445: std %f26, [%o0 + FS_REGS + (4*26)]
4446: std %f28, [%o0 + FS_REGS + (4*28)]
4447: retl
4448: std %f30, [%o0 + FS_REGS + (4*30)]
4449:
4450: /*
4451: * Store the (now known nonempty) FP queue.
4452: * We have to reread the fsr each time in order to get the new QNE bit.
4453: */
4454: Lfp_storeq:
4455: add %o0, FS_QUEUE, %o1 ! q = &f->fs_queue[0];
4456: 1:
4457: std %fq, [%o1 + %o3] ! q[qsize++] = fsr_qfront();
4458: st %fsr, [%o0 + FS_FSR] ! reread fsr
4459: ld [%o0 + FS_FSR], %o4 ! if fsr & QNE, loop
4460: btst %o5, %o4
4461: bnz 1b
4462: inc 8, %o3
4463: b Lfp_finish ! set qsize and finish storing fregs
4464: srl %o3, 3, %o3 ! (but first fix qsize)
4465:
4466: /*
4467: * The fsr store trapped. Do it again; this time it will not trap.
4468: * We could just have the trap handler return to the `st %fsr', but
4469: * if for some reason it *does* trap, that would lock us into a tight
4470: * loop. This way we panic instead. Whoopee.
4471: */
4472: savefpcont:
4473: b special_fp_store + 4 ! continue
4474: st %fsr, [%o0 + FS_FSR] ! but first finish the %fsr store
4475:
4476: /*
4477: * Load FPU state.
4478: */
4479: ENTRY(loadfpstate)
4480: rd %psr, %o1 ! enable FP before we begin
4481: set PSR_EF, %o2
4482: or %o1, %o2, %o1
4483: wr %o1, 0, %psr
4484: nop; nop; nop ! paranoia
4485: ldd [%o0 + FS_REGS + (4*0)], %f0
4486: ldd [%o0 + FS_REGS + (4*2)], %f2
4487: ldd [%o0 + FS_REGS + (4*4)], %f4
4488: ldd [%o0 + FS_REGS + (4*6)], %f6
4489: ldd [%o0 + FS_REGS + (4*8)], %f8
4490: ldd [%o0 + FS_REGS + (4*10)], %f10
4491: ldd [%o0 + FS_REGS + (4*12)], %f12
4492: ldd [%o0 + FS_REGS + (4*14)], %f14
4493: ldd [%o0 + FS_REGS + (4*16)], %f16
4494: ldd [%o0 + FS_REGS + (4*18)], %f18
4495: ldd [%o0 + FS_REGS + (4*20)], %f20
4496: ldd [%o0 + FS_REGS + (4*22)], %f22
4497: ldd [%o0 + FS_REGS + (4*24)], %f24
4498: ldd [%o0 + FS_REGS + (4*26)], %f26
4499: ldd [%o0 + FS_REGS + (4*28)], %f28
4500: ldd [%o0 + FS_REGS + (4*30)], %f30
4501: retl
4502: ld [%o0 + FS_FSR], %fsr ! setfsr(f->fs_fsr);
4503:
4504: /*
4505: * ienab_bis(bis) int bis;
4506: * ienab_bic(bic) int bic;
4507: *
4508: * Set and clear bits in the interrupt register.
4509: * Since there are no read-modify-write instructions for this,
4510: * and one of the interrupts is nonmaskable, we must disable traps.
4511: */
4512: ENTRY(ienab_bis)
4513: ! %o0 = bits to set
4514: rd %psr, %o2
4515: wr %o2, PSR_ET, %psr ! disable traps
4516: nop; nop ! 3-instr delay until ET turns off
4517: sethi %hi(IE_reg_addr), %o3
4518: ldub [%o3 + %lo(IE_reg_addr)], %o4
4519: or %o4, %o0, %o4 ! *IE_reg_addr |= bis;
4520: stb %o4, [%o3 + %lo(IE_reg_addr)]
4521: wr %o2, 0, %psr ! reenable traps
4522: nop
4523: retl
4524: nop
4525:
4526: ENTRY(ienab_bic)
4527: ! %o0 = bits to clear
4528: rd %psr, %o2
4529: wr %o2, PSR_ET, %psr ! disable traps
4530: nop; nop
4531: sethi %hi(IE_reg_addr), %o3
4532: ldub [%o3 + %lo(IE_reg_addr)], %o4
4533: andn %o4, %o0, %o4 ! *IE_reg_addr &=~ bic;
4534: stb %o4, [%o3 + %lo(IE_reg_addr)]
4535: wr %o2, 0, %psr ! reenable traps
4536: nop
4537: retl
4538: nop
4539:
4540: /*
4541: * ffs(), using table lookup.
4542: * The process switch code shares the table, so we just put the
4543: * whole thing here.
4544: */
4545: ffstab:
4546: .byte -24,1,2,1,3,1,2,1,4,1,2,1,3,1,2,1 /* 00-0f */
4547: .byte 5,1,2,1,3,1,2,1,4,1,2,1,3,1,2,1 /* 10-1f */
4548: .byte 6,1,2,1,3,1,2,1,4,1,2,1,3,1,2,1 /* 20-2f */
4549: .byte 5,1,2,1,3,1,2,1,4,1,2,1,3,1,2,1 /* 30-3f */
4550: .byte 7,1,2,1,3,1,2,1,4,1,2,1,3,1,2,1 /* 40-4f */
4551: .byte 5,1,2,1,3,1,2,1,4,1,2,1,3,1,2,1 /* 50-5f */
4552: .byte 6,1,2,1,3,1,2,1,4,1,2,1,3,1,2,1 /* 60-6f */
4553: .byte 5,1,2,1,3,1,2,1,4,1,2,1,3,1,2,1 /* 70-7f */
4554: .byte 8,1,2,1,3,1,2,1,4,1,2,1,3,1,2,1 /* 80-8f */
4555: .byte 5,1,2,1,3,1,2,1,4,1,2,1,3,1,2,1 /* 10-9f */
4556: .byte 6,1,2,1,3,1,2,1,4,1,2,1,3,1,2,1 /* a0-af */
4557: .byte 5,1,2,1,3,1,2,1,4,1,2,1,3,1,2,1 /* b0-bf */
4558: .byte 7,1,2,1,3,1,2,1,4,1,2,1,3,1,2,1 /* c0-cf */
4559: .byte 5,1,2,1,3,1,2,1,4,1,2,1,3,1,2,1 /* d0-df */
4560: .byte 6,1,2,1,3,1,2,1,4,1,2,1,3,1,2,1 /* e0-ef */
4561: .byte 5,1,2,1,3,1,2,1,4,1,2,1,3,1,2,1 /* f0-ff */
4562:
4563: /*
4564: * We use a table lookup on each byte.
4565: *
4566: * In each section below, %o1 is the current byte (0, 1, 2, or 3).
4567: * The last byte is handled specially: for the first three,
4568: * if that byte is nonzero, we return the table value
4569: * (plus 0, 8, or 16 for the byte number), but for the last
4570: * one, we just return the table value plus 24. This means
4571: * that ffstab[0] must be -24 so that ffs(0) will return 0.
4572: */
4573: ENTRY(ffs)
4574: set ffstab, %o2
4575: andcc %o0, 0xff, %o1 ! get low byte
4576: bz,a 1f ! try again if 0
4577: srl %o0, 8, %o0 ! delay slot, get ready for next byte
4578:
4579: retl ! return ffstab[%o1]
4580: ldsb [%o2 + %o1], %o0
4581:
4582: 1:
4583: andcc %o0, 0xff, %o1 ! byte 1 like byte 0...
4584: bz,a 2f
4585: srl %o0, 8, %o0 ! (use delay to prepare for byte 2)
4586:
4587: ldsb [%o2 + %o1], %o0
4588: retl ! return ffstab[%o1] + 8
4589: add %o0, 8, %o0
4590:
4591: 2:
4592: andcc %o0, 0xff, %o1
4593: bz,a 3f
4594: srl %o0, 8, %o0 ! (prepare for byte 3)
4595:
4596: ldsb [%o2 + %o1], %o0
4597: retl ! return ffstab[%o1] + 16
4598: add %o0, 16, %o0
4599:
4600: 3: ! just return ffstab[%o0] + 24
4601: ldsb [%o2 + %o0], %o0
4602: retl
4603: add %o0, 24, %o0
4604:
4605: /*
4606: * Here is a very good random number generator. This implementation is
4607: * based on ``Two Fast Implementations of the "Minimal Standard" Random
4608: * Number Generator", David G. Carta, Communications of the ACM, Jan 1990,
4609: * Vol 33 No 1.
4610: */
4611: .data
4612: randseed:
4613: .word 1
4614: .text
4615: ENTRY(random)
4616: sethi %hi(16807), %o1
4617: wr %o1, %lo(16807), %y
4618: sethi %hi(randseed), %g1
4619: ld [%g1 + %lo(randseed)], %o0
4620: andcc %g0, 0, %o2
4621: mulscc %o2, %o0, %o2
4622: mulscc %o2, %o0, %o2
4623: mulscc %o2, %o0, %o2
4624: mulscc %o2, %o0, %o2
4625: mulscc %o2, %o0, %o2
4626: mulscc %o2, %o0, %o2
4627: mulscc %o2, %o0, %o2
4628: mulscc %o2, %o0, %o2
4629: mulscc %o2, %o0, %o2
4630: mulscc %o2, %o0, %o2
4631: mulscc %o2, %o0, %o2
4632: mulscc %o2, %o0, %o2
4633: mulscc %o2, %o0, %o2
4634: mulscc %o2, %o0, %o2
4635: mulscc %o2, %o0, %o2
4636: mulscc %o2, %g0, %o2
4637: rd %y, %o3
4638: srl %o2, 16, %o1
4639: set 0xffff, %o4
4640: and %o4, %o2, %o0
4641: sll %o0, 15, %o0
4642: srl %o3, 17, %o3
4643: or %o3, %o0, %o0
4644: addcc %o0, %o1, %o0
4645: bneg 1f
4646: sethi %hi(0x7fffffff), %o1
4647: retl
4648: st %o0, [%g1 + %lo(randseed)]
4649: 1:
4650: or %o1, %lo(0x7fffffff), %o1
4651: add %o0, 1, %o0
4652: and %o1, %o0, %o0
4653: retl
4654: st %o0, [%g1 + %lo(randseed)]
4655:
4656: /*
1.29 deraadt 4657: * void lo_microtime(struct timeval *tv)
1.1 deraadt 4658: *
4659: * LBL's sparc bsd 'microtime': We don't need to spl (so this routine
4660: * can be a leaf routine) and we don't keep a 'last' timeval (there
4661: * can't be two calls to this routine in a microsecond). This seems to
4662: * be about 20 times faster than the Sun code on an SS-2. - vj
4663: *
4664: * Read time values from slowest-changing to fastest-changing,
4665: * then re-read out to slowest. If the values read before
4666: * the innermost match those read after, the innermost value
4667: * is consistent with the outer values. If not, it may not
4668: * be and we must retry. Typically this loop runs only once;
4669: * occasionally it runs twice, and only rarely does it run longer.
4670: */
1.30 deraadt 4671: #if defined(SUN4)
1.29 deraadt 4672: ENTRY(lo_microtime)
1.30 deraadt 4673: #else
4674: ENTRY(microtime)
4675: #endif
1.1 deraadt 4676: sethi %hi(_time), %g2
4677: sethi %hi(TIMERREG_VA), %g3
4678: 1:
4679: ldd [%g2+%lo(_time)], %o2 ! time.tv_sec & time.tv_usec
4680: ld [%g3+%lo(TIMERREG_VA)], %o4 ! usec counter
4681: ldd [%g2+%lo(_time)], %g4 ! see if time values changed
4682: cmp %g4, %o2
4683: bne 1b ! if time.tv_sec changed
4684: cmp %g5, %o3
4685: bne 1b ! if time.tv_usec changed
4686: tst %o4
4687:
4688: bpos 2f ! reached limit?
4689: srl %o4, TMR_SHIFT, %o4 ! convert counter to usec
4690: sethi %hi(_tick), %g4 ! bump usec by 1 tick
4691: ld [%g4+%lo(_tick)], %o1
4692: set TMR_MASK, %g5
4693: add %o1, %o3, %o3
4694: and %o4, %g5, %o4
4695: 2:
4696: add %o4, %o3, %o3
4697: set 1000000, %g5 ! normalize usec value
4698: cmp %o3, %g5
4699: bl,a 3f
4700: st %o2, [%o0] ! (should be able to std here)
4701: add %o2, 1, %o2 ! overflow
4702: sub %o3, %g5, %o3
4703: st %o2, [%o0] ! (should be able to std here)
4704: 3:
4705: retl
4706: st %o3, [%o0+4]
4707:
4708: /*
4709: * This procedure exists to make stdarg functions work correctly.
4710: * We write the caller's `in' registers into his caller's `arg dump'
4711: * area. That arg-dump area immediately precedes the argument extension
4712: * area, resulting in a single contiguous block of memory.
4713: *
4714: * This is really the wrong way to do it: the arguments should be written
4715: * to storage local to the stdarg function, and the stdarg `pick up
4716: * the next argument' code should pick it up from whichever region is
4717: * `active' at that point.
4718: */
4719: .globl ___builtin_saveregs
4720: ___builtin_saveregs:
4721: ! not profiled -- this should be done inline anyway
4722: ! bleah! the arg dump area is unaligned! cannot std w/o reg/reg moves
4723: st %i0, [%fp + 0x44] ! fr->fr_argd[0]
4724: st %i1, [%fp + 0x48] ! fr->fr_argd[1]
4725: st %i2, [%fp + 0x4c] ! fr->fr_argd[2]
4726: st %i3, [%fp + 0x50] ! fr->fr_argd[3]
4727: st %i4, [%fp + 0x54] ! fr->fr_argd[4]
4728: retl
4729: st %i5, [%fp + 0x58] ! fr->fr_argd[5]
4730:
1.8 pk 4731: #if defined(KGDB) || defined(DDB)
1.1 deraadt 4732: /*
4733: * Write all windows (user or otherwise), except the current one.
4734: *
4735: * THIS COULD BE DONE IN USER CODE
4736: */
4737: ENTRY(write_all_windows)
4738: /*
4739: * g2 = g1 = nwindows - 1;
4740: * while (--g1 > 0) save();
4741: * while (--g2 > 0) restore();
4742: */
4743: sethi %hi(_nwindows), %g1
4744: ld [%g1 + %lo(_nwindows)], %g1
4745: dec %g1
4746: mov %g1, %g2
4747:
4748: 1: deccc %g1
4749: bg,a 1b
4750: save %sp, -64, %sp
4751:
4752: 2: deccc %g2
4753: bg,a 2b
4754: restore
4755:
4756: retl
4757: nop
4758: #endif /* KGDB */
4759:
1.8 pk 4760: ENTRY(setjmp)
4761: std %sp, [%o0+0] ! stack pointer & return pc
4762: st %fp, [%o0+8] ! frame pointer
4763: retl
4764: clr %o0
4765:
4766: Lpanic_ljmp:
4767: .asciz "longjmp botch"
4768: ALIGN
4769:
4770: ENTRY(longjmp)
4771: addcc %o1, %g0, %g6 ! compute v ? v : 1 in a global register
4772: be,a 0f
4773: mov 1, %g6
4774: 0:
4775: mov %o0, %g1 ! save a in another global register
4776: ld [%g1+8], %g7 /* get caller's frame */
4777: 1:
4778: cmp %fp, %g7 ! compare against desired frame
4779: bl,a 1b ! if below,
4780: restore ! pop frame and loop
4781: be,a 2f ! if there,
4782: ldd [%g1+0], %o2 ! fetch return %sp and pc, and get out
4783:
4784: Llongjmpbotch:
4785: ! otherwise, went too far; bomb out
4786: save %sp, -CCFSZ, %sp /* preserve current window */
4787: sethi %hi(Lpanic_ljmp), %o0
4788: call _panic
4789: or %o0, %lo(Lpanic_ljmp), %o0;
4790: unimp 0
4791:
4792: 2:
4793: cmp %o2, %sp ! %sp must not decrease
4794: bge,a 3f
4795: mov %o2, %sp ! it is OK, put it in place
4796: b,a Llongjmpbotch
4797: 3:
4798: jmp %o3 + 8 ! success, return %g6
4799: mov %g6, %o0
4800:
1.1 deraadt 4801: .data
1.8 pk 4802: #ifdef DDB
4803: .globl _esym
4804: _esym:
4805: .word 0
4806: #endif
1.1 deraadt 4807: .globl _cold
4808: _cold:
4809: .word 1 ! cold start flag
4810:
4811: .globl _proc0paddr
4812: _proc0paddr:
4813: .word _u0 ! KVA of proc0 uarea
4814:
4815: /* interrupt counters XXX THESE BELONG ELSEWHERE (if anywhere) */
4816: .globl _intrcnt, _eintrcnt, _intrnames, _eintrnames
4817: _intrnames:
4818: .asciz "spur"
4819: .asciz "lev1"
4820: .asciz "lev2"
4821: .asciz "lev3"
4822: .asciz "lev4"
4823: .asciz "lev5"
4824: .asciz "lev6"
4825: .asciz "lev7"
4826: .asciz "lev8"
4827: .asciz "lev9"
4828: .asciz "clock"
4829: .asciz "lev11"
4830: .asciz "lev12"
4831: .asciz "lev13"
4832: .asciz "prof"
4833: _eintrnames:
4834: ALIGN
4835: _intrcnt:
4836: .skip 4*15
4837: _eintrcnt:
4838:
4839: .comm _nwindows, 4
4840: .comm _promvec, 4
4841: .comm _curproc, 4
4842: .comm _qs, 32 * 8
4843: .comm _whichqs, 4
CVSweb <webmaster@jp.NetBSD.org>