|
|
1.1 root 1: /* locore.s 4.50 81/05/18 */
2: # -------------------
3:
4: #include "../machine/mtpr.h"
5: #include "../machine/trap.h"
6: #include "../machine/psl.h"
7: #include "../machine/pte.h"
8: #include "../machine/cp.h"
9: #include "../machine/mem.h"
10: #include "../machine/fp.h"
11:
12: #include "../h/errno.h"
13:
14: .set HIGH,0x1f # mask for total disable
15: .set BERVEC,0x80 # offset into scb of the bus error vector
16: .set RESTVEC,0x8 # offset into scb of the restart vector
17: .set MEMUNIT,64*1024 # minimum memory increment
18:
19: .set NISP,3 # number of interrupt stack pages
20: .set SYSTEM,0xC0000000 # virtual address of system start
21: .set PPAGES,0x100000 # Number of possible pages in P0,P1, etc.
22:
23: /* ACBL for non-negative '_add' */
24: #define ACBL(_limit,_add,_index,_displ) \
25: addl2 _add,_index; \
26: cmpl _index,_limit; \
27: bleq _displ
28:
29: /* _ACBL for negative '_add' */
30: #define _ACBL(_limit,_add,_index,_displ) \
31: addl2 _add,_index; \
32: cmpl _index,_limit; \
33: bgeq _displ
34:
35: #define MOVC3(_len,_srcaddr,_dstaddr) \
36: movl _srcaddr,r0; \
37: movl _dstaddr,r1; \
38: movl _len,r2; \
39: movblk
40:
41: /* Keep address of psl if coming from user mode */
42: #define CHECK_SFE(_delta) \
43: bitl $PSL_CURMOD,_delta(sp); \
44: jeql 1f; \
45: moval _delta(sp),_user_psl; \
46: 1:
47:
48: /*
49: * User structure is UPAGES at top of user space.
50: */
51: .globl _u
52: .set _u,SYSTEM - UPAGES*NBPG
53:
54: /*
55: * Restart stack. Used on power recovery or panic.
56: * Takes a core-dump and then halts.
57: */
58: .globl _rsstk
59:
60: _rsstk: .space 1024-8
61: .globl pwfl_stk
62: pwfl_stk: .space 4
63: dumpflag: .space 4
64:
65: .globl _intstack
66: _intstack:
67: .space NISP*NBPG
68: eintstack:
69:
70: .data
71: .globl pwfl_r0
72: pwfl_r0: .space 14*4 # Enough for r0 - r13
73: .globl pwfl_sp
74: pwfl_sp: .long 0x12345678 # r14
75: .globl pwfl_SCBB
76: pwfl_SCBB: .long 0x12345678
77: .globl pwfl_SBR
78: pwfl_SBR: .long 0x12345678
79: .globl pwfl_SLR
80: pwfl_SLR: .long 0x12345678
81: .globl pwfl_P0BR
82: pwfl_P0BR: .long 0x12345678
83: .globl pwfl_P0LR
84: pwfl_P0LR: .long 0x12345678
85: .globl pwfl_P1BR
86: pwfl_P1BR: .long 0x12345678
87: .globl pwfl_P1LR
88: pwfl_P1LR: .long 0x12345678
89: .globl pwfl_P2BR
90: pwfl_P2BR: .long 0x12345678
91: .globl pwfl_P2LR
92: pwfl_P2LR: .long 0x12345678
93: .globl pwfl_IPL
94: pwfl_IPL: .long 0x12345678
95: .globl pwfl_DCK
96: pwfl_DCK: .long 0x12345678
97: .globl pwfl_CCK
98: pwfl_CCK: .long 0x12345678
99: .globl pwfl_PCBB
100: pwfl_PCBB: .long 0x12345678
101: .globl pwfl_ISP
102: pwfl_ISP: .long 0x12345678
103: .globl pwfl_KSP
104: pwfl_KSP: .long 0x12345678
105: .globl pwfl_USP
106: pwfl_USP: .long 0x12345678
107: .globl pwfl_MME
108: pwfl_MME: .long 0x12345678
109: .globl pwfl_PSL
110: pwfl_PSL: .long 0x12345678
111:
112: /*
113: * Do a dump.
114: * Called by auto-restart.
115: * May be called manually.
116: */
117: .align 2
118: .text
119: .globl _Xdoadump
120: .globl _doadump
121: _Xdoadump: # CP brings Tahoe here on power recovery
122: loadr $0x3fff,pwfl_r0 # Restore r0 - r13
123: movl pwfl_sp,sp # Restore sp ( = r14 )
124: mtpr pwfl_SCBB,$SCBB
125: mtpr pwfl_SBR,$SBR # Restore all re_loadable registers
126: mtpr pwfl_SLR,$SLR
127: mtpr pwfl_P0BR,$P0BR
128: mtpr pwfl_P0LR,$P0LR
129: mtpr pwfl_P1BR,$P1BR
130: mtpr pwfl_P1LR,$P1LR
131: mtpr pwfl_P2BR,$P2BR
132: mtpr pwfl_P2LR,$P2LR
133: mtpr pwfl_IPL,$IPL
134: mtpr pwfl_DCK,$DCK
135: mtpr pwfl_CCK,$CCK
136: mtpr pwfl_PCBB,$PCBB
137: mtpr pwfl_ISP,$ISP
138: mtpr pwfl_KSP,$KSP
139: mtpr pwfl_USP,$USP
140:
141: bicpsw $0xff # Restore PSW.
142: bispsw pwfl_PSL+2 # Set original bits back (just in case..)
143: /* now go to mapped mode */
144: /* Have to change PC to system addresses */
145: mtpr $1,$PACC # Thoroughly clean up caches.
146: mtpr $1,$PADC
147: mtpr $1,$TBIA
148: mtpr pwfl_MME,$MME # Restore MME. Last thing to be done.
149: jmp *$0f
150: _doadump:
151: .word 0
152: #define _rsstkmap _Sysmap+12
153: # Tahoe storage, scb, rsstk, interrupt stack
154: 0:
155: mtpr $HIGH,$IPL
156: andl2 $0!PG_PROT,_rsstkmap
157: orl2 $PG_KW,_rsstkmap # Make dump stack r/w
158: tstl dumpflag # dump only once!
159: bneq 1f
160: movl $1,dumpflag
161: mtpr $0,$TBIA
162: movab dumpflag,sp
163: callf $4,_dumpsys
164: 1:
165: halt
166:
167: /*
168: * Interrupt vector routines
169: */
170: .globl _waittime
171:
172: #define SCBVEC(name) \
173: .align 2; \
174: .globl _X/**/name; \
175: _X/**/name
176: #define PANIC(msg) clrl _waittime; pushab 1f; \
177: callf $8,_panic; 1: .asciz msg
178: #define PRINTF(n,msg) pushab 1f; callf $(n*4)+4,_printf; MSG(msg)
179: #define MSG(msg) .data; 1: .asciz msg; .text
180:
181: # these registers are not restored by the C-compiler.
182: #define PUSHR pushl r0; pushl r1;
183: #define POPR movl (sp)+, r1; movl (sp)+, r0;
184: # mask for error code on stack.
185:
186: #define SAVE_FPSTAT(_delta) bitl $PSL_DBL,_delta(sp); \
187: beql 1f; \
188: pushl $1; \
189: pushd; \
190: jmp 2f; \
191: 1: pushl $0; \
192: pushl $0; \
193: stf -(sp); \
194: 2: tstl _u+PCB_SAVACC; \
195: bneq 3f; \
196: moval 0(sp),_u+PCB_SAVACC; \
197: orl2 $2,8(sp);\
198: 3: pushl $0;
199:
200: #define REST_FPSTAT tstl (sp)+; \
201: bitl $2,8(sp);\
202: beql 1f;\
203: movl $0,_u+PCB_SAVACC; \
204: 1: bitl $1,8(sp); \
205: beql 2f; \
206: ldd (sp); \
207: jmp 3f; \
208: 2: ldf (sp); \
209: 3: moval 12(sp),sp;
210:
211: #define REST_ACC tstl _u+PCB_SAVACC; \
212: beql 2f; \
213: movl _u+PCB_SAVACC,r1; \
214: andl3 $(EXPMASK|SIGNBIT),(r1),-(sp); \
215: cmpl $0x80000000,(sp)+; \
216: bneq 3f; \
217: clrl (r1); \
218: 3: bitl $1,8(r1); \
219: beql 1f; \
220: ldd (r1); \
221: jmp 2f; \
222: 1: ldf (r1); \
223: 2: ;
224:
225: #define PUSHBPAR pushab 6*4(sp) /* Push address of buserr paramters */
226: #define BPAR1 28 /* Offset to first hardware parameter */
227:
228: SCBVEC(buserr):
229: CHECK_SFE(12)
230: SAVE_FPSTAT(12);
231: PUSHR
232: andl3 BPAR1(sp),$ERRCD,r0
233: jeql go_on
234: cmpl r0,$APE
235: jneq 1f
236: halt # Address parity error !!!
237: 1: cmpl r0,$VBE
238: jneq go_on
239: halt # Versabus error !!!
240: go_on:
241: PUSHBPAR # Pointer to parameters
242: callf $8,_buserror
243: POPR
244: REST_FPSTAT;
245: movab 8(sp),sp # Remove hardware parameters
246: rei
247:
248: SCBVEC(powfail): # We should be on interrupt stack now.
249: movpsl pwfl_PSL # Keeps all flags, etc.
250: storer $0x3fff,pwfl_r0 # Saves r0 - r13
251: moval 0(sp),pwfl_sp # Saves sp ( = r14 )
252: mfpr $SBR,pwfl_SBR # Save all re_loadable registers
253: mfpr $SLR,pwfl_SLR
254: mfpr $P0BR,pwfl_P0BR
255: mfpr $P0LR,pwfl_P0LR
256: mfpr $P1BR,pwfl_P1BR
257: mfpr $P1LR,pwfl_P1LR
258: mfpr $P2BR,pwfl_P2BR
259: mfpr $P2LR,pwfl_P2LR
260: mfpr $IPL,pwfl_IPL
261: mfpr $MME,pwfl_MME
262: mfpr $DCK,pwfl_DCK
263: mfpr $CCK,pwfl_CCK
264: mfpr $PCBB,pwfl_PCBB
265: mfpr $ISP,pwfl_ISP
266: mfpr $SCBB,pwfl_SCBB
267: mfpr $KSP,pwfl_KSP
268: mfpr $USP,pwfl_USP
269: moval _Xdoadump-SYSTEM,_scb+RESTVEC
270: halt
271:
272: SCBVEC(stray):
273: PUSHR;
274: movpsl r0
275: shrl $16, r0,-(sp)
276: andl2 $0x1f, (sp)
277: PRINTF(2, "******* Undefined interrupt at ipl 0x%x *******\n");
278: POPR;
279: rei
280:
281: #include "../net/netisr.h"
282: .globl _netisr
283: SCBVEC(netintr):
284: CHECK_SFE(4)
285: SAVE_FPSTAT(4)
286: PUSHR
287:
288: bbc $NETISR_RAW,_netisr,1f
289: andl2 $(0!(1<<NETISR_RAW)),_netisr
290: callf $4,_rawintr
291: 1:
292: #ifdef INET
293: #include "../netinet/in_systm.h"
294: bbc $NETISR_IP,_netisr,1f
295: andl2 $(0!(1<<NETISR_IP)),_netisr
296: callf $4,_ipintr
297: 1:
298: #endif
299: #ifdef NS
300: bbc $NETISR_NS,_netisr,1f
301: andl2 $(0!(1<<NETISR_NS)),_netisr
302: callf $4,_nsintr
303: 1:
304: #endif
305: POPR;
306: REST_FPSTAT
307: rei
308: SCBVEC(soft15):
309: SCBVEC(soft14):
310: SCBVEC(soft13):
311: SCBVEC(soft11):
312: SCBVEC(soft10):
313: #ifndef SIMIO
314: SCBVEC(soft9):
315: #endif
316: SCBVEC(soft7):
317: SCBVEC(soft6):
318: SCBVEC(soft5):
319: SCBVEC(soft4):
320: #ifndef SIMIO
321: SCBVEC(soft3):
322: SCBVEC(soft2):
323: SCBVEC(soft1):
324: #endif
325: PUSHR
326: PRINTF(1, "******* Undefined software interrupt *******\n")
327: POPR;
328: rei
329:
330: #ifdef SIMIO
331: SCBVEC(soft2):
332: #endif
333: SCBVEC(cnrint):
334: CHECK_SFE(4)
335: SAVE_FPSTAT(4);PUSHR;
336: pushl $CPCONS; callf $8,_cnrint; POPR; incl _cnt+V_INTR;
337: REST_FPSTAT; rei
338: #ifdef SIMIO
339: SCBVEC(soft3):
340: #endif
341: SCBVEC(cnxint):
342: CHECK_SFE(4)
343: SAVE_FPSTAT(4);PUSHR;
344: pushl $CPCONS; callf $8,_cnxint; POPR; REST_FPSTAT;
345: incl _cnt+V_INTR; rei
346: SCBVEC(rmtrint):
347: CHECK_SFE(4)
348: SAVE_FPSTAT(4); PUSHR;
349: pushl $CPREMOT; callf $8,_cnrint; POPR; REST_FPSTAT;
350: incl _cnt+V_INTR; rei
351: SCBVEC(rmtxint):
352: CHECK_SFE(4)
353: SAVE_FPSTAT(4); PUSHR;
354: pushl $CPREMOT; callf $8,_cnxint; POPR; REST_FPSTAT;
355: incl _cnt+V_INTR; rei
356: #ifdef SIMIO
357: SCBVEC(soft9):
358: #endif
359:
360: #define PUSHPCPSL pushl 5*4+2*4(sp); pushl 5*4+2*4(sp);
361:
362: SCBVEC(hardclock):
363: CHECK_SFE(4)
364: SAVE_FPSTAT(4)
365: PUSHR
366: PUSHPCPSL # push pc and psl
367: callf $12,_hardclock # hardclock(pc,psl)
368: POPR;
369: REST_FPSTAT
370: incl _cnt+V_INTR ## temp so not to break vmstat -= HZ
371: rei
372: SCBVEC(softclock):
373: CHECK_SFE(4)
374: SAVE_FPSTAT(4)
375: PUSHR
376: PUSHPCPSL # push pc and psl
377: callf $12,_softclock # softclock(pc,psl)
378: POPR;
379: REST_FPSTAT
380: rei
381:
382: /*
383: * Trap and fault vector routines
384: */
385: #define TRAP(a) pushl $T_/**/a; jbr alltraps
386:
387: /*
388: * Ast delivery (profiling and/or reschedule)
389: */
390: /*
391: * When we want to reschedule we will force a memory fault by setting the m.s.b
392: * of P0LR. Then , on memory fault if m.s.b of P0LR is on we will clear it and
393: * TRAP(astflt).
394: *
395: */
396:
397: # if this bit is on it is an ast.
398: #define ASTBIT 0x00100000
399: #define P0MASK 0xc0000000
400:
401: SCBVEC(kspnotval):
402: CHECK_SFE(4)
403: pushl $0;
404: SAVE_FPSTAT(8)
405: TRAP(KSPNOTVAL)
406: SCBVEC(privinflt):
407: CHECK_SFE(4)
408: pushl $0;
409: SAVE_FPSTAT(8)
410: TRAP(PRIVINFLT)
411: SCBVEC(resopflt):
412: CHECK_SFE(4)
413: pushl $0;
414: SAVE_FPSTAT(8)
415: TRAP(RESOPFLT)
416: SCBVEC(resadflt):
417: CHECK_SFE(4)
418: pushl $0;
419: SAVE_FPSTAT(8)
420: TRAP(RESADFLT)
421: SCBVEC(bptflt):
422: CHECK_SFE(4)
423: pushl $0;
424: SAVE_FPSTAT(8)
425: TRAP(BPTFLT)
426: SCBVEC(tracep):
427: CHECK_SFE(4)
428: pushl $0;
429: SAVE_FPSTAT(8)
430: TRAP(TRCTRAP)
431: SCBVEC(alignflt):
432: CHECK_SFE(4)
433: pushl $0;
434: SAVE_FPSTAT(8)
435: TRAP(ALIGNFLT)
436: SCBVEC(arithtrap):
437: CHECK_SFE(8)
438: SAVE_FPSTAT(8)
439: TRAP(ARITHTRAP)
440:
441: SCBVEC(protflt):
442: CHECK_SFE(12)
443: bitl $1,(sp)+
444: jneq segflt
445: SAVE_FPSTAT(8)
446: TRAP(PROTFLT)
447: segflt:
448: SAVE_FPSTAT(8)
449: TRAP(SEGFLT)
450:
451: SCBVEC(fpm): # Floating Point eMulation
452: .globl _fpemulate
453: CHECK_SFE(16)
454: SAVE_FPSTAT(16)
455: callf $4,_fpemulate
456: REST_FPSTAT
457: moval 8(sp),sp # Pop operand
458: tstl (sp) # Stack= PSL, PC, return_code
459: jneq _Xarithtrap # If not OK, emulate F.P. exception
460: movab 4(sp),sp # Else remove return_code and
461: rei
462:
463: SCBVEC(sfexcep):
464: CHECK_SFE(4)
465: pushl $0
466: SAVE_FPSTAT(8)
467: TRAP(ASTFLT)
468:
469: SCBVEC(transflt):
470: CHECK_SFE(12)
471: bitl $1,(sp)+
472: bneq tableflt
473: pageflt:
474: SAVE_FPSTAT(8)
475: TRAP(PAGEFLT)
476: tableflt:
477: SAVE_FPSTAT(8)
478: TRAP(TABLEFLT)
479:
480: #define REST_STACK movab 4(sp), sp; REST_FPSTAT; movab 4(sp), sp
481:
482: alltraps:
483: mfpr $USP,-(sp);
484: callf $4,_trap; mtpr (sp)+,$USP
485: incl _cnt+V_TRAP
486: REST_STACK # pop type, code, an fp stuff
487: mtpr $HIGH,$IPL ## dont go to a higher IPL (GROT)
488: rei
489:
490: SCBVEC(syscall):
491: CHECK_SFE(8)
492: SAVE_FPSTAT(8)
493: pushl $T_SYSCALL
494: mfpr $USP,-(sp); callf $4,_syscall; mtpr (sp)+,$USP
495: incl _cnt+V_SYSCALL
496: REST_STACK # pop type, code, an fp stuff
497: mtpr $HIGH,$IPL ## dont go to a higher IPL (GROT)
498: rei
499:
500: /*
501: * System page table
502: */
503: #define vaddr(x) ((((x)-_Sysmap)/4)*NBPG+SYSTEM)
504: #define SYSMAP(mname, vname, npte) \
505: _/**/mname: .globl _/**/mname; \
506: .space npte*4; \
507: .globl _/**/vname; \
508: .set _/**/vname,vaddr(_/**/mname)
509:
510: .data
511: .align 2
512: SYSMAP(Sysmap ,Sysbase ,SYSPTSIZE )
513: SYSMAP(VMEMbeg ,vmembeg ,0 )
514: SYSMAP(VMEMmap ,vmem ,IOSIZE )
515: SYSMAP(ACE0map ,ace0utl ,(ACEBPTE+1) )
516: SYSMAP(ACE1map ,ace1utl ,(ACEBPTE+1) )
517: SYSMAP(VMEMend ,vmemend ,0 )
518: SYSMAP(Usrptmap ,usrpt ,USRPTSIZE )
519: SYSMAP(Forkmap ,forkutl ,UPAGES )
520: SYSMAP(Xswapmap ,xswaputl ,UPAGES )
521: SYSMAP(Xswap2map,xswap2utl ,UPAGES )
522: SYSMAP(Swapmap ,swaputl ,UPAGES )
523: SYSMAP(Pushmap ,pushutl ,UPAGES )
524: SYSMAP(Vfmap ,vfutl ,UPAGES )
525: SYSMAP(VD0map ,vd0utl ,(MAXBPTE+1) )
526: SYSMAP(VD1map ,vd1utl ,(MAXBPTE+1) )
527: SYSMAP(VD2map ,vd2utl ,(MAXBPTE+1) )
528: SYSMAP(VD3map ,vd3utl ,(MAXBPTE+1) )
529: SYSMAP(CY0map ,cy0utl ,(TBUFSIZ+1) )
530: SYSMAP(CY1map ,cy1utl ,(TBUFSIZ+1) )
531: SYSMAP(CMAP1 ,CADDR1 ,1 )
532: SYSMAP(CMAP2 ,CADDR2 ,1 )
533: SYSMAP(mmap ,vmmap ,1 )
534: SYSMAP(msgbufmap,msgbuf ,MSGBUFPTECNT )
535: SYSMAP(camap ,cabase ,16*CLSIZE )
536: SYSMAP(ecamap ,calimit ,0 )
537: SYSMAP(Mbmap ,mbutl ,NMBCLUSTERS*CLSIZE)
538: SYSMAP(Msgmap ,msgutl ,MSGMAPPTE)
539: eSysmap:
540: .globl _Syssize
541: .set _Syssize,(eSysmap-_Sysmap)/4
542:
543: .text
544: /*
545: * Initialization
546: *
547: * IPL 0x1f; MME 0; scbb, pcbb, sbr, slr, isp, ksp not set
548: *
549: */
550:
551: .align 2
552: .globl start
553: start:
554: .word 0
555:
556: /* set system control block base and system page table params */
557:
558: mtpr $_scb-SYSTEM,$SCBB
559: mtpr $_Sysmap-SYSTEM,$SBR
560: mtpr $_Syssize,$SLR
561:
562: /* double map the kernel into the virtual user addresses of phys mem */
563: /* (to be on the safe side.This is supposed to run in system sace. ) */
564: mtpr $_Sysmap,$P0BR
565: mtpr $_Syssize,$P0LR
566:
567: mtpr $_Sysmap,$P1BR # Against Murphy
568: mtpr $_Syssize,$P1LR
569:
570: /* set ISP */
571: movl $_intstack-SYSTEM+NISP*NBPG,sp # Still physical !
572: mtpr $_intstack+NISP*NBPG,$ISP
573:
574: /* count up memory */
575:
576: clrl r7
577: 1: pushl $1; pushl r7; callf $12,_badaddr; tstl r0; bneq 9f
578: addl2 $MEMUNIT,r7
579: brb 1b
580: 9:
581: /* clear memory from kernel bss and pages for proc 0 u. and page table */
582: movab _edata,r6
583: movab _end,r5
584: andl2 $0!SYSTEM,r6
585: andl2 $0!SYSTEM,r5
586: addl2 $(UPAGES*NBPG)+NBPG+NBPG,r5
587: 1: clrl (r6); ACBL( r5,$4,r6,1b)
588:
589: /* trap() and syscall() save r0-r13 in the entry mask (per ../h/reg.h) */
590: /* For floating point emulation, we do same for 'fpemulate' */
591: orw2 $0x01fff,_trap
592: orw2 $0x01fff,_syscall
593: orw2 $0x01fff,_fpemulate
594:
595: /* initialize system page table: scb and int stack writeable */
596: clrl r2
597: movab eintstack,r1
598: andl2 $0!SYSTEM,r1
599: shrl $PGSHIFT,r1,r1 # r1-page number of eintstack.
600:
601: /* Start by making the processor storage read/only */
602:
603: orl3 $PG_V|PG_KR,r2,_Sysmap[r2]; incl r2;
604: orl3 $PG_V|PG_KR,r2,_Sysmap[r2]; incl r2;
605:
606: /* Other parts of the system are read/write for kernel */
607:
608: 1: orl3 $PG_V|PG_KW,r2,_Sysmap[r2]; # data:kernel write + phys=virtual
609: aoblss r1,r2,1b
610:
611: /* make rsstk read-only as red zone for interrupt stack */
612: andl2 $0!PG_PROT,_rsstkmap
613: orl2 $PG_V|PG_KR,_rsstkmap # Make dump stack r/w
614:
615: /* make kernel text space read-only */
616: /*
617: * HAVE TO CHECK ALL THE MAGIC CONSTANTS USED HERE : $xxxxxx */
618:
619: movab _etext+NBPG-1,r1
620: andl2 $0!SYSTEM,r1
621: shrl $PGSHIFT,r1,r1
622: 1: orl3 $PG_V|PG_KR,r2,_Sysmap[r2]
623: aoblss r1,r2,1b
624:
625: /* make kernel data, bss, read-write */
626: movab _end+NBPG-1,r1
627: andl2 $0!SYSTEM,r1
628: shrl $PGSHIFT,r1,r1
629: 1: orl3 $PG_V|PG_KW,r2,_Sysmap[r2]
630: aoblss r1,r2,1b
631:
632: /* now go to mapped mode */
633: /* Have to change both PC and SP to system addresses */
634: mtpr $1,$TBIA
635: mtpr $1,$PADC /* needed by HW parity & ECC logic */
636: mtpr $1,$PACC /* just in case */
637: mtpr $1,$MME
638: movab SYSTEM(sp),sp
639: .globl go_virt
640: go_virt:
641: jmp *$0f
642: 0:
643:
644: /* disable any interrupts */
645: movl $0,_intenable
646: /* init mem sizes */
647: shrl $PGSHIFT,r7,_maxmem
648: movl _maxmem,_physmem
649: movl _maxmem,_freemem
650:
651: /* setup context for proc[0] == Scheduler */
652: movab _end-SYSTEM+NBPG-1,r6
653: andl2 $0!(NBPG-1),r6 # make page boundary
654:
655: /* setup page table for proc[0] */
656: shrl $PGSHIFT,r6,r3 # r3 = btoc(r6)
657: orl3 $PG_V|PG_KW,r3,_Usrptmap # init first upt entry
658: incl r3 # r3 - next page
659: movab _usrpt,r0 # r0 - first user page
660: mtpr r0,$TBIS
661:
662: /* init p0br, p0lr */
663: mtpr r0,$P0BR # No P0 for proc[0]
664: mtpr $0,$P0LR
665:
666: mtpr r0,$P1BR # No P1 either
667: mtpr $0,$P1LR
668:
669:
670: /* init p2br, p2lr */
671: movab NBPG(r0),r0
672: movl $PPAGES-UPAGES,r1
673: mtpr r1,$P2LR
674: moval -4*PPAGES(r0),r2
675: mtpr r2,$P2BR
676:
677: /* setup mapping for UPAGES of _u */
678: clrl r2;
679: movl $SYSTEM,r1
680: addl2 $UPAGES,r3
681: jbr 2f
682: 1: decl r3
683: moval -NBPG(r1),r1; # r1 = virtual add of next (downward) _u page
684: subl2 $4,r0 # r0 = pte address
685: orl3 $PG_V|PG_URKW,r3,(r0)
686: mtpr r1,$TBIS
687: 2: aobleq $UPAGES,r2,1b
688:
689: /* initialize (slightly) the pcb */
690: movab UPAGES*NBPG(r1),PCB_KSP(r1) # KSP starts at end of _u
691: movl r1,PCB_USP(r1) # USP starts just below _u
692: mfpr $P0BR,PCB_P0BR(r1)
693: mfpr $P0LR,PCB_P0LR(r1)
694: mfpr $P1BR,PCB_P1BR(r1)
695: mfpr $P1LR,PCB_P1LR(r1)
696: mfpr $P2BR,PCB_P2BR(r1)
697: mfpr $P2LR,PCB_P2LR(r1)
698: movl $CLSIZE,PCB_SZPT(r1) # init u.u_pcb.pcb_szpt
699: movl r11,PCB_R11(r1) # r11 obtained from CP on boot
700: movab 1f,PCB_PC(r1) # initial pc
701: clrl PCB_PSL(r1) # kernel mode, ipl=0
702: shll $PGSHIFT,r3,r3
703: mtpr r3,$PCBB # first pcbb (physical ! )
704:
705: /* Go to a 'normal' process mode (kernel) */
706:
707: ldpctx
708: rei # Actually 'returns' to the next instruction:
709:
710: /* put signal trampoline code in u. area */
711: 1: movab _u,r0
712: movl sigcode+0,PCB_SIGC+0(r0)
713: movl sigcode+4,PCB_SIGC+4(r0)
714: movl sigcode+8,PCB_SIGC+8(r0)
715: movl sigcode+12,PCB_SIGC+12(r0)
716:
717: /* save reboot flags in global _boothowto */
718: movl r11,_boothowto
719:
720: /* calculate firstaddr, and call main() */
721: movab _end-SYSTEM+NBPG-1,r0
722: shrl $PGSHIFT,r0,-(sp)
723: addl2 $UPAGES+1,(sp) # First physical unused page number
724: callf $8,_main
725:
726: /* proc[1] == /etc/init now running here in kernel mode; run icode */
727: pushl $PSL_CURMOD # User mode PSL
728: pushl $0 # PC = 0 (virtual now)
729: rei
730:
731: /* signal trampoline code: it is known that this code takes up to 16 */
732: /* bytes in pcb.h and in the code above */
733: /* The following user stack layout was set up by machdep.c/sendsig */
734: /* routine: */
735: /* */
736: /* +---------------+ */
737: /* | Last PSL |\ */
738: /* +---------------+ > for rei */
739: /* :-->| Last PC |/ */
740: /* | +---------------+ */
741: /* :___|__* SP |\ */
742: /* +---------------+ | */
743: /* | sigmask | | */
744: /* +---------------+ > cleaned by kcall $139 (sigcleanup) */
745: /* :-->| u.u_onstack | | */
746: /* | +---------------+ | */
747: /* :___|_* copy of SCP |/ */
748: /* | +---------------+ */
749: /* | | Process' r0 | */
750: /* | +---------------+ */
751: /* | | Process' r1 | */
752: /* | +---------------+ */
753: /* | | Handler addr. |\ */
754: /* | +---------------+ | */
755: /* :___|_* SCP | | */
756: /* +---------------+ > cleaned by ret from calls */
757: /* | u.u_code | | */
758: /* +---------------+ | */
759: /* | signal number|/ */
760: /* +---------------+ */
761: /* */
762: /* * Stack when entering sigcode; setup by sendsig(); */
763: /* */
764: .align 2
765: sigcode: # When the process executes this code
766: # (located in its u. structure), it
767: # is in user mode !
768: calls $4*4+4,*12(sp) # 4 words popped from stack when this call returns
769: movl (sp)+,r1
770: movl (sp)+,r0
771: kcall $139 # Signal cleanup
772: rei # From user mode to user mode !
773:
774: /*
775: * Primitives
776: */
777:
778: /*
779: * badaddr(addr, len)
780: * see if access addr with a len type instruction causes a machine check
781: * len is length of access (1=byte, 2=short, 4=long)
782: * r0 = 0 means good(exists); r0 =1 means does not exist.
783: */
784: .globl _badaddr
785: _badaddr:
786: .word 0x1c # Keep r4,r3,r2
787: mfpr $IPL,r1
788: mtpr $HIGH,$IPL
789: movl _scb+BERVEC,r2
790: movl 4(fp),r3
791: movl 8(fp),r4
792: movab 9f,_scb+BERVEC
793: bbc $0,r4,1f; tstb (r3)
794: 1: bbc $1,r4,1f; tstw (r3)
795: 1: bbc $2,r4,1f; tstl (r3)
796: 1: clrl r0 # made it w/o machine checks
797: 2: movl r2,_scb+BERVEC
798: mtpr r1,$IPL
799: ret
800:
801: .align 2
802: 9: # Here we catch buss error (if it comes)
803: andl3 4(sp),$ERRCD,r0
804: cmpl r0,$APE
805: jneq 1f
806: halt # Address parity error !!!
807: 1: cmpl r0,$VBE
808: jneq 1f
809: halt # Versabus error
810: 1:
811: movl $1,r0 # Anything else = bad address
812: movab 8(sp),sp # discard buss error trash
813: movab 2b,(sp) # new program counter on stack.
814: rei
815:
816:
817: /*
818: * badcyaddr(addr)
819: * see if access tape master controller addr causes a bus error
820: * r0 = 0: no error; r0 = 1: timeout error.
821: */
822: .globl _badcyaddr
823: _badcyaddr:
824: .word 0x0c # Keep r3,r2
825: mfpr $IPL,r1
826: mtpr $HIGH,$IPL
827: movl _scb+BERVEC,r2
828: clrl r3
829: movab 9f,_scb+BERVEC
830: movob $-1, *4(fp)
831: 1: aobleq $1000, r3, 1b
832: clrl r0 # made it w/o machine checks
833: 2: movl r2,_scb+BERVEC
834: mtpr r1,$IPL
835: ret
836:
837: .align 2
838: 9: # Here we catch buss error (if it comes)
839: andl3 4(sp),$ERRCD,r0
840: cmpl r0,$APE
841: jneq 1f
842: halt # Address parity error !!!
843: 1: cmpl r0,$VBE
844: jneq 1f
845: halt # Versabus error
846: 1:
847: movl $1,r0 # Anything else = timeout
848: movab 8(sp),sp # discard buss error trash
849: movab 2b,(sp) # new program counter on stack.
850: rei
851:
852: _bcopy: .globl _bcopy
853: .word 0x4 # save r2
854: # Called by ovbcopy(from,dst,len)
855: movl 4(fp),r0
856: movl 8(fp),r1
857: movl 12(fp),r2
858: movblk
859: ret
860:
861: _ovbcopy: .globl _ovbcopy
862: .word 0x001c
863: movl 4(fp),r0
864: movl 8(fp),r1
865: movl 12(fp),r2
866: cmpl r0,r1
867: bgtru 1f # normal forward case
868: beql 2f # equal, nothing to do
869: addl2 r2,r0 # may be overlapping
870: cmpl r0,r1
871: bgtru 3f
872: subl2 r2,r0 # normal forward case
873: 1:
874: movblk
875: 2:
876: ret
877: 3:
878: addl2 r2,r1 # overlapping, must do backwards
879: subl3 r0,r1,r3
880: movl r2,r4
881: jbr 5f
882: 4:
883: subl2 r3,r0
884: subl2 r3,r1
885: movl r3,r2
886: movblk
887: subl2 r3,r0
888: subl2 r3,r1
889: subl2 r3,r4
890: 5:
891: cmpl r4,r3
892: jgtr 4b
893: movl r4,r2
894: subl2 r2,r0
895: subl2 r2,r1
896: movblk
897: ret
898:
899: /*
900: * bzero (base, count)
901: * zero out a block starting at 'base', size 'count'.
902: */
903: _bzero:
904: .globl _bzero
905: .word 0x4
906: movl $1f,r0 # r0 = null source string
907: movl 4(fp),r1 # r1 = destination address
908: movl 8(fp),r2 # r2 = count
909: movs3
910: ret
911: 1:
912: .byte 0
913:
914:
915: _copyin: .globl _copyin # the _Copyin subroutine in VAX
916: # became _copyin procedure for TAHOE
917: .word 0x0004
918: movl 12(fp),r0 # copy length
919: blss ersb
920: movl 4(fp),r1 # copy user address
921: cmpl $NBPG,r0 # probing one page or less ?
922: bgeq cishort # yes
923: ciloop:
924: prober $1,(r1),$NBPG # bytes accessible ?
925: beql ersb # no
926: addl2 $NBPG,r1 # incr user address ptr
927: _ACBL ($NBPG+1,$-NBPG,r0,ciloop) # reduce count and loop
928: cishort:
929: prober $1,(r1),r0 # bytes accessible ?
930: beql ersb # no
931: MOVC3 (12(fp),4(fp),8(fp))
932: clrl r0
933: ret
934:
935: ersb:
936: movl $EFAULT,r0
937: ret
938:
939: _copyout: .globl _copyout # the _Copyout subroutine in VAX
940: # became _copyout procedure for TAHOE
941: .word 0x04
942: movl 12(fp),r0 # get count
943: blss ersb
944: movl 8(fp),r1 # get user address
945: cmpl $NBPG,r0 # can do in one probew?
946: bgeq coshort # yes
947: coloop:
948: probew $1,(r1),$NBPG # bytes accessible?
949: beql ersb # no
950: addl2 $NBPG,r1 # increment user address
951: _ACBL ($NBPG+1,$-NBPG,r0,coloop) # reduce count and loop
952: coshort:
953: probew $1,(r1),r0 # bytes accessible?
954: beql ersb # no
955: MOVC3 (12(fp),4(fp),8(fp))
956: clrl r0
957: ret
958:
959: /*
960: * non-local goto's
961: */
962: .globl _setjmp # the _Setjmp subroutine in VAX
963: # became _setjmp procedure for TAHOE
964: _setjmp:
965: .word 0x0
966: movl 4(fp),r2
967: storer $0x1ff8,(r2)
968: addl2 $40,r2
969: movl (fp),(r2)
970: addl2 $4,r2
971: movab 8(fp),(r2)
972: addl2 $4,r2
973: movl -8(fp),(r2)
974: clrl r0
975: ret
976:
977: .globl _longjmp # the _Longjmp subroutine in VAX
978: # became _longjmp procedure for TAHOE
979: _longjmp:
980: .word 0x0000
981: movl 4(fp),r2
982: _Longjmp: # called from swtch
983: loadr $0x3ff8,(r2)
984: addl2 $44,r2
985: movl (r2),r1
986: addl2 $4,r2
987: movab (sp),r0
988: cmpl r1,r0 # must be a pop
989: bgequ lj2
990: pushab lj1
991: callf $8,_panic
992: lj2:
993: movl r1,sp
994: jmp *(r2)
995:
996: lj1: .asciz "longjmp"
997:
998:
999: .globl _whichqs
1000: .globl _qs
1001: .globl _cnt
1002:
1003: .globl _noproc
1004: .comm _noproc,4
1005: .globl _runrun
1006: .comm _runrun,4
1007:
1008: /*
1009: * The following primitives use the fancy TAHOE instructions.
1010: * _whichqs tells which of the 32 queues _qs
1011: * have processes in them. setrq puts processes into queues, remrq
1012: * removes them from queues. The running process is on no queue,
1013: * other processes are on a queue related to p->p_pri, divided by 4
1014: * actually to shrink the 0-127 range of priorities into the 32 available
1015: * queues.
1016: */
1017:
1018: /*
1019: * setrq(p), using fancy TAHOE instructions.
1020: *
1021: * Call should be made at spl8(), and p->p_stat should be SRUN
1022: */
1023: .globl _setrq
1024: _setrq:
1025: .word 0x4
1026: movl 4(fp),r0
1027: tstl P_RLINK(r0) ## firewall: p->p_rlink must be 0
1028: beql set1 ##
1029: pushab set3 ##
1030: callf $8,_panic ##
1031: set1:
1032: movzbl P_PRI(r0),r1 # put on queue which is p->p_pri / 4
1033: shar $2,r1,r1
1034: shal $1,r1,r2
1035: moval _qs[r2],r2
1036: insque (r0),*4(r2) # at end of queue
1037: shal r1,$1,r1
1038: orl2 r1,_whichqs # mark queue non-empty
1039: ret
1040:
1041: set3: .asciz "setrq"
1042:
1043: /*
1044: * remrq(p), using fancy TAHOE instructions
1045: *
1046: * Call should be made at spl8().
1047: */
1048: .globl _remrq
1049: _remrq:
1050: .word 0x0
1051: movl 4(fp),r0
1052: movzbl P_PRI(r0),r1
1053: shar $2,r1,r1
1054: bbs r1,_whichqs,rem1
1055: pushab rem3 # it wasn't recorded to be on its q
1056: callf $8,_panic
1057: rem1:
1058: remque (r0)
1059: bneq rem2 # q not empty yet
1060: shal r1,$1,r1
1061: mcoml r1,r1
1062: andl2 r1,_whichqs # mark queue empty
1063: rem2:
1064: clrl P_RLINK(r0) ## for firewall checking
1065: ret
1066:
1067: rem3: .asciz "remrq"
1068:
1069: .globl __insque
1070: __insque:
1071: .word 0
1072: insque *4(fp), *8(fp)
1073: ret
1074:
1075:
1076: .globl __remque
1077: __remque:
1078: .word 0
1079: remque *4(fp)
1080: ret
1081:
1082: /*
1083: * Masterpaddr is the p->p_addr of the running process on the master
1084: * processor. When a multiprocessor system, the slave processors will have
1085: * an array of slavepaddr's.
1086: */
1087: .globl _masterpaddr
1088: .data
1089: _masterpaddr:
1090: .long 0
1091:
1092: .text
1093: sw0: .asciz "swtch"
1094: /*
1095: * swtch(), using fancy TAHOE instructions
1096: */
1097: .globl _swtch
1098: _swtch:
1099: .word 0x0
1100: movl (fp),fp # prepare for rei
1101: movl (sp),4(sp) # saved pc
1102: tstl (sp)+
1103: movpsl 4(sp)
1104: movl $1,_noproc
1105: clrl _runrun
1106: mtpr0: mtpr $0,$IPL # must allow interrupts here
1107: sw1: ffs _whichqs,r0 # look for non-empty queue
1108: bgeq sw1a
1109: brb sw1 # this is an idle loop!
1110: sw1a: mtpr $0x18,$IPL # lock out all so _whichqs==_qs
1111: bbc r0,_whichqs,mtpr0 # proc moved via lbolt interrupt
1112: shal $1,r0,r1
1113: moval _qs[r1],r1
1114: movl (r1),r2 # r2 = p = highest pri process
1115: remque *(r1)
1116: bvc sw2 # make sure something was there
1117: sw1b: pushab sw0
1118: callf $8,_panic
1119: sw2: bneq sw3
1120: shal r0,$1,r1
1121: mcoml r1,r1
1122: andl2 r1,_whichqs # no more procs in this queue
1123: sw3:
1124: clrl _noproc
1125: tstl P_WCHAN(r2) ## firewalls
1126: bneq sw1b ##
1127: movzbl P_STAT(r2),r3 ##
1128: cmpl $SRUN,r3 ##
1129: bneq sw1b ##
1130: clrl P_RLINK(r2) ##
1131: movl *P_ADDR(r2),r0
1132: movl r0,_masterpaddr
1133: shal $PGSHIFT,r0,r0 # r0 = pcbb(p)
1134: /* mfpr $PCBB,r1 # resume of current proc is easy
1135: * cmpl r0,r1
1136: */ beql res0
1137: incl _cnt+V_SWTCH
1138: brb swresume
1139: /* fall into... */
1140:
1141: .data
1142: .globl _prevpcb
1143: _prevpcb:
1144: .long 0
1145: .text
1146: /*
1147: * resume(pf)
1148: */
1149: .globl _resume
1150: _resume:
1151: .word 0x0
1152: shal $PGSHIFT,4(fp),r0 # r0 = pcbb(p)
1153: movl (fp),fp # prepare for rei
1154: movl (sp)+,4(sp) # saved pc
1155: tstl (sp)+
1156: movpsl 4(sp)
1157: swresume:
1158: mtpr $0x18,$IPL # no interrupts, please
1159: movl _CMAP2,_u+PCB_CMAP2 # yech
1160: REST_ACC # restore original accumulator
1161: svpctx
1162: mtpr r0,$PCBB
1163: ldpctx
1164: movl _u+PCB_CMAP2,_CMAP2 # yech
1165: mtpr $_CADDR2,$TBIS
1166: res0:
1167: tstl _u+PCB_SSWAP
1168: beql res1
1169: movl _u+PCB_SSWAP,r2
1170: clrl _u+PCB_SSWAP
1171: movab _Longjmp,(sp)
1172: clrl 4(sp) # PSL = kernel mode, IPL=0
1173: res1:
1174: /*
1175: * Now we have to care about code and data keys.
1176: * 2 functions may be called, so r0 and r1 must be
1177: * saved across the 'callf'. Also, r2 is used as index
1178: * since r1 may be changed by the functions (just a
1179: * precaution).
1180: */
1181: PUSHR # ro and r1
1182: pushl r2
1183: movl _u+U_PROCP,r2 # r2 = & proc[?]
1184: tstl P_CKEY(r2) # does he have a code key ?
1185: bneq ckey_ok
1186: callf $4,_getcodekey # no, we have to give him one.
1187: movl r0,P_CKEY(r2)
1188: ckey_ok:
1189: tstl P_DKEY(r2) # same stuff for data key
1190: bneq dkey_ok
1191: callf $4,_getdatakey
1192: movl r0,P_DKEY(r2)
1193: dkey_ok:
1194: mtpr P_CKEY(r2),$CCK
1195: mtpr P_DKEY(r2),$DCK
1196: movl (sp)+,r2 # restore his registers
1197: POPR
1198: rei
1199:
1200: /*
1201: * {fu,su},{byte,word}
1202: */
1203: .globl _fuiword
1204: .globl _fuword
1205: _fuiword:
1206: _fuword:
1207: .word 0x0
1208: bitl $3,4(fp) # Check against alignment problems
1209: bneq fserr #
1210: prober $1,*4(fp),$4
1211: beql fserr
1212: movl *4(fp),r0
1213: ret
1214: fserr:
1215: mnegl $1,r0
1216: ret
1217:
1218: .globl _fuibyte
1219: .globl _fubyte
1220: _fuibyte:
1221: _fubyte:
1222: .word 0x0
1223: prober $1,*4(fp),$1
1224: beql fserr
1225: movzbl *4(fp),r0
1226: ret
1227:
1228: .globl _suiword
1229: .globl _suword
1230: _suiword:
1231: _suword:
1232: .word 0x0
1233: bitl $3,4(fp) # Check against alignment problems
1234: bneq fserr #
1235: probew $1,*4(fp),$4
1236: beql fserr
1237: movl 8(fp),*4(fp)
1238: clrl r0
1239: ret
1240:
1241: .globl _suibyte
1242: .globl _subyte
1243: _suibyte:
1244: _subyte:
1245: .word 0x0
1246: probew $1,*4(fp),$1
1247: beql fserr
1248: movb 11(fp),*4(fp)
1249: clrl r0
1250: ret
1251:
1252: /*
1253: * Copy 1 relocation unit (NBPG bytes)
1254: * from user virtual address to physical address
1255: */
1256: _copyseg: .globl _copyseg
1257: .word 0x4
1258: orl3 $PG_V|PG_KW,8(fp),_CMAP2
1259: mtpr $_CADDR2,$TBIS # invalidate entry for copy
1260: MOVC3 ($NBPG,4(fp),$_CADDR2)
1261: ret
1262:
1263: /*
1264: * clearseg(physical_page_number);
1265: *
1266: * zero out physical memory
1267: * specified in relocation units (NBPG bytes)
1268: * This routine was optimized for speed on Tahoe.
1269: */
1270: _clearseg: .globl _clearseg
1271: .word 0
1272: orl3 $PG_V|PG_KW,4(fp),_CMAP1 # Maps to virtual addr CADDR1
1273: mtpr $_CADDR1,$TBIS
1274: movl $255,r0 # r0 = limit
1275: clrl r1 # r1 = index of cleared long
1276: 1:
1277: clrl _CADDR1[r1]
1278: aobleq r0,r1,1b
1279: ret
1280:
1281: /*
1282: * if ( useracc(address, count, mode) ) ....
1283: * Check address.
1284: * Given virtual address, byte count, and rw flag
1285: * returns 0 on no access.
1286: * Note : it is assumed that on all calls to this routine,
1287: * mode=0 means write access, mode=1 means read access.
1288: */
1289: _useracc: .globl _useracc
1290: .word 0x4
1291: movl $1,r2 # r2 = 'user mode' for probew/probew
1292: probes:
1293: movl 4(fp),r0 # get va
1294: movl 8(fp),r1 # count
1295: tstl 12(fp) # test for read access ?
1296: bneq userar # yes
1297: cmpl $NBPG,r1 # can we do it in one probe ?
1298: bgeq uaw2 # yes
1299: uaw1:
1300: probew r2,(r0),$NBPG
1301: beql uaerr # no access
1302: addl2 $NBPG,r0
1303: _ACBL($NBPG+1,$-NBPG,r1,uaw1)
1304: uaw2:
1305: probew r2,(r0),r1
1306: beql uaerr
1307: movl $1,r0
1308: ret
1309:
1310: userar:
1311: cmpl $NBPG,r1
1312: bgeq uar2
1313: uar1:
1314: prober r2,(r0),$NBPG
1315: beql uaerr
1316: addl2 $NBPG,r0
1317: _ACBL($NBPG+1,$-NBPG,r1,uar1)
1318: uar2:
1319: prober r2,(r0),r1
1320: beql uaerr
1321: movl $1,r0
1322: ret
1323: uaerr:
1324: clrl r0
1325: ret
1326:
1327: /*
1328: * if ( kernacc(address, count, mode) ) ....
1329: * Check address.
1330: * Given virtual address, byte count, and rw flag
1331: * returns 0 on no access.
1332: * Same as useracc routine but checks for kernel access rights.
1333: */
1334:
1335: _kernacc: .globl _kernacc
1336: .word 0x4
1337: clrl r2 # r2 = 0 means kernel mode probe.
1338: jbr probes # Dijkstra would get gastric distress here.
1339:
1340: /*
1341: * addupc - increment some histogram counter
1342: * in the profiling buffer
1343: *
1344: * addupc(pc, prof, counts)
1345: * long pc , counts; Only least significant word of 'counts' is added.
1346: * struct uprof *prof;
1347: *
1348: * struct uprof { # profile arguments
1349: * short *r_base; # buffer base
1350: * unsigned pr_size; # buffer size
1351: * unsigned pr_off; # pc offset
1352: * unsigned pr_scale; # pc scaling
1353: * }
1354: */
1355: .globl _addupc
1356: _addupc:
1357: .word 4
1358: movl 8(fp),r2 # r2 points to structure
1359: subl3 8(r2),4(fp),r0 # r0 = PC - lowpc
1360: jlss 9f # PC < lowpc , out of range !
1361: shrl $1,r0,r0 # the unit is words
1362: shrl $1,12(r2),r1 # ditto for scale
1363: emul r1,r0,$0,r0
1364: shrq $14,r0,r0
1365: tstl r0 # too big
1366: jneq 9f
1367: cmpl r1,4(r2) # Check buffer overflow
1368: jgequ 9f
1369: probew $1,*0(r2)[r1],$2 # counter accessible?
1370: jeql 9f
1371: shrl $1,r1,r1 # make r1 word index
1372: addw2 14(fp),*0(r2)[r1]
1373: 9: ret
1374: SCBVEC(udintr0):
1375: SCBVEC(xpintr0):
1376: jbr _Xstray
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.