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