|
|
1.1 root 1: .data
2: .asciz "@(#)locore.s 1.1 86/02/03 Copyr 1985 Sun Micro"
3: .even
4: .text
5: /*
6: * Copyright (c) 1985 by Sun Microsystems, Inc.
7: */
8:
9: #include "../h/param.h"
10: #include "../h/vmparam.h"
11: #include "../h/errno.h"
12: /*
13: #include "../netinet/in_systm.h"
14:
15: #include "../sundev/mbvar.h"
16: */
17:
18: #include "../machine/asm_linkage.h"
19: #include "../machine/buserr.h"
20: #include "../machine/clock.h"
21: #include "../machine/cpu.h"
22: #include "../machine/diag.h"
23: #include "../machine/enable.h"
24: #include "../machine/interreg.h"
25: #include "../machine/memerr.h"
26: #include "../machine/mmu.h"
27: #include "../machine/pcb.h"
28: #include "../machine/psl.h"
29: #include "../machine/pte.h"
30: #include "../machine/reg.h"
31: #include "../machine/trap.h"
32:
33: #include "assym.s"
34:
35: /*
36: * Absolute external symbols
37: */
38: .globl _u, _DVMA
39: _u = UADDR | 32 bit virtual address for u-area
40: _DVMA = 0x0FF00000 | 28 bit virtual address for system DVMA
41:
42: /*
43: * The interrupt stack. This must be the first thing in the data
44: * segment (other than an sccs string) so that we don't stomp
45: * on anything important during interrupt handling. We get a
46: * red zone below this stack for free when the kernel text is
47: * write protected. Since the kernel is loaded with the "-N"
48: * flag, we pad this stack by a page because when the page
49: * level protection is done, we will lose part of this interrupt
50: * stack. Thus the true interrupt stack will be at least MIN_INTSTACK_SZ
51: * bytes and at most MIN_INTSTACK_SZ+NBPG bytes. The interrupt entry
52: * code assumes that the interrupt stack is at a lower address than
53: * both eintstack and the kernel stack in the u area.
54: */
55: #define MIN_INTSTACK_SZ 0x800
56: .data
57: .globl _intstack, eintstack
58: _intstack: | bottom of interrupt stack
59: . = . + NBPG + MIN_INTSTACK_SZ
60: eintstack: | end (top) of interrupt stack
61:
62: /*
63: * System software page tables
64: */
65: #define vaddr(x) ((((x)-_Sysmap)/4)*NBPG + KERNELBASE)
66: #define SYSMAP(mname, vname, npte) \
67: .globl mname; \
68: mname: .=.+(4*npte); \
69: .globl vname; \
70: vname = vaddr(mname);
71: SYSMAP(_Sysmap ,_Sysbase ,SYSPTSIZE )
72: SYSMAP(_Usrptmap ,_usrpt ,USRPTSIZE )
73: SYSMAP(_Forkmap ,_forkutl ,UPAGES )
74: SYSMAP(_Xswapmap ,_xswaputl ,UPAGES )
75: SYSMAP(_Xswap2map,_xswap2utl ,UPAGES )
76: SYSMAP(_Swapmap ,_swaputl ,UPAGES )
77: SYSMAP(_Pushmap ,_pushutl ,UPAGES )
78: SYSMAP(_Vfmap ,_vfutl ,UPAGES )
79: SYSMAP(_CMAP1 ,_CADDR1 ,1 ) | local tmp
80: SYSMAP(_CMAP2 ,_CADDR2 ,1 ) | local tmp
81: SYSMAP(_mmap ,_vmmap ,1 )
82: SYSMAP(_msgbufmap,_msgbuf ,MSGBUFPTECNT )
83: /*
84: SYSMAP(_Mbmap ,_mbutl ,NMBCLUSTERS*CLSIZE)
85: */
86: SYSMAP(_ESysmap ,_Syslimit ,0 ) | must be last
87:
88: .globl _Syssize
89: _Syssize = (_ESysmap-_Sysmap)/4
90:
91: /*
92: * Software copy of system enable register
93: * This is always atomically updated
94: */
95: .data
96: .globl _enablereg
97: _enablereg: .byte 0 | UNIX's system enable register
98: .even
99: .text
100:
101: /*
102: * Macro to save all registers and switch to kernel context
103: * 1: Save and switch context
104: * 2: Save all registers
105: * 3: Save user stack pointer
106: */
107: #define SAVEALL() \
108: clrw sp@-;\
109: moveml #0xFFFF,sp@-;\
110: movl usp,a0;\
111: movl a0,sp@(R_SP)
112:
113: /* Normal trap sequence */
114: #define TRAP(type) \
115: SAVEALL();\
116: movl #type,sp@-;\
117: jra trap
118:
119: /*
120: * System initialization
121: * UNIX receives control at the label `_start' which
122: * must be at offset zero in this file; this file must
123: * be the first thing in the boot image.
124: */
125: .text
126: .globl _start
127: _start:
128: /*
129: * We should reset the world here, but it screws the UART settings.
130: *
131: * Do a halfhearted job of setting up the mmu so that we can run out
132: * of the high address space. We do this by reading the current pmegs
133: * for the `real' locations and using them for the virtual relocation.
134: * NOTE - Assumes that the real and virtual locations have the same
135: * segment offsets from 0 and KERNELBASE!!!
136: *
137: * We make the following assumptions about our environment
138: * as set up by the monitor:
139: *
140: * - we have enough memory mapped for the entire kernel + some more
141: * - all pages are writable
142: * - the last pmeg [SEGINV] has no valid pme's
143: * - the highest virtual segment has a pmeg allocated to it
144: * - when the monitor's romp->v_memorybitmap points to a zero
145: * - each low segment i is mapped to use pmeg i
146: * - each page map entry i maps physical page i
147: * - the monitor's scb is NOT in low memory
148: * - on systems w/ ecc memory, that the monitor has set the base
149: * addresses and enabled all the memory cards correctly
150: *
151: * We will set the protection properly in startup().
152: */
153:
154: /*
155: * Before we set up the new mapping and start running with the correct
156: * addresses, all of the code must be carefully written to be position
157: * independent code, since we are linked for running out of high addresses,
158: * but we get control running in low addresses. We continue to run
159: * off the stack set up by the monitor until after we set up the u area.
160: */
161: movw #SR_HIGH,sr | lock out interrupts
162: moveq #FC_MAP,d0
163: movc d0,sfc | set default sfc to FC_MAP
164: movc d0,dfc | set default dfc to FC_MAP
165: moveq #KCONTEXT,d0
166: movsb d0,CONTEXTBASE | now running in KCONTEXT
167:
168: leax: lea pc@(_start-(leax+2)),a2 | a2 = true current location of _start
169: movl a2,d2 | real start address
170: andl #SEGMENTADDRBITS,d2 | clear extraneous bits
171: orl #SEGMENTBASE,d2 | set to segment map offset
172: movl d2,a2 | a2 = real adddress map pointer
173:
174: movl #_start,d3 | virtual start address
175: andl #SEGMENTADDRBITS,d3 | clear extraneous bits
176: orl #SEGMENTBASE,d3 | set to segment map offset
177: movl d3,a3 | a3 = virtual address map pointer
178:
179: /*
180: * Compute the number used to control the dbra loop.
181: * By doing ((end - 1) - KERNELBASE) >> SGSHIFT we
182: * essentially get ctos(btoc(end - KERNELBASE)) - 1
183: * where the - 1 is adjustment for the dbra loop.
184: */
185: movl #_end-1,d1 | get virtual end
186: subl #KERNELBASE,d1 | subtract off base address
187: movl #SGSHIFT,d0 | load up segment shift value
188: lsrl d0,d1 | d1 = # of segments to map - 1
189:
190: /*
191: * Now loop through the real addresses where we are loaded and set
192: * up the virtual segments for where we want to be virtually to be the same.
193: */
194: 0:
195: movsb a2@,d0 | get real segno value
196: movsb d0,a3@ | set virtual segno value
197: addl #NBSG,a2 | bump real address map pointer
198: addl #NBSG,a3 | bump virtual address map pointer
199: dbra d1,0b | decrement count and loop
200:
201: movl #CACHE_CLEAR+CACHE_ENABLE,d0
202: movc d0,cacr | clear (and enable) the cache
203:
204: jmp cont:l | force non-PC rel branch
205: cont:
206:
207: /*
208: * PHEW! Now we are running with correct addresses
209: * and can use non-position independent code.
210: */
211:
212: /*
213: * Now map in our own copies of the eeprom, clock, memory error
214: * register, interrupt control register, and ecc regs into the
215: * last virtual segment which already has a pmeg allocated to it
216: * when we get control from the monitor.
217: */
218: lea EEPROM_ADDR_MAPVAL,a0 | map in eeprom
219: movl #EEPROM_ADDR_PTE,d0
220: movsl d0,a0@
221:
222: lea CLKADDR_MAPVAL,a0 | map in clock
223: movl #CLKADDR_PTE,d0
224: movsl d0,a0@
225:
226: lea MEMREG_MAPVAL,a0 | map in memory error register
227: movl #MEMREG_PTE,d0
228: movsl d0,a0@
229:
230: lea INTERREG_MAPVAL,a0 | map in interrupt control reg
231: movl #INTERREG_PTE,d0
232: movsl d0,a0@
233:
234: lea ECCREG_MAPVAL,a0 | map in ecc regs
235: movl #ECCREG_PTE,d0
236: movsl d0,a0@
237:
238: /*
239: * Check to see if memory was all mapped in correctly. On versions >= 'N',
240: * if ROMP_ROMVEC_VERSION is greater than zero, then ROMP_MEMORYBITMAP
241: * contains the address of a pointer to an array of bits
242: * If this pointer is non-zero, then we had some bad pages
243: * Until we get smarter, we give up if we find this condition.
244: */
245: tstl ROMP_ROMVEC_VERSION
246: ble 1f | field is <= zero, don't do next test
247: movl ROMP_MEMORYBITMAP,a0
248: tstl a0@
249: jeq 1f | pointer is zero, all ok
250: pea 0f
251: jsr _halt
252: addqw #4,sp | in case they really want to try this
253: .data
254: 0: .asciz "Memory bad"
255: .even
256: .text
257: 1:
258:
259: /*
260: * Set up mapping for the u page(s) now, using the physical page(s)
261: * after _end. This code and uinit() are closely related.
262: */
263: movl #(UPAGES-1),d1 | dbra loop counter
264: pea _end-KERNELBASE+NBPG-1 | phys addr of starting page past end
265: jsr _getpgmap | getpgmap(end - KERNELBASE + NBPG - 1)
266: addqw #4,sp | pop argument
267: orl #(PG_S+PG_W),d0 | make a system writable page
268: lea _u,a0 | get addr of u area
269: 0:
270: movl d0,sp@- | push pte
271: pea a0@ | push addr
272: jsr _setpgmap | setpgmap(u + i*NBPG, pte + i)
273: addqw #8,sp | pop arguments
274: addql #1,d0 | bump pte to next phys page
275: addl #NBPG,a0 | bump addr
276: dbra d1,0b
277:
278: | zero first page which will be scb/usrpt page
279: movl #((NBPG-1)/4),d0 | dbra byte count
280: lea 0,a0 | start at zero
281: 0: clrl a0@+ | clear long word and increment
282: dbra d0,0b | decrement count and loop
283:
284: | zero bss + u page(s) (using low addresses)
285: movl #_end-KERNELBASE+(NBPG*(UPAGES+1))-1,d0
286: andl #~(NBPG-1),d0 | mask off to page boundary
287: lea _edata-KERNELBASE,a0 | get bss start
288: subl a0,d0 | get bss length
289: lsrl #2,d0 | shift for long count
290: 0: clrl a0@+ | clear long word and increment
291: subql #1,d0
292: jne 0b | decrement count and loop
293:
294: /*
295: * Set up the stack. From now we continue to use the 68020 ISP
296: * (interrupt stack pointer). This is because the MSP (master
297: * stack pointer) as implemented by Motorola is too painful to
298: * use since we have to play lots of games and add extra tests
299: * to set something in the master stack if we running on the
300: * interrupt stack and we are about to pop off a throw away
301: * stack frame.
302: *
303: * Thus it is possible to having naming conflicts. In general,
304: * when the term "interrupt stack" (no pointer) is used, it
305: * is referring to the software implemented interrupt stack
306: * and the "kernel stack" is the per user kernel stack in the
307: * user area. We handling switching between the two different
308: * address ranges upon interrupt entry/exit. We will use ISP
309: * and MSP if we are referring to the hardstack stack pointers.
310: */
311: lea _u+U_STACK+KERNSTACK,sp | set to top of kernel stack
312:
313: /*
314: * See if we have a 68881 attached.
315: * _fppstate is 0 if no fpp,
316: * 1 if fpp is present and enabled,
317: * and -1 if fpp is present but disabled
318: * (not currently used).
319: */
320: .data
321: .globl _fppstate
322: _fppstate: .word 1 | mark as present until we find out otherwise
323: .text
324:
325: flinevec = 0x2c
326: movsb ENABLEREG,d0 | get the current enable register
327: orb #ENA_FPP,d0 | or in FPP enable bit
328: movsb d0,ENABLEREG | set in the enable register
329: movl sp,a1 | save sp in case of fline fault
330: movc vbr,a0 | get vbr
331: movl a0@(flinevec),d1 | save old f line trap handler
332: movl #ffault,a0@(flinevec) | set up f line handler
333: frestore fnull
334: jra 1f
335:
336: fnull: .long 0 | null fpp internal state
337:
338: ffault: | handler for no fpp present
339: movw #0,_fppstate | set global to say no fpp
340: andb #~ENA_FPP,d0 | clear ENA_FPP enable bit
341: movl a1,sp | clean up stack
342:
343: 1:
344: movl d1,a0@(flinevec) | restore old f line trap handler
345: movsb d0,ENABLEREG | set up enable reg
346: movb d0,_enablereg | save soft copy of enable register
347:
348: | dummy up a stack so process 1 can find saved registers
349: movl #USRSTACK,a0 | init user stack pointer
350: movl a0,usp
351: clrw sp@- | dummy fmt & vor
352: movl #USRTEXT,sp@- | push pc
353: movw #SR_USER,sp@- | push sr
354: lea 0,a6 | stack frame link 0 in main
355: | invoke main, we will return as process 1 (init)
356: SAVEALL()
357: jsr _main | simulate interrupt -> main
358: clrl d0 | fake return value from trap
359: jra rei
360:
361: /*
362: * Entry points for interrupt and trap vectors
363: */
364: .globl buserr, addrerr, coprocerr, fmterr, illinst, zerodiv, chkinst
365: .globl trapv, privvio, trace, emu1010, emu1111, spurious
366: .globl badtrap, brkpt, floaterr, level2, level3, level4, level5
367: .globl _level7, errorvec
368:
369: buserr:
370: TRAP(T_BUSERR)
371:
372: addrerr:
373: TRAP(T_ADDRERR)
374:
375: coprocerr:
376: TRAP(T_COPROCERR)
377:
378: fmterr:
379: TRAP(T_FMTERR)
380:
381: illinst:
382: TRAP(T_ILLINST)
383:
384: zerodiv:
385: TRAP(T_ZERODIV)
386:
387: chkinst:
388: TRAP(T_CHKINST)
389:
390: trapv:
391: TRAP(T_TRAPV)
392:
393: privvio:
394: TRAP(T_PRIVVIO)
395:
396: trace:
397: TRAP(T_TRACE)
398:
399: emu1010:
400: TRAP(T_EMU1010)
401:
402: emu1111:
403: TRAP(T_EMU1111)
404:
405: spurious:
406: TRAP(T_SPURIOUS)
407:
408: badtrap:
409: TRAP(T_M_BADTRAP)
410:
411: brkpt:
412: TRAP(T_BRKPT)
413:
414: floaterr:
415: TRAP(T_M_FLOATERR)
416:
417: errorvec:
418: TRAP(T_M_ERRORVEC)
419:
420: level2:
421: IOINTR(2)
422:
423: level3:
424: IOINTR(3)
425:
426: level4:
427: IOINTR(4)
428:
429: .data
430: .globl _ledcnt
431: ledpat:
432: .byte ~0x80
433: .byte ~0x40
434: .byte ~0x20
435: .byte ~0x10
436: .byte ~0x08
437: .byte ~0x04
438: .byte ~0x02
439: .byte ~0x01
440: .byte ~0x02
441: .byte ~0x04
442: .byte ~0x08
443: .byte ~0x10
444: .byte ~0x20
445: .byte ~0x40
446: endpat:
447: .even
448: ledptr: .long ledpat
449: flag5: .word 0
450: flag7: .word 0
451: _ledcnt: .word 50 | once per second min LED update rate
452: ledcnt: .word 0
453: .text
454:
455: /*
456: * This code assumes that the real time clock interrupts 100 times
457: * a second and that we want to only call hardclock 50 times/sec
458: * We update the LEDs with new values so at least a user can tell
459: * that something it still running before calling hardclock().
460: */
461: level5: | default clock interrupt
462: tstb CLKADDR+CLK_INTRREG | read CLKADDR->clk_intrreg to clear
463: andb #~IR_ENA_CLK5,INTERREG | clear interrupt request
464: orb #IR_ENA_CLK5,INTERREG | and re-enable
465: tstb CLKADDR+CLK_INTRREG | clear interrupt register again,
466: | if we lost interrupt we will
467: | resync later anyway.
468: | for 100 hz operation, comment out from here ...
469: notw flag5 | toggle flag
470: jeq 0f | if result zero skip ahead
471: rte
472: 0:
473: | ... to here
474: moveml #0xC0E0,sp@- | save d0,d1,a0,a1,a2
475:
476: movl sp,a2 | save copy of previous sp
477: cmpl #eintstack,sp | on interrupt stack?
478: jls 1f | yes, skip
479: lea eintstack,sp | no, switch to interrupt stack
480: 1:
481:
482: /* check for LED update */
483: movl a2@(5*4+2),a1 | get saved pc
484: cmpl #idle,a1 | were we idle?
485: beq 0f | yes, do LED update
486: subqw #1,ledcnt
487: bge 2f | if positive skip LED update
488: 0:
489: movw _ledcnt,ledcnt | reset counter
490: movl ledptr,a0 | get pointer
491: movb a0@+,d0 | get next byte
492: cmpl #endpat,a0 | are we at the end?
493: bne 1f | if not, skip
494: lea ledpat,a0 | reset pointer
495: 1:
496: movl a0,ledptr | save pointer
497: movsb d0,DIAGREG | d0 to diagnostic LEDs
498:
499: 2: | call hardclock
500: movw a2@(5*4),d0 | get saved sr
501: movl d0,sp@- | push it as a long
502: movl a1,sp@- | push saved pc
503: jsr _hardclock | call UNIX routine
504: movl a2,sp | restore old sp
505: moveml sp@+,#0x0703 | restore all saved regs
506: jra rei_io | all done
507:
508: /*
509: * Level 7 interrupts can be caused by parity/ECC errors or the
510: * clock chip. The clock chip is tied to level 7 interrupts
511: * only if we are profiling. Because of the way nmi's work,
512: * we clear the any level 7 clock interrupts first before
513: * checking the memory error register.
514: */
515: _level7:
516: #ifdef GPROF
517: tstb CLKADDR+CLK_INTRREG | read CLKADDR->clk_intrreg to clear
518: andb #~IR_ENA_CLK7,INTERREG | clear interrupt request
519: orb #IR_ENA_CLK7,INTERREG | and re-enable
520: #endif GPROF
521:
522: moveml #0xC0C0,sp@- | save C regs
523: movb MEMREG,d0 | read memory error register
524: andb #ER_INTR,d0 | a parity/ECC interrupt pending?
525: jeq 0f | if not, jmp
526: jsr _memerr | dump memory error info
527: /*MAYBE REACHED*/ | if we do return to here, then
528: jra 1f | we had a non-fatal memory problem
529: 0:
530:
531: #ifdef GPROF
532: | for 100 hz profiling, comment out from here ...
533: notw flag7 | toggle flag
534: jne 1f | if result non-zero return
535: | ... to here
536: jsr kprof | do the profiling
537: #else GPROF
538: pea 0f | push message printf
539: jsr _printf | print the message
540: addqw #4,sp | pop argument
541: .data
542: 0: .asciz "stray level 7 interrupt\012"
543: .even
544: .text
545: #endif GPROF
546: 1:
547: moveml sp@+,#0x0303 | restore regs
548: rte
549:
550: /*
551: * Called by trap #2 to do an instruction cache flush operation
552: */
553: .globl flush
554: flush:
555: movl #CACHE_CLEAR+CACHE_ENABLE,d0
556: movc d0,cacr | clear (and enable) the cache
557: rte
558:
559: .globl syscall, trap, rei
560: /*
561: * Special case for syscall.
562: * Everything in line because this is by far the most
563: * common interrupt.
564: */
565: syscall:
566: subqw #2,sp | empty space
567: moveml #0xFFFF,sp@- | save all regs
568: movl usp,a0 | get usp
569: movl a0,sp@(R_SP) | save usp
570: movl #syserr,_u+U_LOFAULT | catch a fault if and when
571: movl a0@,d0 | get the syscall code
572: syscont:
573: clrl _u+U_LOFAULT | clear lofault
574: movl d0,sp@- | push syscall code
575: jsr _syscall | go to C routine
576: addqw #4,sp | pop arg
577: orw #SR_INTPRI,sr | need to test atomicly, rte will lower
578: bclr #AST_STEP_BIT-24,_u+PCB_P0LR | need to single step?
579: jne 4f
580: bclr #AST_SCHED_BIT-24,_u+PCB_P0LR | need to reschedule?
581: jeq 3f | no, get out
582: 4: bset #TRACE_AST_BIT-24,_u+PCB_P0LR | say that we're tracing for AST
583: jne 3f | if already doing it, skip
584: bset #SR_TRACE_BIT-8,sp@(R_SR) | set trace mode
585: jeq 3f | if wasn't set, continue
586: bset #TRACE_USER_BIT-24,_u+PCB_P0LR | save fact that trace was set
587: 3: movl sp@(R_SP),a0 | restore user SP
588: movl a0,usp
589: movl #CACHE_CLEAR+CACHE_ENABLE,d0
590: movc d0,cacr | clear (and enable) the cache
591: 1:
592: moveml sp@,#0x7FFF | restore all but SP
593: addw #R_SR,sp | pop all saved regs
594: rte | and return!
595:
596: syserr:
597: movl #-1,d0 | set err code
598: jra syscont | back to mainline
599:
600: /*
601: * We reset the sfc and dfc to FC_MAP in case we came in from
602: * a trap while in the monitor since the monitor uses movs
603: * instructions after dorking w/ sfc and dfc during its operation.
604: */
605: trap:
606: moveq #FC_MAP,d0
607: movc d0,sfc
608: movc d0,dfc
609: jsr _trap | Enter C trap routine
610: addqw #4,sp | Pop trap type
611:
612: /*
613: * Return from interrupt or trap, check for AST's.
614: * d0 contains the size of info to pop (if any)
615: */
616: rei:
617: btst #SR_SMODE_BIT-8,sp@(R_SR) | SR_SMODE ?
618: bne 1f | skip if system
619: orw #SR_INTPRI,sr | need to test atomicly, rte will lower
620: bclr #AST_STEP_BIT-24,_u+PCB_P0LR | need to single step?
621: jne 4f
622: bclr #AST_SCHED_BIT-24,_u+PCB_P0LR | need to reschedule?
623: jeq 3f | no, get out
624: 4: bset #TRACE_AST_BIT-24,_u+PCB_P0LR | say that we're tracing for AST
625: bne 3f | if already doing it, skip
626: bset #SR_TRACE_BIT-8,sp@(R_SR) | set trace mode
627: jeq 3f | if wasn't set, continue
628: bset #TRACE_USER_BIT-24,_u+PCB_P0LR | save fact that trace was set
629: 3: movl sp@(R_SP),a0 | restore user SP
630: movl a0,usp
631: movl #CACHE_CLEAR+CACHE_ENABLE,a0
632: movc a0,cacr | clear (and enable) the cache
633: 1:
634: tstl d0 | any cleanup needed?
635: beq 2f | no, skip
636: movl sp,a0 | get current sp
637: addw d0,a0 | pop off d0 bytes of crud
638: clrw a0@(R_VOR) | dummy VOR
639: movl sp@(R_PC),a0@(R_PC) | move PC
640: movw sp@(R_SR),a0@(R_SR) | move SR
641: movl a0,sp@(R_SP) | stash new sp value
642: moveml sp@,#0xFFFF | restore all including SP
643: addw #R_SR,sp | pop all saved regs
644: rte | and return!
645: 2:
646: moveml sp@,#0x7FFF | restore all but SP
647: addw #R_SR,sp | pop all saved regs
648: rte | and return!
649:
650: /*
651: * Return from I/O interrupt, check for AST's.
652: */
653: .globl rei_io
654: rei_iop:
655: moveml sp@+,#0x0707 | pop regs <a2,a1,a0,d2,d1,d0>
656: rei_io:
657: addql #1,_cnt+V_INTR | increment io interrupt count
658: rei_si:
659: btst #SR_SMODE_BIT-8,sp@ | SR_SMODE? (SR is atop stack)
660: jne 3f | skip if system
661: orw #SR_INTPRI,sr | need to test atomicly, rte will lower
662: bclr #AST_STEP_BIT-24,_u+PCB_P0LR | need to single step?
663: jne 4f
664: bclr #AST_SCHED_BIT-24,_u+PCB_P0LR | need to reschedule?
665: jeq 3f | no, get out
666: 4: bset #TRACE_AST_BIT-24,_u+PCB_P0LR | say that we're tracing for AST
667: jne 3f | if already doing it, skip
668: bset #SR_TRACE_BIT-8,sp@ | set trace mode in SR atop stack
669: jeq 3f | if wasn't set, continue
670: bset #TRACE_USER_BIT-24,_u+PCB_P0LR | save fact that trace was set
671: 3:
672: rte | and return!
673:
674: /*
675: * Handle software interrupts
676: * Just call C routine
677: */
678: .globl softint
679: softint:
680: moveml #0xC0E0,sp@- | save regs we trash <d0,d1,a0,a1,a2>
681: movl sp,a2 | save copy of previous sp
682: cmpl #eintstack,sp | on interrupt stack?
683: jls 0f | yes, skip
684: lea eintstack,sp | no, switch to interrupt stack
685: 0:
686: bclr #IR_SOFT_INT1_BIT,INTERREG| clear interrupt request
687: jsr _softint | Call C
688: movl a2,sp | restore old sp
689: moveml sp@+,#0x0703 | restore saved regs <a2,a1,a0,d1,d0>
690: jra rei_si
691:
692: /*
693: * Turn on a software interrupt (H/W level 1).
694: */
695: ENTRY(siron)
696: bset #IR_SOFT_INT1_BIT,INTERREG | trigger level 1 intr
697: rts
698:
699: /*
700: * return 1 if an interrupt is being serviced (on interrupt stack),
701: * otherwise return 0.
702: */
703: ENTRY(intsvc)
704: clrl d0 | assume false
705: cmpl #eintstack,sp | on interrupt stack?
706: bhi 1f | no, skip
707: movl #1,d0 | return true
708: 1:
709: rts
710:
711: /*
712: * Enable and disable DVMA.
713: */
714: ENTRY(enable_dvma)
715: 1:
716: orb #ENA_SDVMA,_enablereg | enable System DVMA
717: movb _enablereg,d0 | get it in a register
718: movsb d0,ENABLEREG | put enable register back
719: cmpb _enablereg,d0 | see if someone higher changed it
720: bne 1b | if so, try again
721: rts
722:
723: ENTRY(disable_dvma)
724: 1:
725: andb #~ENA_SDVMA,_enablereg | disable System DVMA
726: movb _enablereg,d0 | get it in a register
727: movsb d0,ENABLEREG | put enable register back
728: cmpb _enablereg,d0 | see if someone higher changed it
729: bne 1b | if so, try again
730: rts
731:
732: /*
733: * Transfer data to and from user space -
734: * Note that these routines can cause faults
735: * It is assumed that the kernel has nothing at
736: * less than KERNELBASE in the virtual address space.
737: */
738: | Return length of user string _fustrlen(address)
739: ENTRY(fustrlen)
740: movl #fsuerr,_u+U_LOFAULT | catch a fault if and when
741: movl sp@(4),a0 | get address
742: movl #KERNELBASE-1,a1
743: 1:
744: cmpl a1,a0 | check address range
745: jhi fsuerr | jmp if greater than
746: tstb a0@+ | is it 0
747: jne 1b
748: movl a0,d0
749: subl sp@(4),d0 | compute difference
750: clrl _u+U_LOFAULT | clear lofault
751: rts
752:
753: | Fetch user byte _fubyte(address)
754: ENTRY2(fubyte,fuibyte)
755: movl #fsuerr,_u+U_LOFAULT | catch a fault if and when
756: movl sp@(4),a0 | get address
757: cmpl #KERNELBASE-1,a0 | check address range
758: jhi fsuerr | jmp if greater than
759: movb a0@,d0 | get the byte
760: andl #0xFF,d0
761: clrl _u+U_LOFAULT | clear lofault
762: rts
763:
764:
765: | Fetch user (short) word: _fusword(address)
766: ENTRY(fusword)
767: movl #fsuerr,_u+U_LOFAULT | catch a fault if and when
768: movl sp@(4),a0 | get address
769: cmpl #KERNELBASE-2,a0 | check address range
770: jhi fsuerr | jmp if greater than
771: movw a0@,d0 | get the word
772: andl #0xFFFF,d0
773: clrl _u+U_LOFAULT | clear lofault
774: rts
775:
776: | Fetch user (long) word: _fuword(address)
777: ENTRY2(fuword,fuiword)
778: movl #fsuerr,_u+U_LOFAULT | catch a fault if and when
779: movl sp@(4),a0 | get address
780: cmpl #KERNELBASE-4,a0 | check address range
781: jhi fsuerr | jmp if greater than
782: movl a0@,d0 | get the long word
783: clrl _u+U_LOFAULT | clear lofault
784: rts
785:
786: | Set user byte: _subyte(address, value)
787: ENTRY2(subyte,suibyte)
788: movl #fsuerr,_u+U_LOFAULT | catch a fault if and when
789: movl sp@(4),a0 | get address
790: cmpl #KERNELBASE-1,a0 | check address range
791: jhi fsuerr | jmp if greater than
792: movb sp@(8+3),a0@ | set the byte
793: clrl d0 | indicate success
794: clrl _u+U_LOFAULT | clear lofault
795: rts
796:
797: | Set user short word: _susword(address, value)
798: ENTRY(susword)
799: movl #fsuerr,_u+U_LOFAULT | catch a fault if and when
800: movl sp@(4),a0 | get address
801: cmpl #KERNELBASE-2,a0 | check address range
802: jhi fsuerr | jmp if greater than
803: movw sp@(8+2),a0@ | set the word
804: clrl d0 | indicate success
805: clrl _u+U_LOFAULT | clear lofault
806: rts
807:
808: | Set user (long) word: _suword(address, value)
809: ENTRY2(suword,suiword)
810: movl #fsuerr,_u+U_LOFAULT | catch a fault if and when
811: movl sp@(4),a0 | get address
812: cmpl #KERNELBASE-4,a0 | check address range
813: jhi fsuerr | jmp if greater than
814: movl sp@(8+0),a0@ | set the long word
815: clrl d0 | indicate success
816: clrl _u+U_LOFAULT | clear lofault
817: rts
818:
819: fsuerr:
820: movl #-1,d0 | return error
821: clrl _u+U_LOFAULT | clear lofault
822: rts
823:
824: /*
825: * copyout() - except for _u+U_LOFAULT and address
826: * checking this is just bcopy().
827: */
828: ENTRY(copyout)
829: movl #cpctxerr,_u+U_LOFAULT | catch faults
830: movl sp@(4),a0
831: movl sp@(8),a1
832: movl sp@(12),d0
833: jle 7f | leave if ridiculous count
834: copyoutcheck:
835: movl a1,d1 | get starting address
836: cmpl #KERNELBASE,d1 | check starting address
837: jpl cpctxerr | jmp on error
838: addl d0,d1 | compute ending address
839: cmpl #KERNELBASE,d1 | check ending address
840: jhi cpctxerr | jmp on error
841: cmpl d1,a1 | check for wrap around
842: jhi cpctxerr | jmp on error
843: /* If from address is odd, move one byte to make it even */
844: movl a0,d1
845: btst #0,d1
846: jeq 1f | even, skip
847: movb a0@+,a1@+ | move the byte
848: subql #1,d0 | decrement count
849: /* Now if to address is odd, we have to do byte-by-byte moves */
850: 1: movl a1,d1
851: btst #0,d1
852: jne 2f | if odd go do bytes
853: /* Now both addresses are even and we can do long moves */
854: rorl #2,d0 | get count as longs
855: jra 5f | enter loop at bottom
856: 4: movl a0@+,a1@+ | move a long
857: 5: dbra d0,4b | do until --longcount < 0
858: roll #2,d0
859: andl #3,d0 | count %= sizeof (long)
860: jra 2f
861: /*
862: * Here for the last 3 bytes or if we have to do byte-by-byte moves
863: * because the pointers were relatively odd
864: */
865: 3: movb a0@+,a1@+ | move a byte
866: 2: dbra d0,3b | until --count < 0
867: 7: clrl d0 | indicate success
868: clrl _u+U_LOFAULT
869: rts | and return
870:
871: /*
872: * copyin() - except for _u+U_LOFAULT and address
873: * checking this is just bcopy().
874: */
875: ENTRY(copyin)
876: movl #cpctxerr,_u+U_LOFAULT | catch faults
877: movl sp@(4),a0
878: movl sp@(8),a1
879: movl sp@(12),d0
880: jle 7f | leave if ridiculous count
881: copyincheck:
882: movl a0,d1 | get starting address
883: cmpl #KERNELBASE,d1 | check starting address
884: jpl cpctxerr | jmp on error
885: addl d0,d1 | compute ending address
886: cmpl #KERNELBASE,d1 | check ending address
887: jhi cpctxerr | jmp on error
888: cmpl d1,a0 | check for wrap around
889: jhi cpctxerr | jmp on error
890: /* If from address is odd, move one byte to make it even */
891: movl a0,d1
892: btst #0,d1
893: jeq 1f | even, skip
894: movb a0@+,a1@+ | move the byte
895: subql #1,d0 | decrement count
896: /* Now if to address is odd, we have to do byte-by-byte moves */
897: 1: movl a1,d1
898: btst #0,d1
899: jne 2f | if odd go do bytes
900: /* Now both addresses are even and we can do long moves */
901: rorl #2,d0 | get count as longs
902: jra 5f | enter loop at bottom
903: 4: movl a0@+,a1@+ | move a long
904: 5: dbra d0,4b | do until --longcount < 0
905: roll #2,d0
906: andl #3,d0 | count %= sizeof (long)
907: jra 2f
908: /*
909: * Here for the last 3 bytes or if we have to do byte-by-byte moves
910: * because the pointers were relatively odd
911: */
912: 3: movb a0@+,a1@+ | move a byte
913: 2: dbra d0,3b | until --count < 0
914: 7: clrl d0 | indicate success
915: clrl _u+U_LOFAULT
916: rts | and return
917:
918: cpctxerr:
919: movl #EFAULT,d0 | return error
920: clrl _u+U_LOFAULT | clear lofault
921: rts
922:
923: /*
924: * fetch user longwords -- used by syscall -- faster than copyin
925: * Doesn't worry about alignment of transfer, let the 68020 worry
926: * about that - we won't be doing more than 8 long words anyways.
927: * Use copyin to do more careful checking if we are real close.
928: * fulwds(uadd, sadd, nlwds)
929: */
930: ENTRY(fulwds)
931: movl #cpctxerr,_u+U_LOFAULT | catch a fault if and when
932: movl sp@(4),a0 | user address
933: movl sp@(8),a1 | system address
934: movl sp@(12),d0 | number of words
935: cmpl #KERNELBASE-8*4,a0 | check starting address
936: jls 1f | enter loop at bottom if ok
937: lsll #2,d0 | convert to byte count
938: jra copyincheck | let copyin code handle
939: 2: movl a0@+,a1@+ | get longword
940: 1: dbra d0,2b | loop on count
941: clrl d0 | indicate success
942: clrl _u+U_LOFAULT | clear lofault
943: rts
944:
945: /*
946: * Get/Set vector base register
947: */
948: ENTRY(getvbr)
949: movc vbr,d0
950: rts
951:
952: ENTRY(setvbr)
953: movl sp@(4),d0
954: movc d0,vbr
955: rts
956:
957: /*
958: * Enter the monitor -- called for console abort
959: */
960: ENTRY(montrap)
961: jsr _startnmi | enable monitor nmi routine
962: movl sp@(4),a0 | address to trap to
963: clrw sp@- | dummy VOR
964: pea 0f | return address
965: movw sr,sp@- | current sr
966: jra a0@ | trap to monitor
967: 0:
968: jsr _stopnmi | disable monitor nmi routine
969: rts
970:
971: /*
972: * Read the ID prom. This is mapped from IDPROMBASE for IDPROMSIZE
973: * bytes in the FC_MAP address space for byte access only. Assumes
974: * that the sfc has already been set to FC_MAP.
975: */
976: ENTRY(getidprom)
977: movl sp@(4),a0 | address to copy bytes to
978: lea IDPROMBASE,a1 | select id prom
979: movl #(IDPROMSIZE-1),d1 | byte loop counter
980: 0: movsb a1@+,d0 | get a byte
981: movb d0,a0@+ | save it
982: dbra d1,0b | and loop
983: rts
984:
985: /*
986: * Enable and disable video.
987: */
988: ENTRY(setvideoenable)
989: 1:
990: tstl sp@(4) | is bit on or off
991: jeq 2f
992: orb #ENA_VIDEO,_enablereg | enable video
993: jra 3f
994: 2:
995: andb #~ENA_VIDEO,_enablereg | disable video
996: 3:
997: movb _enablereg,d0 | get it in a register
998: movsb d0,ENABLEREG | put enable register back
999: cmpb _enablereg,d0 | see if someone higher changed it
1000: bne 1b | if so, try again
1001: rts
1002:
1003: /*
1004: * Enable and disable video Copy.
1005: */
1006: ENTRY(setcopyenable)
1007: 1:
1008: tstl sp@(4) | is bit on or off
1009: jeq 2f
1010: orb #ENA_COPY,_enablereg | enable video copy
1011: jra 3f
1012: 2:
1013: andb #~ENA_COPY,_enablereg | disable copy
1014: 3:
1015: movb _enablereg,d0 | get it in a register
1016: movsb d0,ENABLEREG | put enable register back
1017: cmpb _enablereg,d0 | see if someone higher changed it
1018: bne 1b | if so, try again
1019: rts
1020:
1021: /*
1022: * Enable and disable video interrupt.
1023: */
1024: ENTRY(setintrenable)
1025: tstl sp@(4) | is bit on or off
1026: jeq 1f
1027: orb #IR_ENA_VID4,INTERREG | enable video interrupt
1028: rts
1029: 1:
1030: andb #~IR_ENA_VID4,INTERREG | disable
1031: rts
1032:
1033: /*
1034: * Read the bus error register
1035: */
1036: ENTRY(getbuserr)
1037: clrl d0
1038: movsb BUSERRREG,d0 | get the buserr register
1039: rts
1040:
1041: /*
1042: * Set the fpp registers to the u area values
1043: */
1044: ENTRY(setfppregs)
1045: tstw _fppstate | is fpp present and enabled?
1046: jle 1f | branch if not
1047: fmovem _u+U_FPS_REGS,fp0-fp7 | set fp data registers
1048: fmovem _u+U_FPS_CTRL,fpc/fps/fpi | set control registers
1049: 1:
1050: rts
1051:
1052: /*
1053: * Define some variables used by post-modem debuggers
1054: * to help them work on kernels with changing structures.
1055: */
1056: .globl UPAGES_DEBUG, KERNELBASE_DEBUG, VADDR_MASK_DEBUG
1057: .globl PGSHIFT_DEBUG, SLOAD_DEBUG
1058:
1059: UPAGES_DEBUG = UPAGES
1060: KERNELBASE_DEBUG = KERNELBASE
1061: VADDR_MASK_DEBUG = 0x0fffffff
1062: PGSHIFT_DEBUG = PGSHIFT
1063: SLOAD_DEBUG = SLOAD
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.