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