fixed -P bug, multiple -[PF] bug, and first line after EOF bug
[unix-history] / usr / src / sys / tahoe / tahoe / locore.s
CommitLineData
bd08bc0f 1/* locore.s 1.25 88/05/06 */
57a0bdb5
SL
2
3#include "../tahoe/mtpr.h"
4#include "../tahoe/trap.h"
5#include "../tahoe/psl.h"
6#include "../tahoe/pte.h"
7#include "../tahoe/cp.h"
8#include "../tahoe/mem.h"
a55e280b
SL
9#include "../tahoe/SYS.h"
10#include "../tahoemath/fp.h"
57a0bdb5 11
a55e280b
SL
12#include "errno.h"
13#include "syscall.h"
14#include "cmap.h"
57a0bdb5 15
56ad8000
SL
16 .set HIGH,0x1f # mask for total disable
17 .set NISP,3 # number of interrupt stack pages
18 .set SYSTEM,0xC0000000 # virtual address of system start
19 .set PPAGES,0x100000 # possible pages in P0,P1, etc.
57a0bdb5
SL
20
21/* ACBL for non-negative '_add' */
22#define ACBL(_limit,_add,_index,_displ) \
23 addl2 _add,_index; \
24 cmpl _index,_limit; \
25 bleq _displ
26
27/* _ACBL for negative '_add' */
28#define _ACBL(_limit,_add,_index,_displ) \
29 addl2 _add,_index; \
30 cmpl _index,_limit; \
31 bgeq _displ
32
a55e280b 33#define MOVC3(_srcaddr,_dstaddr,_len) \
57a0bdb5
SL
34 movl _srcaddr,r0; \
35 movl _dstaddr,r1; \
36 movl _len,r2; \
37 movblk
38
a55e280b 39/* keep address of psl if coming from user mode */
57a0bdb5
SL
40#define CHECK_SFE(_delta) \
41 bitl $PSL_CURMOD,_delta(sp); \
42 jeql 1f; \
43 moval _delta(sp),_user_psl; \
441:
45
46/*
47 * User structure is UPAGES at top of user space.
48 */
49 .globl _u
50 .set _u,SYSTEM - UPAGES*NBPG
51
52/*
53 * Restart stack. Used on power recovery or panic.
54 * Takes a core-dump and then halts.
55 */
56 .globl _rsstk
57a0bdb5 57 .globl pwfl_stk
a55e280b
SL
58_rsstk:
59 .space 1024-8
60pwfl_stk:
61 .space 4
62dumpflag:
63 .space 4
57a0bdb5
SL
64
65 .globl _intstack
66_intstack:
67 .space NISP*NBPG
68eintstack:
69
a55e280b
SL
70/*
71 * Power failure storage block and
72 * macros for saving and restoring.
73 */
74#define POWERFAIL(id,longs) \
75 .globl pwfl_/**/id \
76pwfl_/**/id: .space longs*4
57a0bdb5 77 .data
a55e280b
SL
78 POWERFAIL(r0, 14) # r0-r13
79 POWERFAIL(sp, 1) # r14
80 POWERFAIL(SCBB, 1) # system control block base
81 POWERFAIL(SBR, 1) # system pte base
82 POWERFAIL(SLR, 1) # system pte length
83 POWERFAIL(P0BR, 1) # p0 pte base
84 POWERFAIL(P0LR, 1) # p0 pte length
85 POWERFAIL(P1BR, 1) # p1 pte base
86 POWERFAIL(P1LR, 1) # p1 pte length
87 POWERFAIL(P2BR, 1) # p2 pte base
88 POWERFAIL(P2LR, 1) # p2 pte length
89 POWERFAIL(IPL, 1) # interrupt priority level
90 POWERFAIL(DCK, 1) # data cache key
91 POWERFAIL(CCK, 1) # code cache key
92 POWERFAIL(PCBB, 1) # process control block base
93 POWERFAIL(ISP, 1) # interrupt stack pointer
94 POWERFAIL(KSP, 1) # kernel mode stack pointer
95 POWERFAIL(USP, 1) # user mode stack pointer
96 POWERFAIL(MME, 1) # memory management enable
97 POWERFAIL(PSL, 1) # processor status longword
98
99/*
100 * Save current state in power fail storage block.
101 */
102#define SAVEpwfl() \
103 movpsl pwfl_PSL # Keeps all flags, etc. \
104 storer $0x3fff,pwfl_r0 # Saves r0-r13 \
105 moval 0(sp),pwfl_sp # Saves sp (=r14) \
106 mfpr $SBR,pwfl_SBR # Save all re_loadable registers \
107 mfpr $SLR,pwfl_SLR \
108 mfpr $P0BR,pwfl_P0BR \
109 mfpr $P0LR,pwfl_P0LR \
110 mfpr $P1BR,pwfl_P1BR \
111 mfpr $P1LR,pwfl_P1LR \
112 mfpr $P2BR,pwfl_P2BR \
113 mfpr $P2LR,pwfl_P2LR \
114 mfpr $IPL,pwfl_IPL \
115 mfpr $MME,pwfl_MME \
116 mfpr $DCK,pwfl_DCK \
117 mfpr $CCK,pwfl_CCK \
118 mfpr $PCBB,pwfl_PCBB \
119 mfpr $ISP,pwfl_ISP \
120 mfpr $SCBB,pwfl_SCBB \
121 mfpr $KSP,pwfl_KSP \
122 mfpr $USP,pwfl_USP
123
124/*
125 * Restore state saved in power fail block and
126 * jmp to location specified after (possibly)
127 * enabling memory management.
128 */
129#define RESTOREpwfl(loc) \
130 loadr $0x3fff,pwfl_r0 # Restore r0-r13 \
131 movl pwfl_sp,sp # Restore sp (=r14) \
132 mtpr pwfl_SCBB,$SCBB \
133 mtpr pwfl_SBR,$SBR # Restore all re_loadable registers \
134 mtpr pwfl_SLR,$SLR \
135 mtpr pwfl_P0BR,$P0BR \
136 mtpr pwfl_P0LR,$P0LR \
137 mtpr pwfl_P1BR,$P1BR \
138 mtpr pwfl_P1LR,$P1LR \
139 mtpr pwfl_P2BR,$P2BR \
140 mtpr pwfl_P2LR,$P2LR \
141 mtpr pwfl_IPL,$IPL \
142 mtpr pwfl_DCK,$DCK \
143 mtpr pwfl_CCK,$CCK \
144 mtpr pwfl_PCBB,$PCBB \
145 mtpr pwfl_ISP,$ISP \
146 mtpr pwfl_KSP,$KSP \
147 mtpr pwfl_USP,$USP \
148\
149 bicpsw $0xff # Restore PSW. \
150 bispsw pwfl_PSL+2 # Set original bits back (just in case..) \
151# now go to mapped mode \
152# Have to change PC to system addresses \
153 mtpr $1,$PACC # Thoroughly clean up caches. \
154 mtpr $1,$PADC \
155 mtpr $1,$TBIA \
156 mtpr pwfl_MME,$MME # Restore MME. Last thing to be done. \
157 jmp loc
57a0bdb5
SL
158
159/*
160 * Do a dump.
161 * Called by auto-restart.
162 * May be called manually.
163 */
164 .align 2
165 .text
166 .globl _Xdoadump
167 .globl _doadump
a55e280b
SL
168_Xdoadump: # CP comes here after power fail
169 RESTOREpwfl(*0f) # restore state
57a0bdb5
SL
170_doadump:
171 .word 0
a55e280b
SL
1720: mtpr $HIGH,$IPL
173#define _rsstkmap _Sysmap+12 # powerfail storage, scb, rsstk, int stack
57a0bdb5
SL
174 tstl dumpflag # dump only once!
175 bneq 1f
04d1fc31
MK
176 andl2 $~PG_PROT,_rsstkmap
177 orl2 $PG_KW,_rsstkmap # Make dump stack r/w
57a0bdb5 178 mtpr $0,$TBIA
04d1fc31 179 movl $1,dumpflag
57a0bdb5
SL
180 movab dumpflag,sp
181 callf $4,_dumpsys
1821:
183 halt
184
185/*
186 * Interrupt vector routines
187 */
188 .globl _waittime
57a0bdb5
SL
189#define SCBVEC(name) \
190 .align 2; \
191 .globl _X/**/name; \
192_X/**/name
a55e280b
SL
193#define PANIC(msg) \
194 clrl _waittime; pushab 1f; callf $8,_panic; 1: .asciz msg
195#define PRINTF(n,msg) \
196 pushab 1f; callf $(n+2)*4,_printf; MSG(msg)
197#define MSG(msg) .data; 1: .asciz msg; .text
198/*
07f28727 199 * r0-r5 are saved across all faults and interrupts.
56ad8000 200 * Routines below and those hidden in vbglue.s (device
a55e280b
SL
201 * interrupts) invoke the PUSHR/POPR macros to execute
202 * this. Also, certain stack frame offset calculations
07f28727 203 * use this, using the REGSPC definition (and FPSPC defined below).
a55e280b 204 */
07f28727
MK
205#define REGSPC 6*4
206#define PUSHR movab -REGSPC(sp),sp; storer $0x3f,(sp)
207#define POPR loadr $0x3f,(sp); movab REGSPC(sp),sp
a55e280b
SL
208
209/*
210 * Floating point state is saved across faults and
211 * interrupts. The state occupies 4 longwords on
212 * the stack:
213 * precision indicator (single = 0/double = 1)
214 * double representation of accumulator
215 * save accumulator status flag (pcb_savacc)
216 */
217#define FPSPC (4*4)
218
219#define SAVE_FPSTAT(_delta) \
220 bitl $PSL_DBL,_delta(sp); \
221 beql 1f; \
222 pushl $1; \
223 pushd; \
224 jmp 2f; \
2251: pushl $0; \
226 pushl $0; \
227 stf -(sp); \
2282: tstl _u+PCB_SAVACC; \
229 bneq 3f; \
230 moval 0(sp),_u+PCB_SAVACC; \
231 orl2 $2,8(sp);\
2323: pushl $0;
233
234#define REST_FPSTAT \
235 tstl (sp)+; \
236 bitl $2,8(sp);\
237 beql 1f;\
238 movl $0,_u+PCB_SAVACC; \
2391: bitl $1,8(sp); \
240 beql 2f; \
241 ldd (sp); \
242 jmp 3f; \
2432: ldf (sp); \
2443: moval 12(sp),sp;
245
246#define REST_ACC \
247 tstl _u+PCB_SAVACC; \
248 beql 2f; \
249 movl _u+PCB_SAVACC,r1; \
250 andl3 $(EXPMASK|SIGNBIT),(r1),-(sp); \
251 cmpl $0x80000000,(sp)+; \
252 bneq 3f; \
253 clrl (r1); \
2543: bitl $1,8(r1); \
255 beql 1f; \
256 ldd (r1); \
257 jmp 2f; \
2581: ldf (r1); \
2592: ;
260
261 .data
262nofault: .space 4 # bus error non-local goto label
57a0bdb5 263
a55e280b 264 .text
57a0bdb5
SL
265SCBVEC(buserr):
266 CHECK_SFE(12)
a55e280b 267 SAVE_FPSTAT(12)
af0b6351 268 incl _intrcnt+I_BUSERR # keep stats...
a55e280b
SL
269 pushl r0 # must save
270 andl3 24(sp),$ERRCD,r0 # grab pushed MER value
271 cmpl r0,$APE # address parity error?
57a0bdb5 272 jneq 1f
a55e280b
SL
273 halt
2741: cmpl r0,$VBE # versabus error?
275 jneq 2f
276 halt
2772:
278 movl (sp)+,r0 # restore r0 and...
279 bitl $PSL_CURMOD,4*4+3*4(sp) # check if happened in user mode?
280 jeql 3f # yes, then shift stack up for trap...
281 movl 12(sp),16(sp) # sorry, no space for which-buss...
282 movl 8(sp),12(sp)
283 movl 4(sp),8(sp)
284 movl 0(sp),4(sp)
285 movl $T_BUSERR,0(sp) # push trap type code and...
286 jbr alltraps # ...merge with all other traps
2873: # kernel mode, check to see if...
288 tstl nofault # ...doing peek/poke?
289 jeql 4f # nofault set? if so, jump to it...
290 movl nofault,4*4+2*4(sp) # ...setup for non-local goto
291 clrl nofault
292 jbr 5f
2934:
294 PUSHR
07f28727 295 pushab 4*4+REGSPC(sp) # address of bus error parameters
57a0bdb5
SL
296 callf $8,_buserror
297 POPR
a55e280b
SL
2985:
299 REST_FPSTAT
300 movab 8(sp),sp # remove bus error parameters
57a0bdb5
SL
301 rei
302
a55e280b
SL
303SCBVEC(powfail): # We should be on interrupt stack now.
304 SAVEpwfl() # save machine state
56ad8000 305 moval _Xdoadump-SYSTEM,_scb+SCB_DOADUMP
57a0bdb5
SL
306 halt
307
308SCBVEC(stray):
44622fe3 309 incl _cnt+V_INTR # add to statistics
57a0bdb5
SL
310 rei
311
312#include "../net/netisr.h"
313 .globl _netisr
314SCBVEC(netintr):
315 CHECK_SFE(4)
56ad8000
SL
316 SAVE_FPSTAT(4); PUSHR
317#include "imp.h"
318#if NIMP > 0
319 bbc $NETISR_IMP,_netisr,1f;
320 andl2 $~(1<<NETISR_IMP),_netisr
321 callf $4,_impintr;
57a0bdb5 3221:
56ad8000 323#endif
57a0bdb5 324#ifdef INET
57a0bdb5 325 bbc $NETISR_IP,_netisr,1f
a55e280b 326 andl2 $~(1<<NETISR_IP),_netisr
57a0bdb5
SL
327 callf $4,_ipintr
3281:
329#endif
330#ifdef NS
331 bbc $NETISR_NS,_netisr,1f
a55e280b 332 andl2 $~(1<<NETISR_NS),_netisr
57a0bdb5
SL
333 callf $4,_nsintr
3341:
335#endif
56ad8000
SL
336 bbc $NETISR_RAW,_netisr,1f
337 andl2 $~(1<<NETISR_RAW),_netisr
338 callf $4,_rawintr
3391:
340 incl _cnt+V_SOFT
341 POPR; REST_FPSTAT
57a0bdb5
SL
342 rei
343
57a0bdb5
SL
344SCBVEC(cnrint):
345 CHECK_SFE(4)
a55e280b 346 SAVE_FPSTAT(4); PUSHR;
af0b6351
SL
347 pushl $CPCONS; callf $8,_cnrint;
348 incl _intrcnt+I_CNR
349 incl _cnt+V_INTR
a55e280b
SL
350 POPR; REST_FPSTAT;
351 rei
57a0bdb5
SL
352SCBVEC(cnxint):
353 CHECK_SFE(4)
a55e280b 354 SAVE_FPSTAT(4); PUSHR;
af0b6351
SL
355 pushl $CPCONS; callf $8,_cnxint;
356 incl _intrcnt+I_CNX
357 incl _cnt+V_INTR
a55e280b
SL
358 POPR; REST_FPSTAT;
359 rei
57a0bdb5
SL
360SCBVEC(rmtrint):
361 CHECK_SFE(4)
362 SAVE_FPSTAT(4); PUSHR;
af0b6351
SL
363 pushl $CPREMOT; callf $8,_cnrint;
364 incl _intrcnt+I_RMTR
365 incl _cnt+V_INTR
a55e280b
SL
366 POPR; REST_FPSTAT;
367 rei
57a0bdb5
SL
368SCBVEC(rmtxint):
369 CHECK_SFE(4)
370 SAVE_FPSTAT(4); PUSHR;
af0b6351
SL
371 pushl $CPREMOT; callf $8,_cnxint;
372 incl _intrcnt+I_RMTX
373 incl _cnt+V_INTR
a55e280b
SL
374 POPR; REST_FPSTAT;
375 rei
57a0bdb5 376
a55e280b 377#define PUSHPCPSL pushl 4+FPSPC+REGSPC(sp); pushl 4+FPSPC+REGSPC(sp);
57a0bdb5
SL
378
379SCBVEC(hardclock):
a55e280b
SL
380 tstl _clk_enable
381 bneq 1f
382 rei
3831:
57a0bdb5 384 CHECK_SFE(4)
a55e280b
SL
385 SAVE_FPSTAT(4); PUSHR
386 PUSHPCPSL # push pc and psl
387 callf $12,_hardclock # hardclock(pc,psl)
af0b6351 388 incl _intrcnt+I_CLOCK
57a0bdb5 389 incl _cnt+V_INTR ## temp so not to break vmstat -= HZ
a55e280b 390 POPR; REST_FPSTAT
57a0bdb5
SL
391 rei
392SCBVEC(softclock):
393 CHECK_SFE(4)
a55e280b 394 SAVE_FPSTAT(4); PUSHR;
57a0bdb5 395 PUSHPCPSL # push pc and psl
a55e280b 396 callf $12,_softclock # softclock(pc,psl)
af0b6351 397 incl _cnt+V_SOFT
a55e280b 398 POPR; REST_FPSTAT
57a0bdb5
SL
399 rei
400
56ad8000
SL
401/*
402 * Stray VERSAbus interrupt catch routines
403 */
404 .data
405#define PJ .align 2; callf $4,_Xvstray
406 .globl _catcher
407_catcher:
408 PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ
409 PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ
410 PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ
411 PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ
412 PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ
413 PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ
414 PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ
415 PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ
416 PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ
417 PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ
418 PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ
419 PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ;PJ
420
421 .align 2
422 .globl _cold
423_cold: .long 0x3
424
425 .text
426SCBVEC(vstray):
427 .word 0
428 bbc $0,_cold,2f # system running?
429 bbc $1,_cold,1f # doing autoconfig?
430 jbr 3f # random interrupt, ignore
4311:
432 mfpr $IPL,r12 # ...setup br and cvec
433 subl3 $_catcher+7,-8(fp),r11; shar $3,r11,r11
434 addl2 $SCB_DEVBASE,r11
435 jbr 3f
4362:
437 PUSHR
438 subl3 $_catcher+7,-8(fp),r0; shar $3,r0,r0
439 addl3 $SCB_DEVBASE,r0,-(sp);
440 mfpr $IPL,-(sp)
441 PRINTF(2, "stray intr ipl %x vec %x\n")
442 POPR
4433: moval 0f,-8(fp); ret # pop callf frame...
4440: rei # ...and return
445
57a0bdb5
SL
446/*
447 * Trap and fault vector routines
448 */
449#define TRAP(a) pushl $T_/**/a; jbr alltraps
450
451/*
452 * Ast delivery (profiling and/or reschedule)
453 */
57a0bdb5
SL
454
455SCBVEC(kspnotval):
456 CHECK_SFE(4)
457 pushl $0;
458 SAVE_FPSTAT(8)
459 TRAP(KSPNOTVAL)
460SCBVEC(privinflt):
461 CHECK_SFE(4)
462 pushl $0;
463 SAVE_FPSTAT(8)
464 TRAP(PRIVINFLT)
465SCBVEC(resopflt):
466 CHECK_SFE(4)
467 pushl $0;
468 SAVE_FPSTAT(8)
469 TRAP(RESOPFLT)
470SCBVEC(resadflt):
471 CHECK_SFE(4)
472 pushl $0;
473 SAVE_FPSTAT(8)
474 TRAP(RESADFLT)
475SCBVEC(bptflt):
476 CHECK_SFE(4)
477 pushl $0;
478 SAVE_FPSTAT(8)
479 TRAP(BPTFLT)
11b6ca93
SL
480SCBVEC(kdbintr):
481 CHECK_SFE(4);
482 pushl $0;
483 SAVE_FPSTAT(8);
484 TRAP(KDBTRAP);
57a0bdb5
SL
485SCBVEC(tracep):
486 CHECK_SFE(4)
487 pushl $0;
488 SAVE_FPSTAT(8)
489 TRAP(TRCTRAP)
490SCBVEC(alignflt):
82bf8967 491#ifdef ALIGN
44622fe3
SL
492 bitl $PSL_CURMOD,4(sp)
493 jeql align_excp # Can't emulate for kernel mode !
494 jbr non_aligned # Only emulated for user mode.
495align_excp:
496#else
57a0bdb5 497 CHECK_SFE(4)
44622fe3 498#endif
57a0bdb5
SL
499 pushl $0;
500 SAVE_FPSTAT(8)
501 TRAP(ALIGNFLT)
502SCBVEC(arithtrap):
503 CHECK_SFE(8)
504 SAVE_FPSTAT(8)
505 TRAP(ARITHTRAP)
506
507SCBVEC(protflt):
508 CHECK_SFE(12)
509 bitl $1,(sp)+
510 jneq segflt
511 SAVE_FPSTAT(8)
512 TRAP(PROTFLT)
513segflt:
514 SAVE_FPSTAT(8)
515 TRAP(SEGFLT)
516
a55e280b 517SCBVEC(fpm): # Floating Point Emulation
82bf8967 518#ifdef FPE
57a0bdb5
SL
519 CHECK_SFE(16)
520 SAVE_FPSTAT(16)
44622fe3 521 incl _cnt+V_FPE # count emulation traps
57a0bdb5
SL
522 callf $4,_fpemulate
523 REST_FPSTAT
82bf8967 524#endif
57a0bdb5
SL
525 moval 8(sp),sp # Pop operand
526 tstl (sp) # Stack= PSL, PC, return_code
527 jneq _Xarithtrap # If not OK, emulate F.P. exception
528 movab 4(sp),sp # Else remove return_code and
529 rei
530
531SCBVEC(sfexcep):
532 CHECK_SFE(4)
533 pushl $0
534 SAVE_FPSTAT(8)
535 TRAP(ASTFLT)
536
537SCBVEC(transflt):
538 CHECK_SFE(12)
23f9abf2 539 bitl $2,(sp)+
57a0bdb5
SL
540 bneq tableflt
541pageflt:
542 SAVE_FPSTAT(8)
543 TRAP(PAGEFLT)
544tableflt:
545 SAVE_FPSTAT(8)
546 TRAP(TABLEFLT)
547
548#define REST_STACK movab 4(sp), sp; REST_FPSTAT; movab 4(sp), sp
549
550alltraps:
551 mfpr $USP,-(sp);
a55e280b
SL
552 callf $4,_trap;
553 mtpr (sp)+,$USP
57a0bdb5 554 incl _cnt+V_TRAP
a55e280b 555 REST_STACK # pop type, code, and fp stuff
57a0bdb5
SL
556 mtpr $HIGH,$IPL ## dont go to a higher IPL (GROT)
557 rei
558
559SCBVEC(syscall):
560 CHECK_SFE(8)
561 SAVE_FPSTAT(8)
562 pushl $T_SYSCALL
a55e280b
SL
563 mfpr $USP,-(sp);
564 callf $4,_syscall;
565 mtpr (sp)+,$USP
57a0bdb5 566 incl _cnt+V_SYSCALL
a55e280b 567 REST_STACK # pop type, code, and fp stuff
57a0bdb5
SL
568 mtpr $HIGH,$IPL ## dont go to a higher IPL (GROT)
569 rei
570
571/*
741dff62
SL
572 * System page table.
573 *
56ad8000
SL
574 * Mbmap and Usrptmap are enlarged by CLSIZE entries
575 * as they are managed by resource maps starting with index 1 or CLSIZE.
57a0bdb5
SL
576 */
577#define vaddr(x) ((((x)-_Sysmap)/4)*NBPG+SYSTEM)
578#define SYSMAP(mname, vname, npte) \
579_/**/mname: .globl _/**/mname; \
56ad8000 580 .space (npte)*4; \
57a0bdb5
SL
581 .globl _/**/vname; \
582 .set _/**/vname,vaddr(_/**/mname)
bd08bc0f 583#define ADDMAP(npte) .space (npte)*4
57a0bdb5
SL
584
585 .data
586 .align 2
587 SYSMAP(Sysmap ,Sysbase ,SYSPTSIZE )
57a0bdb5
SL
588 SYSMAP(Forkmap ,forkutl ,UPAGES )
589 SYSMAP(Xswapmap ,xswaputl ,UPAGES )
590 SYSMAP(Xswap2map,xswap2utl ,UPAGES )
591 SYSMAP(Swapmap ,swaputl ,UPAGES )
592 SYSMAP(Pushmap ,pushutl ,UPAGES )
593 SYSMAP(Vfmap ,vfutl ,UPAGES )
57a0bdb5
SL
594 SYSMAP(CMAP1 ,CADDR1 ,1 )
595 SYSMAP(CMAP2 ,CADDR2 ,1 )
596 SYSMAP(mmap ,vmmap ,1 )
56ad8000 597 SYSMAP(alignmap ,alignutl ,1 ) /* XXX */
57a0bdb5 598 SYSMAP(msgbufmap,msgbuf ,MSGBUFPTECNT )
56ad8000 599 SYSMAP(Mbmap ,mbutl ,NMBCLUSTERS*CLSIZE+CLSIZE )
34544495 600 SYSMAP(camap ,cabase ,16*CLSIZE )
56ad8000
SL
601#ifdef GPROF
602 SYSMAP(profmap ,profbase ,600*CLSIZE )
603#endif
220741c6
KM
604 /*
605 * Enlarge kmempt as needed for bounce buffers allocated
606 * by tahoe controllers.
607 */
608#include "dk.h"
bd08bc0f 609 ADDMAP( NVD*(MAXPHYS/NBPG+CLSIZE) )
34544495 610#include "yc.h"
220741c6 611#include "yc.h"
bd08bc0f 612 ADDMAP( NCY*(MAXPHYS/NBPG+CLSIZE) )
4eaa1510 613#include "mp.h"
bd08bc0f 614 ADDMAP( NMP*14 )
34544495 615 SYSMAP(ecamap ,calimit ,0 )
220741c6 616 SYSMAP(ekmempt ,kmemlimit ,0 )
4eaa1510 617
56ad8000 618 SYSMAP(VMEMbeg ,vmembeg ,0 )
741dff62 619 SYSMAP(VMEMmap ,vmem ,VBIOSIZE )
220741c6
KM
620 SYSMAP(VMEMmap1 ,vmem1 ,0 )
621#include "ace.h"
bd08bc0f 622 ADDMAP( NACE*32 )
56ad8000 623 SYSMAP(VMEMend ,vmemend ,0 )
4eaa1510 624
23f9abf2 625 SYSMAP(VBmap ,vbbase ,CLSIZE )
bd08bc0f
MK
626 ADDMAP( NVD*(MAXPHYS/NBPG+CLSIZE) )
627 ADDMAP( NCY*(MAXPHYS/NBPG+CLSIZE) )
628 ADDMAP( NMP*14 )
741dff62 629 SYSMAP(eVBmap ,vbend ,0 )
4eaa1510 630
56ad8000 631 SYSMAP(Usrptmap ,usrpt ,USRPTSIZE+CLSIZE )
57a0bdb5
SL
632eSysmap:
633 .globl _Syssize
634 .set _Syssize,(eSysmap-_Sysmap)/4
635
636 .text
637/*
638 * Initialization
639 *
640 * IPL 0x1f; MME 0; scbb, pcbb, sbr, slr, isp, ksp not set
57a0bdb5 641 */
57a0bdb5
SL
642 .align 2
643 .globl start
644start:
645 .word 0
57a0bdb5 646/* set system control block base and system page table params */
57a0bdb5
SL
647 mtpr $_scb-SYSTEM,$SCBB
648 mtpr $_Sysmap-SYSTEM,$SBR
649 mtpr $_Syssize,$SLR
57a0bdb5 650/* double map the kernel into the virtual user addresses of phys mem */
57a0bdb5
SL
651 mtpr $_Sysmap,$P0BR
652 mtpr $_Syssize,$P0LR
a55e280b 653 mtpr $_Sysmap,$P1BR # against Murphy
57a0bdb5 654 mtpr $_Syssize,$P1LR
57a0bdb5 655/* set ISP */
a55e280b 656 movl $_intstack-SYSTEM+NISP*NBPG,sp # still physical
57a0bdb5 657 mtpr $_intstack+NISP*NBPG,$ISP
57a0bdb5 658/* count up memory */
57a0bdb5
SL
659 clrl r7
6601: pushl $1; pushl r7; callf $12,_badaddr; tstl r0; bneq 9f
a55e280b 661 ACBL($MAXMEM*1024-1,$64*1024,r7,1b)
57a0bdb5
SL
6629:
663/* clear memory from kernel bss and pages for proc 0 u. and page table */
11b6ca93
SL
664 movab _edata,r6; andl2 $~SYSTEM,r6
665 movab _end,r5; andl2 $~SYSTEM,r5
666#ifdef KDB
667 subl2 $4,r5
6681: clrl (r6); ACBL(r5,$4,r6,1b) # clear just bss
669 addl2 $4,r5
670 bbc $6,r11,0f # check RB_KDB
671 andl3 $~SYSTEM,r9,r5 # skip symbol & string tables
672 andl3 $~SYSTEM,r9,r6
673#endif
6740: orl3 $SYSTEM,r5,r9 # convert to virtual address
675 addl2 $NBPG-1,r9 # roundup to next page
57a0bdb5 676 addl2 $(UPAGES*NBPG)+NBPG+NBPG,r5
a55e280b
SL
6771: clrl (r6); ACBL(r5,$4,r6,1b)
678/* trap(), syscall(), and fpemulate() save r0-r12 in the entry mask */
57a0bdb5
SL
679 orw2 $0x01fff,_trap
680 orw2 $0x01fff,_syscall
82bf8967 681#ifdef FPE
57a0bdb5 682 orw2 $0x01fff,_fpemulate
82bf8967 683#endif
a55e280b 684 orw2 $0x01ffc,_panic # for debugging (no r0|r1)
56ad8000 685 callf $4,_fixctlrmask # setup for autoconfig
57a0bdb5
SL
686/* initialize system page table: scb and int stack writeable */
687 clrl r2
688 movab eintstack,r1
a55e280b
SL
689 andl2 $~SYSTEM,r1
690 shrl $PGSHIFT,r1,r1 # r1-page number of eintstack
04d1fc31 691/* make 1st page processor storage read/only, 2nd read/write */
57a0bdb5 692 orl3 $PG_V|PG_KR,r2,_Sysmap[r2]; incl r2;
04d1fc31 693 orl3 $PG_V|PG_KW,r2,_Sysmap[r2]; incl r2;
a55e280b
SL
694/* other parts of the system are read/write for kernel */
6951: orl3 $PG_V|PG_KW,r2,_Sysmap[r2]; # data:kernel write+phys=virtual
57a0bdb5 696 aoblss r1,r2,1b
57a0bdb5 697/* make rsstk read-only as red zone for interrupt stack */
a55e280b
SL
698 andl2 $~PG_PROT,_rsstkmap
699 orl2 $PG_V|PG_KR,_rsstkmap
57a0bdb5 700/* make kernel text space read-only */
57a0bdb5 701 movab _etext+NBPG-1,r1
a55e280b 702 andl2 $~SYSTEM,r1
57a0bdb5
SL
703 shrl $PGSHIFT,r1,r1
7041: orl3 $PG_V|PG_KR,r2,_Sysmap[r2]
705 aoblss r1,r2,1b
57a0bdb5 706/* make kernel data, bss, read-write */
11b6ca93 707 andl3 $~SYSTEM,r9,r1
57a0bdb5
SL
708 shrl $PGSHIFT,r1,r1
7091: orl3 $PG_V|PG_KW,r2,_Sysmap[r2]
710 aoblss r1,r2,1b
a55e280b 711/* go to mapped mode, have to change both pc and sp to system addresses */
57a0bdb5 712 mtpr $1,$TBIA
a55e280b
SL
713 mtpr $1,$PADC # needed by HW parity&ECC logic
714 mtpr $1,$PACC # just in case
57a0bdb5
SL
715 mtpr $1,$MME
716 movab SYSTEM(sp),sp
57a0bdb5
SL
717 jmp *$0f
7180:
57a0bdb5
SL
719/* disable any interrupts */
720 movl $0,_intenable
721/* init mem sizes */
722 shrl $PGSHIFT,r7,_maxmem
723 movl _maxmem,_physmem
724 movl _maxmem,_freemem
a55e280b 725/* setup context for proc[0] == scheduler */
11b6ca93 726 andl3 $~SYSTEM,r9,r6 # convert to physical
a55e280b 727 andl2 $~(NBPG-1),r6 # make page boundary
57a0bdb5
SL
728/* setup page table for proc[0] */
729 shrl $PGSHIFT,r6,r3 # r3 = btoc(r6)
730 orl3 $PG_V|PG_KW,r3,_Usrptmap # init first upt entry
731 incl r3 # r3 - next page
732 movab _usrpt,r0 # r0 - first user page
733 mtpr r0,$TBIS
57a0bdb5 734/* init p0br, p0lr */
a55e280b 735 mtpr r0,$P0BR # no p0 for proc[0]
57a0bdb5 736 mtpr $0,$P0LR
a55e280b 737 mtpr r0,$P1BR # no p1 either
57a0bdb5 738 mtpr $0,$P1LR
57a0bdb5
SL
739/* init p2br, p2lr */
740 movab NBPG(r0),r0
741 movl $PPAGES-UPAGES,r1
742 mtpr r1,$P2LR
743 moval -4*PPAGES(r0),r2
744 mtpr r2,$P2BR
57a0bdb5 745/* setup mapping for UPAGES of _u */
a55e280b 746 clrl r2
57a0bdb5
SL
747 movl $SYSTEM,r1
748 addl2 $UPAGES,r3
749 jbr 2f
7501: decl r3
a55e280b 751 moval -NBPG(r1),r1 # r1 = virtual add of next (downward) _u page
57a0bdb5
SL
752 subl2 $4,r0 # r0 = pte address
753 orl3 $PG_V|PG_URKW,r3,(r0)
754 mtpr r1,$TBIS
7552: aobleq $UPAGES,r2,1b
57a0bdb5
SL
756/* initialize (slightly) the pcb */
757 movab UPAGES*NBPG(r1),PCB_KSP(r1) # KSP starts at end of _u
758 movl r1,PCB_USP(r1) # USP starts just below _u
759 mfpr $P0BR,PCB_P0BR(r1)
760 mfpr $P0LR,PCB_P0LR(r1)
761 mfpr $P1BR,PCB_P1BR(r1)
762 mfpr $P1LR,PCB_P1LR(r1)
763 mfpr $P2BR,PCB_P2BR(r1)
764 mfpr $P2LR,PCB_P2LR(r1)
765 movl $CLSIZE,PCB_SZPT(r1) # init u.u_pcb.pcb_szpt
11b6ca93
SL
766 movl r9,PCB_R9(r1) # r9 obtained from boot
767 movl r10,PCB_R10(r1) # r10 obtained from boot
57a0bdb5
SL
768 movl r11,PCB_R11(r1) # r11 obtained from CP on boot
769 movab 1f,PCB_PC(r1) # initial pc
770 clrl PCB_PSL(r1) # kernel mode, ipl=0
57a0bdb5 771 shll $PGSHIFT,r3,r3
a55e280b
SL
772 mtpr r3,$PCBB # first pcbb (physical)
773/* go to kernel mode */
57a0bdb5 774 ldpctx
a55e280b 775 rei # Actually next instruction:
57a0bdb5 776/* put signal trampoline code in u. area */
a55e280b
SL
7771: movab sigcode,r0
778 movab _u+PCB_SIGC,r1
779 movl $19,r2
780 movblk
1e20e4cf
SL
781/* save boot device in global _bootdev */
782 movl r10,_bootdev
57a0bdb5
SL
783/* save reboot flags in global _boothowto */
784 movl r11,_boothowto
11b6ca93
SL
785/* save end of symbol & string table in global _bootesym */
786 subl3 $NBPG-1,r9,_bootesym
57a0bdb5 787/* calculate firstaddr, and call main() */
11b6ca93 788 andl3 $~SYSTEM,r9,r0
57a0bdb5 789 shrl $PGSHIFT,r0,-(sp)
a55e280b 790 addl2 $UPAGES+1,(sp) # first physical unused page
57a0bdb5 791 callf $8,_main
57a0bdb5 792/* proc[1] == /etc/init now running here in kernel mode; run icode */
a55e280b
SL
793 pushl $PSL_CURMOD # User mode PSL
794 pushl $0 # PC = 0 (virtual now)
57a0bdb5
SL
795 rei
796
a55e280b
SL
797/*
798 * Mask for saving/restoring registers on entry to
799 * a user signal handler. Space for the registers
800 * is reserved in sendsig, so beware if you want
801 * to change the mask.
802 */
803#define SIGREGS (R0|R1|R2|R3|R4|R5)
804 .align 2
805 .globl sigcode
806sigcode:
807 storer $SIGREGS,16(sp) # save volatile registers
808 calls $4*3+4,*12(sp) # params pushed by sendsig for handler
809 loadr $SIGREGS,4(sp) # restore volatile registers
810 movab 24(sp),fp # use parameter list set up in sendsig
811 kcall $SYS_sigreturn # cleanup mask and onsigstack
812 halt # sigreturn does not return!
813
814 .globl _icode
815 .globl _initflags
816 .globl _szicode
817/*
818 * Icode is copied out to process 1 to exec /etc/init.
819 * If the exec fails, process 1 exits.
820 */
57a0bdb5 821 .align 2
a55e280b
SL
822_icode:
823 pushab b`argv-l0(pc)
824l0: pushab b`init-l1(pc)
825l1: pushl $2
826 movab (sp),fp
827 kcall $SYS_execv
9f1a98cd 828 pushl r0
a55e280b
SL
829 kcall $SYS_exit
830
831init: .asciz "/etc/init"
832 .align 2
833_initflags:
834 .long 0
835argv: .long init+5-_icode
836 .long _initflags-_icode
837 .long 0
838_szicode:
839 .long _szicode-_icode
57a0bdb5
SL
840
841/*
842 * Primitives
843 */
844
845/*
846 * badaddr(addr, len)
847 * see if access addr with a len type instruction causes a machine check
848 * len is length of access (1=byte, 2=short, 4=long)
849 * r0 = 0 means good(exists); r0 =1 means does not exist.
850 */
a55e280b 851ENTRY(badaddr, R3|R4)
57a0bdb5
SL
852 mfpr $IPL,r1
853 mtpr $HIGH,$IPL
56ad8000 854 movl _scb+SCB_BUSERR,r2
57a0bdb5
SL
855 movl 4(fp),r3
856 movl 8(fp),r4
56ad8000 857 movab 9f,_scb+SCB_BUSERR
57a0bdb5
SL
858 bbc $0,r4,1f; tstb (r3)
8591: bbc $1,r4,1f; tstw (r3)
8601: bbc $2,r4,1f; tstl (r3)
a55e280b 8611: clrl r0
56ad8000 8622: movl r2,_scb+SCB_BUSERR
57a0bdb5
SL
863 mtpr r1,$IPL
864 ret
865
866 .align 2
a55e280b 8679: # catch buss error (if it comes)
57a0bdb5
SL
868 andl3 4(sp),$ERRCD,r0
869 cmpl r0,$APE
870 jneq 1f
a55e280b 871 halt # address parity error
57a0bdb5
SL
8721: cmpl r0,$VBE
873 jneq 1f
874 halt # Versabus error
8751:
876 movl $1,r0 # Anything else = bad address
877 movab 8(sp),sp # discard buss error trash
878 movab 2b,(sp) # new program counter on stack.
879 rei
880
57a0bdb5
SL
881/*
882 * badcyaddr(addr)
883 * see if access tape master controller addr causes a bus error
884 * r0 = 0: no error; r0 = 1: timeout error.
885 */
a55e280b 886ENTRY(badcyaddr, 0)
57a0bdb5
SL
887 mfpr $IPL,r1
888 mtpr $HIGH,$IPL
a55e280b
SL
889 clrl r2
890 movab 2f,nofault
57a0bdb5 891 movob $-1, *4(fp)
a55e280b
SL
8921: aobleq $1000, r2, 1b
893 clrl nofault # made it w/o bus error
894 clrl r0
895 jbr 3f
8962: movl $1,r0
8973: mtpr r1,$IPL
57a0bdb5
SL
898 ret
899
a55e280b
SL
900/*
901 * peek(addr)
902 * fetch word and catch any bus error
903 */
904ENTRY(peek, 0)
905 mfpr $IPL,r1
906 mtpr $0x18,$IPL # not reentrant
907 movl 4(fp),r2
908 movab 1f,nofault
909 movw (r2),r0
910 clrl nofault
911 andl2 $0xffff,r0
912 jbr 2f
9131: movl $-1,r0 # bus error
9142: mtpr r1,$IPL
915 ret
57a0bdb5 916
a55e280b
SL
917/*
918 * poke(addr, val)
919 * write word and catch any bus error
920 */
921ENTRY(poke, R3)
922 mfpr $IPL,r1
923 mtpr $0x18,$IPL # not reentrant
924 movl 4(fp),r2
925 movl 8(fp),r3
926 clrl r0
927 movab 1f,nofault
928 movw r3,(r2)
929 clrl nofault
930 jbr 2f
9311: movl $-1,r0 # bus error
9322: mtpr r1,$IPL
57a0bdb5
SL
933 ret
934
a55e280b
SL
935/*
936 * Copy a potentially overlapping block of memory.
937 *
938 * ovbcopy(src, dst, count)
939 * caddr_t src, dst; unsigned count;
940 */
941ENTRY(ovbcopy, R3|R4)
57a0bdb5
SL
942 movl 4(fp),r0
943 movl 8(fp),r1
944 movl 12(fp),r2
945 cmpl r0,r1
a55e280b
SL
946 bgtru 1f # normal forward case
947 beql 2f # equal, nothing to do
948 addl2 r2,r0 # may be overlapping
57a0bdb5
SL
949 cmpl r0,r1
950 bgtru 3f
a55e280b 951 subl2 r2,r0 # normal forward case
57a0bdb5
SL
9521:
953 movblk
9542:
955 ret
9563:
a55e280b 957 addl2 r2,r1 # overlapping, must do backwards
57a0bdb5
SL
958 subl3 r0,r1,r3
959 movl r2,r4
960 jbr 5f
9614:
962 subl2 r3,r0
963 subl2 r3,r1
964 movl r3,r2
965 movblk
966 subl2 r3,r0
967 subl2 r3,r1
968 subl2 r3,r4
9695:
970 cmpl r4,r3
971 jgtr 4b
972 movl r4,r2
973 subl2 r2,r0
974 subl2 r2,r1
975 movblk
976 ret
977
978/*
a55e280b
SL
979 * Copy a null terminated string from the user address space into
980 * the kernel address space.
981 *
982 * copyinstr(fromaddr, toaddr, maxlength, &lencopied)
57a0bdb5 983 */
36d595e6 984ENTRY(copyinstr, 0)
a55e280b 985 movl 12(fp),r5 # r5 = max length
36d595e6
KM
986 jlss 5f
987 movl 8(fp),r4 # r4 = kernel address
a55e280b 988 movl 4(fp),r0 # r0 = user address
a55e280b
SL
989 andl3 $(NBPG*CLSIZE-1),r0,r2 # r2 = bytes on first page
990 subl3 r2,$(NBPG*CLSIZE),r2
a55e280b
SL
9911:
992 cmpl r5,r2 # r2 = min(bytes on page, length left);
993 jgeq 2f
994 movl r5,r2
9952:
996 prober $1,(r0),r2 # bytes accessible?
36d595e6 997 jeql 5f
a55e280b 998 subl2 r2,r5 # update bytes left count
36d595e6
KM
999 movl r2,r3 # r3 = saved count
1000 movl r0,r1
1001 cmps3 # check for null
1002 tstl r2
a55e280b 1003 jneq 3f
36d595e6
KM
1004 subl2 r3,r0 # back up r0
1005 movl r4,r1
1006 movl r3,r2
1007 movblk # copy in next piece
1008 movl r1,r4
a55e280b
SL
1009 movl $(NBPG*CLSIZE),r2 # check next page
1010 tstl r5 # run out of space?
1011 jneq 1b
1012 movl $ENOENT,r0 # set error code and return
36d595e6 1013 jbr 6f
a55e280b
SL
10143:
1015 tstl 16(fp) # return length?
1016 beql 4f
1017 subl3 r5,12(fp),r5 # actual len = maxlen - unused pages
1018 subl2 r2,r5 # - unused on this page
1019 addl3 $1,r5,*16(fp) # + the null byte
10204:
36d595e6
KM
1021 movl r4,r1
1022 subl3 r2,r3,r2 # calc char cnt
1023 subl2 r2,r0 # back up r0
1024 incl r2 # add on null byte
1025 movblk # copy last piece
a55e280b 1026 clrl r0
57a0bdb5 1027 ret
36d595e6 10285:
a55e280b 1029 movl $EFAULT,r0
36d595e6 10306:
a55e280b 1031 tstl 16(fp)
36d595e6 1032 beql 7f
a55e280b 1033 subl3 r5,12(fp),*16(fp)
36d595e6 10347:
a55e280b
SL
1035 ret
1036
1037/*
1038 * Copy a null terminated string from the kernel
1039 * address space to the user address space.
1040 *
1041 * copyoutstr(fromaddr, toaddr, maxlength, &lencopied)
1042 */
36d595e6 1043ENTRY(copyoutstr, 0)
a55e280b 1044 movl 12(fp),r5 # r5 = max length
b224cc0b 1045 jlss 5f
a55e280b 1046 movl 4(fp),r0 # r0 = kernel address
36d595e6
KM
1047 movl 8(fp),r4 # r4 = user address
1048 andl3 $(NBPG*CLSIZE-1),r4,r2 # r2 = bytes on first page
a55e280b 1049 subl3 r2,$(NBPG*CLSIZE),r2
57a0bdb5 10501:
a55e280b
SL
1051 cmpl r5,r2 # r2 = min(bytes on page, length left);
1052 jgeq 2f
1053 movl r5,r2
10542:
36d595e6 1055 probew $1,(r4),r2 # bytes accessible?
b224cc0b 1056 jeql 5f
a55e280b 1057 subl2 r2,r5 # update bytes left count
36d595e6
KM
1058 movl r2,r3 # r3 = saved count
1059 movl r0,r1
dc4c1de6
MK
1060/*
1061 * This is a workaround for a microcode bug that causes
1062 * a trap type 9 when cmps3/movs3 touches the last byte
1063 * on a valid page immediately followed by an invalid page.
1064 */
36d595e6
KM
1065#ifdef good_cmps3
1066 cmps3 # check for null
a55e280b 1067 tstl r2
a55e280b 1068 jneq 3b
36d595e6
KM
1069#else
1070 decl r2
35f6fda7 1071 beql 9f # cannot handle case of r2 == 0!
36d595e6 1072 cmps3 # check for null up to last byte
35f6fda7 10739:
36d595e6
KM
1074 incl r2
1075 cmpl $1,r2 # get to last byte on page?
1076 bneq 3b
1077 tstb (r0) # last byte on page null?
35f6fda7 1078 beql 3b
36d595e6 1079 incl r0 # not null, so bump pointer
35f6fda7 1080#endif not good_cmps3
36d595e6
KM
1081 subl2 r3,r0 # back up r0
1082 movl r4,r1
1083 movl r3,r2
1084 movblk # copy out next piece
1085 movl r1,r4
a55e280b
SL
1086 movl $(NBPG*CLSIZE),r2 # check next page
1087 tstl r5 # run out of space?
1088 jneq 1b
1089 movl $ENOENT,r0 # set error code and return
36d595e6 1090 jbr 6b
b224cc0b
KM
10915:
1092 clrl *$0 # this should never execute, if it does
1093 movl $EFAULT,r0 # save me a core dump (mkm - 9/87)
10946:
1095 tstl 16(fp)
1096 beql 7f
1097 subl3 r5,12(fp),*16(fp)
10987:
1099 ret
1100
57a0bdb5 1101
a55e280b
SL
1102/*
1103 * Copy a null terminated string from one point to another in
1104 * the kernel address space.
1105 *
1106 * copystr(fromaddr, toaddr, maxlength, &lencopied)
1107 */
36d595e6
KM
1108ENTRY(copystr, 0)
1109 movl 12(fp),r3 # r3 = max length
1110 jlss 5b
a55e280b 1111 movl 4(fp),r0 # r0 = src address
36d595e6
KM
1112 movl 8(fp),r4 # r4 = dest address
1113 clrl r5 # r5 = bytes left
1114 movl r3,r2 # r2 = max bytes to copy
1115 movl r0,r1
1116 cmps3 # check for null
1117 tstl r2
a55e280b 1118 jneq 3b
36d595e6
KM
1119 subl2 r3,r0 # back up r0
1120 movl r4,r1
1121 movl r3,r2
1122 movblk # copy next piece
a55e280b 1123 movl $ENOENT,r0 # set error code and return
36d595e6 1124 jbr 6b
57a0bdb5 1125
a55e280b
SL
1126/*
1127 * Copy a block of data from the user address space into
1128 * the kernel address space.
1129 *
1130 * copyin(fromaddr, toaddr, count)
1131 */
1132ENTRY(copyin, 0)
57a0bdb5 1133 movl 12(fp),r0 # copy length
a55e280b 1134 blss 9f
57a0bdb5 1135 movl 4(fp),r1 # copy user address
a55e280b
SL
1136 cmpl $(CLSIZE*NBPG),r0 # probing one page or less ?
1137 bgeq 2f # yes
11381:
1139 prober $1,(r1),$(CLSIZE*NBPG) # bytes accessible ?
1140 beql 9f # no
1141 addl2 $(CLSIZE*NBPG),r1 # incr user address ptr
1142 _ACBL($(CLSIZE*NBPG+1),$(-CLSIZE*NBPG),r0,1b) # reduce count and loop
11432:
57a0bdb5 1144 prober $1,(r1),r0 # bytes accessible ?
a55e280b
SL
1145 beql 9f # no
1146 MOVC3(4(fp),8(fp),12(fp))
57a0bdb5
SL
1147 clrl r0
1148 ret
a55e280b 11499:
57a0bdb5
SL
1150 movl $EFAULT,r0
1151 ret
1152
a55e280b
SL
1153/*
1154 * Copy a block of data from the kernel
1155 * address space to the user address space.
1156 *
1157 * copyout(fromaddr, toaddr, count)
1158 */
1159ENTRY(copyout, 0)
57a0bdb5 1160 movl 12(fp),r0 # get count
a55e280b 1161 blss 9b
57a0bdb5 1162 movl 8(fp),r1 # get user address
a55e280b
SL
1163 cmpl $(CLSIZE*NBPG),r0 # can do in one probew?
1164 bgeq 2f # yes
11651:
1166 probew $1,(r1),$(CLSIZE*NBPG) # bytes accessible?
1167 beql 9b # no
1168 addl2 $(CLSIZE*NBPG),r1 # increment user address
1169 _ACBL($(CLSIZE*NBPG+1),$(-CLSIZE*NBPG),r0,1b) # reduce count and loop
11702:
57a0bdb5 1171 probew $1,(r1),r0 # bytes accessible?
a55e280b
SL
1172 beql 9b # no
1173 MOVC3(4(fp),8(fp),12(fp))
57a0bdb5
SL
1174 clrl r0
1175 ret
1176
1177/*
1178 * non-local goto's
1179 */
a55e280b
SL
1180#ifdef notdef
1181ENTRY(setjmp, 0)
1182 movl 4(fp),r0
1183 movl (fp),(r0); addl2 $4,r0 # save fp
1184 movl -8(fp),(r0) # save pc
57a0bdb5
SL
1185 clrl r0
1186 ret
a55e280b 1187#endif
57a0bdb5 1188
a55e280b
SL
1189ENTRY(longjmp, 0)
1190 movl 4(fp),r0
1191 movl (r0),newfp; addl2 $4,r0 # must save parameters in memory
1192 movl (r0),newpc # as all regs may be clobbered.
11931:
1194 cmpl fp,newfp # are we there yet?
1195 bgequ 2f # yes
1196 moval 1b,-8(fp) # redirect return pc to us!
1197 ret # pop next frame
11982:
1199 beql 3f # did we miss our frame?
1200 pushab 4f # yep ?!?
57a0bdb5 1201 callf $8,_panic
a55e280b
SL
12023:
1203 movl newpc,r0 # all done, just return
1204 jmp (r0) # to setjmp `ret'
57a0bdb5 1205
a55e280b
SL
1206 .data
1207newpc: .space 4
1208newfp: .space 4
12094: .asciz "longjmp"
11b6ca93 1210 .text
57a0bdb5 1211
a55e280b
SL
1212/*
1213 * setjmp that saves all registers as the call frame may not
1214 * be available to recover them in the usual manner by longjmp.
1215 * Called before swapping out the u. area, restored by resume()
1216 * below.
1217 */
1218ENTRY(savectx, 0)
1219 movl 4(fp),r2
1220 storer $0x1ff8,(r2); addl2 $40,r2 # r3-r12
1221 movl (fp),(r2); addl2 $4,r2 # fp
1222 movab 8(fp),(r2); addl2 $4,r2 # sp
1223 movl -8(fp),(r2) # pc
1224 clrl r0
1225 ret
57a0bdb5 1226
11b6ca93
SL
1227#ifdef KDB
1228/*
1229 * C library -- reset, setexit
1230 *
1231 * reset(x)
1232 * will generate a "return" from
1233 * the last call to
1234 * setexit()
1235 * by restoring r2 - r12, fp
1236 * and doing a return.
1237 * The returned value is x; on the original
1238 * call the returned value is 0.
1239 */
1240ENTRY(setexit, 0)
1241 movab setsav,r0
1242 storer $0x1ffc, (r0)
1243 movl (fp),44(r0) # fp
1244 moval 4(fp),48(r0) # sp
1245 movl -8(fp),52(r0) # pc
1246 clrl r0
1247 ret
1248
1249ENTRY(reset, 0)
1250 movl 4(fp),r0 # returned value
1251 movab setsav,r1
1252 loadr $0x1ffc,(r1)
1253 movl 44(r1),fp
1254 movl 48(r1),sp
1255 jmp *52(r1)
1256
1257 .data
1258 .align 2
1259setsav: .space 14*4
1260 .text
1261#endif
1262
57a0bdb5
SL
1263 .globl _whichqs
1264 .globl _qs
1265 .globl _cnt
1266
1267 .globl _noproc
1268 .comm _noproc,4
1269 .globl _runrun
1270 .comm _runrun,4
57a0bdb5
SL
1271/*
1272 * The following primitives use the fancy TAHOE instructions.
1273 * _whichqs tells which of the 32 queues _qs
1274 * have processes in them. setrq puts processes into queues, remrq
1275 * removes them from queues. The running process is on no queue,
1276 * other processes are on a queue related to p->p_pri, divided by 4
1277 * actually to shrink the 0-127 range of priorities into the 32 available
1278 * queues.
1279 */
1280
1281/*
1282 * setrq(p), using fancy TAHOE instructions.
1283 *
1284 * Call should be made at spl8(), and p->p_stat should be SRUN
1285 */
a55e280b 1286ENTRY(setrq, 0)
57a0bdb5
SL
1287 movl 4(fp),r0
1288 tstl P_RLINK(r0) ## firewall: p->p_rlink must be 0
1289 beql set1 ##
1290 pushab set3 ##
1291 callf $8,_panic ##
1292set1:
1293 movzbl P_PRI(r0),r1 # put on queue which is p->p_pri / 4
1294 shar $2,r1,r1
1295 shal $1,r1,r2
1296 moval _qs[r2],r2
1297 insque (r0),*4(r2) # at end of queue
1298 shal r1,$1,r1
1299 orl2 r1,_whichqs # mark queue non-empty
1300 ret
1301
1302set3: .asciz "setrq"
1303
1304/*
1305 * remrq(p), using fancy TAHOE instructions
1306 *
1307 * Call should be made at spl8().
1308 */
a55e280b 1309ENTRY(remrq, 0)
57a0bdb5
SL
1310 movl 4(fp),r0
1311 movzbl P_PRI(r0),r1
1312 shar $2,r1,r1
1313 bbs r1,_whichqs,rem1
1314 pushab rem3 # it wasn't recorded to be on its q
1315 callf $8,_panic
1316rem1:
1317 remque (r0)
1318 bneq rem2 # q not empty yet
1319 shal r1,$1,r1
1320 mcoml r1,r1
1321 andl2 r1,_whichqs # mark queue empty
1322rem2:
1323 clrl P_RLINK(r0) ## for firewall checking
1324 ret
1325
1326rem3: .asciz "remrq"
1327
57a0bdb5
SL
1328/*
1329 * Masterpaddr is the p->p_addr of the running process on the master
1330 * processor. When a multiprocessor system, the slave processors will have
1331 * an array of slavepaddr's.
1332 */
1333 .globl _masterpaddr
1334 .data
11b6ca93 1335 .align 2
a55e280b 1336_masterpaddr: .long 0
57a0bdb5
SL
1337
1338 .text
1339sw0: .asciz "swtch"
04d1fc31
MK
1340
1341/*
1342 * When no processes are on the runq, swtch branches to idle
1343 * to wait for something to come ready.
1344 */
1345 .globl Idle
1346Idle: idle:
10946d75 1347 movl $1,_noproc
04d1fc31
MK
1348 mtpr $0,$IPL # must allow interrupts here
13491:
1350 tstl _whichqs # look for non-empty queue
1351 bneq sw1
1352 brb 1b
1353
1354badsw: pushab sw0
1355 callf $8,_panic
1356 /* NOTREACHED */
1357
1358 .align 2
57a0bdb5 1359/*
a55e280b 1360 * swtch(), using fancy tahoe instructions
57a0bdb5 1361 */
a55e280b 1362ENTRY(swtch, 0)
57a0bdb5
SL
1363 movl (fp),fp # prepare for rei
1364 movl (sp),4(sp) # saved pc
1365 tstl (sp)+
1366 movpsl 4(sp)
04d1fc31 1367 incl _cnt+V_SWTCH
57a0bdb5 1368sw1: ffs _whichqs,r0 # look for non-empty queue
04d1fc31
MK
1369 blss idle # if none, idle
1370 mtpr $0x18,$IPL # lock out all so _whichqs==_qs
1371 bbc r0,_whichqs,sw1 # proc moved via interrupt
57a0bdb5
SL
1372 shal $1,r0,r1
1373 moval _qs[r1],r1
1374 movl (r1),r2 # r2 = p = highest pri process
1375 remque *(r1)
04d1fc31
MK
1376 bvs badsw # make sure something was there
1377 bneq sw2
57a0bdb5
SL
1378 shal r0,$1,r1
1379 mcoml r1,r1
1380 andl2 r1,_whichqs # no more procs in this queue
04d1fc31 1381sw2:
57a0bdb5 1382 clrl _noproc
04d1fc31 1383 clrl _runrun
10946d75 1384#ifdef notdef
57a0bdb5 1385 tstl P_WCHAN(r2) ## firewalls
04d1fc31 1386 bneq badsw ##
a2f6e980 1387 cmpb P_STAT(r2),$SRUN ##
04d1fc31 1388 bneq badsw ##
10946d75 1389#endif
57a0bdb5
SL
1390 clrl P_RLINK(r2) ##
1391 movl *P_ADDR(r2),r0
a55e280b 1392#ifdef notdef
04d1fc31 1393 cmpl r0,_masterpaddr # resume of current proc is easy
a55e280b
SL
1394 beql res0
1395#endif
04d1fc31
MK
1396 movl r0,_masterpaddr
1397 shal $PGSHIFT,r0,r0 # r0 = pcbb(p)
57a0bdb5 1398 brb swresume
57a0bdb5 1399
57a0bdb5
SL
1400/*
1401 * resume(pf)
1402 */
a55e280b
SL
1403ENTRY(resume, 0)
1404 shal $PGSHIFT,4(fp),r0 # r0 = pcbb(pf)
57a0bdb5
SL
1405 movl (fp),fp # prepare for rei
1406 movl (sp)+,4(sp) # saved pc
1407 tstl (sp)+
1408 movpsl 4(sp)
1409swresume:
a55e280b 1410 mtpr $0x18,$IPL # no interrupts, please
57a0bdb5
SL
1411 movl _CMAP2,_u+PCB_CMAP2 # yech
1412 REST_ACC # restore original accumulator
1413 svpctx
1414 mtpr r0,$PCBB
1415 ldpctx
1416 movl _u+PCB_CMAP2,_CMAP2 # yech
1417 mtpr $_CADDR2,$TBIS
1418res0:
a55e280b
SL
1419 movl _u+U_PROCP,r2 # r2 = u.u_procp
1420 tstl P_CKEY(r2) # does proc have code key?
1421 bneq 1f
1422 callf $4,_getcodekey # no, give him one
a2f6e980 1423 movl _u+U_PROCP,r2 # r2 = u.u_procp
a55e280b
SL
1424 movl r0,P_CKEY(r2)
14251:
a55e280b
SL
1426 tstl P_DKEY(r2) # does proc have data key?
1427 bneq 1f
1428 callf $4,_getdatakey # no, give him one
a2f6e980 1429 movl _u+U_PROCP,r2 # r2 = u.u_procp
a55e280b
SL
1430 movl r0,P_DKEY(r2)
14311:
1432 mtpr P_CKEY(r2),$CCK # set code cache key
1433 mtpr P_DKEY(r2),$DCK # set data cache key
57a0bdb5 1434 tstl _u+PCB_SSWAP
a55e280b
SL
1435 bneq res1
1436 rei
1437res1: # longjmp to saved context
57a0bdb5
SL
1438 movl _u+PCB_SSWAP,r2
1439 clrl _u+PCB_SSWAP
a55e280b
SL
1440 loadr $0x3ff8,(r2); addl2 $44,r2 # restore r3-r13 (r13=fp)
1441 movl (r2),r1; addl2 $4,r2 # fetch previous sp ...
1442 movab (sp),r0 # ... and current sp and
1443 cmpl r1,r0 # check for credibility,
1444 bgequ 1f # if further up stack ...
1445 pushab 2f; callf $8,_panic # ... panic
1446 /*NOTREACHED*/
14471: # sp ok, complete return
1448 movl r1,sp # restore sp
7cceb27c
KM
1449 pushl $PSL_PRVMOD # kernel mode, ipl 0
1450 pushl (r2) # return address
57a0bdb5 1451 rei
a55e280b 14522: .asciz "ldctx"
57a0bdb5
SL
1453
1454/*
1455 * {fu,su},{byte,word}
1456 */
a55e280b 1457ENTRY(fuword, 0)
57a0bdb5
SL
1458 movl 4(fp), r1
1459 prober $1,(r1),$4 # check access
1460 beql fserr # page unreadable
1461 bitl $1,r1 # check byte alignment
1462 bneq 2f # odd, do byte-word-byte
1463 bitl $2,r1 # check word alignment
1464 bneq 1f # odd, do in 2 words
1465 movl (r1),r0 # move longword
1466 ret
14671:
1468 movw (r1),r0 # move two words
1469 shal $16,r0,r0
1470 movzwl 2(r1),r1 # orw2 sign extends
1471 orl2 r1,r0
1472 ret
14732:
1474 movb (r1),r0 # move byte-word-byte
1475 shal $24,r0,r0
1476 movzwl 1(r1),r2 # orw2 sign extends
1477 shal $8,r2,r2
1478 movzbl 3(r1),r1 # orb2 sign extends
1479 orl2 r2,r1
1480 orl2 r1,r0
1481 ret
1482fserr:
1483 mnegl $1,r0
1484 ret
1485
a55e280b 1486ENTRY(fubyte, 0)
57a0bdb5
SL
1487 prober $1,*4(fp),$1
1488 beql fserr
1489 movzbl *4(fp),r0
1490 ret
1491
a55e280b 1492ENTRY(suword, 0)
57a0bdb5
SL
1493 movl 4(fp), r0
1494 probew $1,(r0),$4 # check access
1495 beql fserr # page unwritable
1496 bitl $1,r0 # check byte alignment
1497 bneq 1f # odd byte boundary
1498 bitl $2,r0 # check word alignment
1499 beql 2f # longword aligned
1500 movw 8(fp),(r0) # move two words
1501 movw 10(fp),2(r0)
1502 jbr 3f
15031:
1504 movb 8(fp),(r0)
1505 movb 9(fp),1(r0)
1506 movb 10(fp),2(r0)
1507 movb 11(fp),3(r0)
1508 jbr 3f
15092:
1510 movl 8(fp),(r0)
15113:
1512 clrl r0
1513 ret
1514
a55e280b 1515ENTRY(subyte, 0)
57a0bdb5
SL
1516 probew $1,*4(fp),$1
1517 beql fserr
1518 movb 11(fp),*4(fp)
1519 clrl r0
1520 ret
1521
1522/*
1523 * Copy 1 relocation unit (NBPG bytes)
1524 * from user virtual address to physical address
1525 */
a55e280b 1526ENTRY(copyseg, 0)
57a0bdb5
SL
1527 orl3 $PG_V|PG_KW,8(fp),_CMAP2
1528 mtpr $_CADDR2,$TBIS # invalidate entry for copy
a55e280b 1529 MOVC3(4(fp),$_CADDR2,$NBPG)
57a0bdb5
SL
1530 ret
1531
1532/*
a55e280b 1533 * Clear a page of memory. The page frame is specified.
57a0bdb5 1534 *
a55e280b 1535 * clearseg(pf);
57a0bdb5 1536 */
a55e280b 1537ENTRY(clearseg, 0)
57a0bdb5
SL
1538 orl3 $PG_V|PG_KW,4(fp),_CMAP1 # Maps to virtual addr CADDR1
1539 mtpr $_CADDR1,$TBIS
1540 movl $255,r0 # r0 = limit
1541 clrl r1 # r1 = index of cleared long
15421:
1543 clrl _CADDR1[r1]
1544 aobleq r0,r1,1b
1545 ret
1546
1547/*
a55e280b
SL
1548 * Check user mode read/write access.
1549 *
1550 * useracc(addr, count, mode)
1551 * caddr_t addr; int count, mode;
1552 * mode = 0 write access
1553 * mode = 1 read access
57a0bdb5 1554 */
a55e280b 1555ENTRY(useracc, 0)
57a0bdb5
SL
1556 movl $1,r2 # r2 = 'user mode' for probew/probew
1557probes:
1558 movl 4(fp),r0 # get va
1559 movl 8(fp),r1 # count
1560 tstl 12(fp) # test for read access ?
1561 bneq userar # yes
a55e280b 1562 cmpl $(CLSIZE*NBPG),r1 # can we do it in one probe ?
57a0bdb5
SL
1563 bgeq uaw2 # yes
1564uaw1:
a55e280b 1565 probew r2,(r0),$(CLSIZE*NBPG)
57a0bdb5 1566 beql uaerr # no access
a55e280b
SL
1567 addl2 $(CLSIZE*NBPG),r0
1568 _ACBL($(CLSIZE*NBPG+1),$(-CLSIZE*NBPG),r1,uaw1)
57a0bdb5
SL
1569uaw2:
1570 probew r2,(r0),r1
1571 beql uaerr
1572 movl $1,r0
1573 ret
57a0bdb5 1574userar:
a55e280b 1575 cmpl $(CLSIZE*NBPG),r1
57a0bdb5
SL
1576 bgeq uar2
1577uar1:
a55e280b 1578 prober r2,(r0),$(CLSIZE*NBPG)
57a0bdb5 1579 beql uaerr
a55e280b
SL
1580 addl2 $(CLSIZE*NBPG),r0
1581 _ACBL($(CLSIZE*NBPG+1),$(-CLSIZE*NBPG),r1,uar1)
57a0bdb5
SL
1582uar2:
1583 prober r2,(r0),r1
1584 beql uaerr
1585 movl $1,r0
1586 ret
1587uaerr:
1588 clrl r0
1589 ret
1590
1591/*
a55e280b
SL
1592 * Check kernel mode read/write access.
1593 *
1594 * kernacc(addr, count, mode)
1595 * caddr_t addr; int count, mode;
1596 * mode = 0 write access
1597 * mode = 1 read access
57a0bdb5 1598 */
a55e280b 1599ENTRY(kernacc, 0)
57a0bdb5
SL
1600 clrl r2 # r2 = 0 means kernel mode probe.
1601 jbr probes # Dijkstra would get gastric distress here.
1602
1603/*
1604 * addupc - increment some histogram counter
1605 * in the profiling buffer
1606 *
a55e280b
SL
1607 * addupc(pc, prof, delta)
1608 * long pc; short delta; struct uprof *prof;
57a0bdb5
SL
1609 *
1610 * struct uprof { # profile arguments
1611 * short *r_base; # buffer base
1612 * unsigned pr_size; # buffer size
1613 * unsigned pr_off; # pc offset
1614 * unsigned pr_scale; # pc scaling
1615 * }
1616 */
a55e280b
SL
1617ENTRY(addupc, 0)
1618 movl 8(fp),r2 # r2 points to structure
1619 subl3 8(r2),4(fp),r0 # r0 = PC - lowpc
1620 jlss 9f # PC < lowpc , out of range !
1621 shrl $1,r0,r0 # the unit is words
1622 shrl $1,12(r2),r1 # ditto for scale
57a0bdb5
SL
1623 emul r1,r0,$0,r0
1624 shrq $14,r0,r0
a55e280b 1625 tstl r0 # too big
57a0bdb5 1626 jneq 9f
a55e280b 1627 cmpl r1,4(r2) # Check buffer overflow
57a0bdb5
SL
1628 jgequ 9f
1629 probew $1,*0(r2)[r1],$2 # counter accessible?
1630 jeql 9f
a55e280b 1631 shrl $1,r1,r1 # make r1 word index
57a0bdb5
SL
1632 addw2 14(fp),*0(r2)[r1]
16339: ret
a55e280b
SL
1634
1635/*
1636 * scanc(size, cp, table, mask)
1637 */
1638ENTRY(scanc, R3|R4)
1639 movl 8(fp),r0 # r0 = cp
1640 addl3 4(fp),r0,r2 # end = &cp[size]
1641 movl 12(fp),r1 # r1 = table
1642 movb 19(fp),r4 # r4 = mask
1643 decl r0 # --cp
1644 jbr 0f # just like Fortran...
16451: # do {
1646 movzbl (r0),r3
1647 bitb r4,(r1)[r3] # if (table[*cp] & mask)
1648 jneq 2f # break;
16490: aoblss r2,r0,1b # } while (++cp < end);
16502:
1651 subl3 r0,r2,r0; ret # return (end - cp);
1652
1653/*
1654 * skpc(mask, size, cp)
1655 */
1656ENTRY(skpc, 0)
1657 movl 12(fp),r0 # r0 = cp
1658 addl3 8(fp),r0,r1 # r1 = end = &cp[size];
1659 movb 7(fp),r2 # r2 = mask
1660 decl r0 # --cp;
1661 jbr 0f
16621: # do
1663 cmpb (r0),r2 # if (*cp != mask)
1664 jneq 2f # break;
16650: aoblss r1,r0,1b # while (++cp < end);
16662:
1667 subl3 r0,r1,r0; ret # return (end - cp);
1668
a55e280b
SL
1669/*
1670 * locc(mask, size, cp)
1671 */
1672ENTRY(locc, 0)
1673 movl 12(fp),r0 # r0 = cp
1674 addl3 8(fp),r0,r1 # r1 = end = &cp[size]
1675 movb 7(fp),r2 # r2 = mask
1676 decl r0 # --cp;
1677 jbr 0f
16781: # do
1679 cmpb (r0),r2 # if (*cp == mask)
1680 jeql 2f # break;
16810: aoblss r1,r0,1b # while (++cp < end);
16822:
1683 subl3 r0,r1,r0; ret # return (end - cp);
44622fe3 1684
82bf8967 1685#ifdef ALIGN
44622fe3
SL
1686#include "../tahoealign/align.h"
1687
1688 .globl _alignment
1689/*
1690 * There's an intimate relationship between this piece of code
1691 * and the alignment emulation code (especially the layout
1692 * of local variables in alignment.c! Don't change unless
1693 * you update both this, alignment.h and alignment.c !!
1694 */
1695non_aligned:
1696 orb2 $EMULATEALIGN,_u+U_EOSYS
1697 incl _cnt+V_TRAP
1698 incl _cnt+V_ALIGN # count emulated alignment traps
1699 moval 4(sp),_user_psl
1700 SAVE_FPSTAT(4) # Also zeroes out ret_exception !
1701 pushl $0 # ret_addr
1702 pushl $0 # ret_code
1703 mfpr $USP,-(sp) # user sp
1704 callf $4,_alignment # call w/o parms so regs may be modified
1705 /*
1706 * We return here after a successful emulation or an exception.
1707 * The registers have been restored and we must not alter them
1708 * before returning to the user.
1709 */
17102: mtpr (sp)+,$USP # restore user sp
1711 tstl 8(sp) # Any exception ?
1712 bneq got_excp # Yes, reflect it back to user.
1713 moval 8(sp),sp # pop 2 zeroes pushed above
1714 REST_FPSTAT
1715 xorb2 $EMULATEALIGN,_u+U_EOSYS
1716
1717 bitl $PSL_T,4(sp) # check for trace bit set
1718 beql 9f
1719 CHECK_SFE(4)
1720 pushl $0
1721 SAVE_FPSTAT(8)
1722 TRAP(TRCTRAP)
17239: rei
1724
1725got_excp: # decode exception
1726 casel 8(sp),$ILL_ADDRMOD,$ALIGNMENT
1727 .align 1
1728L1:
1729 .word ill_addrmod-L1
1730 .word ill_access-L1
1731 .word ill_oprnd-L1
1732 .word arithmetic-L1
1733 .word alignment-L1
1734 brw alignment # default - shouldn't come here at all !
1735
1736ill_addrmod: # No other parameters. Set up stack as
1737 moval 8(sp),sp # the HW would do it in a real case.
1738 REST_FPSTAT
1739 jbr _Xresadflt
1740ill_oprnd:
1741 moval 8(sp),sp
1742 REST_FPSTAT
1743 jbr _Xresopflt
1744alignment:
1745 moval 8(sp),sp
1746 REST_FPSTAT
1747 jbr align_excp # NB: going to _Xalignflt would cause loop
1748ill_access:
1749 /*
1750 * Must restore accumulator w/o modifying sp and w/o using
1751 * registers. Solution: copy things needed by REST_FPSTAT.
1752 */
1753 pushl 20(sp) # The flags longword
1754 pushl 20(sp) # acc_low
1755 pushl 20(sp) # acc_high
1756 pushl 20(sp) # ret_exception ignored by REST_FPSTAT
1757 REST_FPSTAT # Back where we were with the sp !
1758 movl (sp),16(sp) # code for illegal access
1759 movl 4(sp),20(sp) # original virtual address
1760 moval 16(sp),sp # Just like the HW would set it up
1761 jbr _Xprotflt
1762arithmetic: # same trickery as above
1763 pushl 20(sp) # The flags longword
1764 pushl 20(sp) # acc_low
1765 pushl 20(sp) # acc_high
1766 pushl 20(sp) # ret_exception ignored by REST_FPSTAT
1767 REST_FPSTAT # Back where we were with the sp !
1768 movl (sp),20(sp) # code for arithmetic exception
1769 moval 20(sp),sp # Just like the HW would set it up
1770 jbr _Xarithtrap
1771#endif