|
|
MiNT 1.12
; Copyright 1992 Eric R. Smith ; Copyright 1993,1994 Atari Corporation ; All rights reserved. %include "magic.i" ; ; interrupt wrapping routines; these should just save registers and call ; the appropriate C handlers, unless speed is a major problem ; TEXT ; ; first, utilities for setting processor status level ; XDEF _spl7 XDEF _spl _spl7: move.w sr,d0 ori.w #$0700,sr rts _spl: move.w 4(sp),sr rts XDEF _mint_5ms XDEF _mint_timer XDEF _mint_vbl XREF _timeout ; C time routine XREF _old_timer ; old GEMDOS time vector XREF _old_vbl ; old GEMDOS vbl vector XREF _old_5ms XREF _build_context XREF _restore_context XREF _proc_clock ; controls process' allocation of CPU time XREF _curproc XREF _enter_kernel XREF _leave_kernel XREF _preempt XREF _in_kernel XREF _calc_load_average XREF _uptimetick XREF _checkbttys_vbl ; AKP: this code is hit once every 5ms; it updates the time fields of curproc. _mint_5ms: move.l a0,-(sp) subq.w #1,_uptimetick move.l _curproc,a0 tst.w _in_kernel bne.s L_systime addq.l #5,P_USRTIME(a0) ; update curproc->usrtime move.l (sp)+,a0 move.l _old_5ms+8,-(sp) ; branch to old vector rts L_systime: addq.l #5,P_SYSTIME(a0) ; update curproc->systime move.l (sp)+,a0 move.l _old_5ms+8,-(sp) rts _mint_timer: movem.l d0-d2/a0-a2,-(sp) ; save C registers jsr _timeout movem.l (sp)+,d0-d2/a0-a2 move.l _old_timer+8,-(sp) ; jump to GEMDOS time vector rts _mint_vbl: %ifndef ONLY030 tst.w ($59e).w ; test longframe (AKP) beq.s L_short1 %endif clr.w -(sp) ; yes, long frames: push a frame word L_short1: pea L_comeback(pc) ; push fake PC move.w sr,-(sp) ; push status register move.l _old_vbl+8,-(sp) ; go service the interrupt rts L_comeback: movem.l d0-d2/a0-a2,-(sp) ; save C registers jsr _checkbttys_vbl tst.w _uptimetick bgt.s L_no_uptime jsr _calc_load_average ; Go test if it's time to update uptime L_no_uptime: movem.l (sp)+,d0-d2/a0-a2 tst.w _proc_clock ; has time expired yet? beq.s L_expired ; yes -- maybe go switch processes L_out: rte ; no -- just return L_expired: btst #5,(sp) ; user mode? bne.s L_out ; no -- switching is not possible tst.w ($43e).w ; test floppy disk lock variable bne.s L_out ; if locked, can't switch tst.w _in_kernel ; are we doing a kernel operation? bne.s L_out L_switch: clr.w -(sp) ; no frame format needed move.l _curproc,-(sp) addq.l #P_CTXT0,(sp) ; to get &curproc->ctxt[SYSCALL] jsr _build_context ; build context move.l _curproc,a0 move.l (a0),sp ; use curproc->sysstack move.w P_CTXT0+C_SR(a0),d7 ; get saved int level %ifdef ONLY030 clr.w -(sp) ; not a system call %else move.w #0,-(sp) ; not a system call %endif jsr _enter_kernel ; enter kernel addq.w #2,sp move.w sr,d1 eor.w d1,d7 and.w #$700,d7 eor.w d7,d1 move.w d1,sr ; vbl allowed again jsr _preempt ; yield processor ori.w #$700,sr ; spl7() jsr _leave_kernel ; restore vectors move.l _curproc,a0 pea 4(a0) jsr _restore_context ; back to user ; ; reset routine -- called on a warm boot. Note that TOS sends the ; address to which we should return in register a6. Also note that ; the stack pointer is in an unknown state, so we set up our own ; XDEF _reset XREF _init_tail ; see main.c XREF _restr_intr _reset: move.w #$2700,sr ; avoid interruption here move.l sp,_init_tail ; save A7 lea _init_tail+256,sp ; set up temporary stack movem.l d0-d2/a0-a2,-(sp) ; save C registers jsr _restr_intr ; restore interrupts movem.l (sp)+,d0-d2/a0-a2 ; restore registers move.l _init_tail,sp jmp (a6) ; reset again ; ; routine for doing a reboot ; XDEF _reboot _reboot: move.w #$2700,sr ; avoid interrupts move.l (0).w,sp ; get sp after reboot move.l (4).w,a6 ; get new reboot address jmp _reset ; ; routine for mouse packet handling ; XDEF _newmvec XDEF _newjvec XREF _mouse_handler ; Experimental three button mouse support (by [email protected], ; August 4, 1992 ; ; Should work with the mice shipped with Atari's ASV or ; compatible ones (like Golden Image GI-6000). Might not work ; on ST/STE systems with older IKBD's or keyboards. The middle mouse ; button is wired to one of the joystick directions on joystick one. ; ; _newmvec is the same as before with two exceptions: ; 1. the first byte of the packet is saved for the joystick handler ; 2. the bit for the middle mouse button is ored in ; ; _newjvec hooks into the joystick vector and chains to the normal ; handler. The middle mouse button state is saved in a special ; register for _newmvec, and a 'fake' mouse packet is set up ; (by merging the last mouse packet header, or-ing in the ; middle button state and using 0/0 for the x/y increment). ; ; the faked_packet and third_button variables are declared at the ; end of this file _newmvec: move.l a0,-(sp) move.b (a0),d0 move.b d0,faked_packet or.b third_button,d0 move.b d0,(a0) jsr _mouse_handler move.l (sp)+,a0 rts ; ; routine for joystick packet handling (used for three button mice) ; XDEF _newjvec XREF _oldjvec _newjvec: move.l a0,-(sp) ; save a0 on the stack move.b 2(a0),d0 ; joystick direction and.b #1,d0 ; middle mouse button in lowest bit add.b d0,d0 ; times 4 add.b d0,d0 move.b d0,third_button ; save it for use in newmvec lea faked_packet,a0 ; 'our' faked mouse event move.b (a0),d0 and.b #$3,d0 ; unmask our mouse button or.b #$F8,d0 ; or in correct header or.b third_button,d0 ; or in the current status move.b d0,(a0) ; write it back move.l a0,-(sp) ; pass pointer to fake packet jsr _mouse_handler ; to \dev\mouse handler addq.l #4,sp ; pop parameter move.l (sp)+,a0 ; restore original a0 value move.l _oldjvec,-(sp) ; jump to original joystick handler rts ; ; new ikbd keyboard interrupt vector ; kintr is a global variable that should be non-zero if a keyboard ; event occured ; XDEF _new_ikbd XREF _old_ikbd XREF _kintr _new_ikbd: move.w #1,_kintr move.l _old_ikbd+8,-(sp) rts ; jump to system interrupt routine ; Generic routine for handling any user-specified interrupts. On 68000, the ; vector number is stored in the high byte of the program counter. ; XDEF _new_intr XDEF _sig_user _new_intr: movem.l d0-d2/a0-a2,-(sp) ; save regs %ifndef ONLY030 tst.w ($59e).w ; is frame format on stack? bne.s nvec ; yes, go use it bsr.s ndummy ; push PC to stack nop ndummy: move.w (sp)+,d0 ; pop hi(PC) to d0 addq.w #2,sp ; pop lo(PC) off stack lsr.w #8,d0 ; move hi byte to vector number bra.s ngot ; continue nvec: %endif move.w 30(sp),d0 ; get frame word lsr.w #2,d0 ; move vector offset to vector number ngot: move.w d0,-(sp) ; push vector offset jsr _sig_user ; send signal addq.w #2,sp ; pop vector offset movem.l (sp)+,d0-d2/a0-a2 ; restore regs rte ; ; simple signal handlers ; global variables referenced: ; in_kernel: (main.c): flag to indicate that we're in the MiNT kernel ; sig_routine: (signal.c): pointer to which signal catching routine to ; call (e.g. for SIGBUS, or whatever) ; XDEF _new_bus,_new_addr,_new_ill,_new_divzero,_new_priv,_new_linef XDEF _new_trace,_new_chk,_new_trapv,_new_fpcp,_new_mmu,_new_pmmuacc XDEF _new_uninit,_new_spurious,_new_format,_new_cpv XREF _in_kernel,_sig_routine XREF _sigbus,_sigaddr,_sigill,_sigfpe,_sigpriv,_sigtrap XREF _haltformat,_haltcpv XREF _sig_exc XREF _mcpu ; ; New bus error handler for memory protection: get the ssp and ; put it in the proc structure before calling ; _sigbus. When the bus error happens in the kernel we don't save ; any contexts. ; We don't want to mess up any registers here because we might bring the ; page in and RTE. ; _new_bus: %ifndef ONLY030 move.w #$8,_sig_exc cmp.l #30,_mcpu bne.s noMMU %endif move.l #_mmu_sigbus,_sig_routine %ifndef ONLY030 bra.s Do_sig noMMU: move.l #_nommu_sigbus,_sig_routine %endif Do_sig: move.l a0,-(sp) ; save a0 move.l _curproc,a0 move.l sp,P_EXCSSP(a0) addq.l #4,P_EXCSSP(a0) move.l 6(sp),P_EXCPC(a0) move.l (sp)+,a0 tst.w _in_kernel ; are we already in the kernel? bne.s Kernel ; yes move.w _sig_exc,-(sp) move.l _curproc,-(sp) addq.l #4,(sp) ; push offset of save area jsr _build_context move.l _curproc,a4 move.l (a4),sp ; put us in the system stack %ifdef ONLY030 clr.w -(sp) ; not a GEMDOS call %else move.w #0,-(sp) ; not a GEMDOS call %endif jsr _enter_kernel ; set up kernel vectors addq.w #2,sp move.l _sig_routine,a1 ; get signal handling routine jsr (a1) ; go do it ori.w #$0700,sr ; spl7() jsr _leave_kernel ; leave kernel addq.w #4,a4 ; get context save area address move.l a4,-(sp) ; push it jsr _restore_context ; restore the context ; ; here's what we do if we already were in the kernel ; Kernel: movem.l d0-d2/a0-a2,-(sp) ; save reggies move.l _sig_routine,a1 ; get handler jsr (a1) ; go do it movem.l (sp)+,d0-d2/a0-a2 rte ; ; _mmu_sigbus: a pre-handler for _sigbus. Check the reason for the bus ; error and report if it was a real access fault. ; _mmu_sigbus: move.l a2,-(sp) move.l _curproc,a0 move.l P_EXCSSP(a0),a1 ; a1 is now exception_ssp move.w $A(a1),d0 ; d0 is SSR move.l $10(a1),a1 ; a1 is the access address move.l a1,P_EXCADDR(a0) ; save the access address ptestr d0,(a1),#7,a2 ; a2 is the table address move.l a2,P_EXCTBL(a0) ; save table address in curproc pmove mmusr,P_EXCMMUSR(a0) ; save resulting mmusr in curproc move.l (sp)+,a2 jmp _sigbus ; chain to bus-error handler %ifndef ONLY030 ; ; _nommu_sigbus: handler for bus errors on machines without MMU _nommu_sigbus: move.l _curproc,a0 move.l P_EXCSSP(a0),a1 lea $10(a1),a1 ; point to access address tst.w ($59e).w ; test longframe beq.s NOMMU1 addq.w #8,a1 ; on 68000, address is 8 bytes further NOMMU1: move.l (a1),P_EXCADDR(a0) ; save the access address jmp _sigbus %endif _new_addr: %ifndef ONLY030 move.w #$c,_sig_exc %endif move.l #_sigaddr,_sig_routine bra Do_sig _new_ill: %ifndef ONLY030 move.w #$10,_sig_exc %endif move.l #_sigill,_sig_routine bra Do_sig _new_divzero: %ifndef ONLY030 move.w #$14,_sig_exc %endif move.l #_sigfpe,_sig_routine bra Do_sig _new_linef: %ifndef ONLY030 move.w #$2c,_sig_exc %endif move.l #_sigill,_sig_routine bra Do_sig _new_chk: %ifndef ONLY030 move.w #$18,_sig_exc %endif move.l #_sigfpe,_sig_routine bra Do_sig _new_trapv: %ifndef ONLY030 move.w #$1c,_sig_exc %endif move.l #_sigfpe,_sig_routine bra Do_sig _new_fpcp: ; don't set _sig_exc - only needed for 68000 vectors move.l #_sigfpe,_sig_routine bra Do_sig _new_mmu: ; don't set _sig_exc - only needed for 68000 vectors move.l #_sigill,_sig_routine bra Do_sig _new_pmmuacc: ; don't set _sig_exc - only needed for 68000 vectors move.l #_sigbus,_sig_routine bra Do_sig _new_uninit: %ifndef ONLY030 move.w #$3c,_sig_exc %endif move.l #_sigbus,_sig_routine bra Do_sig _new_spurious: %ifndef ONLY030 move.w #$60,_sig_exc %endif move.l #_sigbus,_sig_routine bra Do_sig _new_format: move.l #_haltformat,_sig_routine bra Do_sig _new_cpv: move.l #_haltcpv,_sig_routine bra Do_sig XREF _old_priv ; old privilege violation vector _new_priv: %ifndef ONLY030 move.w #$20,_sig_exc %endif move.l #_sigpriv,_sig_routine %ifndef ONLY030 tst.w ($59e).w ; 68000s always get SIGPRIV beq Do_sig %endif movem.l d0/a0,-(a7) move.l 10(a7),a0 ; fetch exception address move.w (a0),d0 and.w #$ffc0,d0 ; partially decode move sr,... cmp.w #$40c0,d0 ; and test it movem.l (a7)+,d0/a0 ; preserves the flags bne Do_sig ; doesn't look like sr,... move.l _old_priv+8,-(sp) ; let our parent handle it rts ; XBRA vectors from main.c XREF _old_dos,_old_bios,_old_xbios XREF _old_divzero,_old_chk,_old_trapv _new_trace: btst #5,(a7) ; only check when called from supervisor mode beq.s S_1 cmp.l #_old_dos+12,2(a7) ; lets not trace the kernel ! beq.s S_2 cmp.l #_old_xbios+12,2(a7) beq.s S_2 cmp.l #_old_bios+12,2(a7) beq.s S_2 cmp.l #_old_divzero+12,2(a7) beq.s S_2 cmp.l #_old_trapv+12,2(a7) beq.s S_2 cmp.l #_old_chk+12,2(a7) beq.s S_2 ; add any other non-traceable entities here... S_1: move.w #$24,_sig_exc move.l #_sigtrap,_sig_routine bra Do_sig S_2: and.w #$3fff,(a7) ; clear both trace bits rte ; and re-start the handler ; ; BIOS disk vectors for pseudo-disks like U: and X:; these are present ; just in case some program (foolishly) attempts to access these drives ; directly and gets horribly confused ; XREF _old_getbpb ; old Getbpb vector XREF _old_mediach ; old Mediach vector XREF _old_rwabs ; old Rwabs vector XREF _aliasdrv ; array of drive aliases XDEF _new_getbpb XDEF _new_mediach XDEF _new_rwabs _new_getbpb: move.w 4(sp),d0 ; check the drive cmp.w #$1f,d0 ; legal drive? bhi.s noalias0 ; no move.w d0,d1 ; get index add.w d0,d1 ; convert to index lea _aliasdrv,a0 move.w 0(a0,d1.w),d1 ; alias drive? beq.s noalias0 move.w d1,d0 subq.w #1,d0 ; adjust for aliasdrv base of '@' cmp.w #$1f,d0 ; is this a legal drive? bhi.s nobpb ; no -- ignore it noalias0: cmp.w #$14,d0 ; drive U:? beq.s nobpb ; yes, no BPB available move.l _old_getbpb+8,a0 ; not our drive jmp (a0) ; call the old vector for it nobpb: moveq.l #0,d0 ; 0 means "no BPB read" rts _new_mediach: move.w 4(sp),d0 ; check the drive cmp.w #$1f,d0 ; legal drive? bhi.s noalias1 ; no move.w d0,d1 ; get index add.w d0,d1 ; convert to index lea _aliasdrv,a0 move.w 0(a0,d1.w),d1 ; alias drive? beq.s noalias1 move.w d1,d0 subq.w #1,d0 ; adjust for aliasdrv base cmp.w #$1f,d0 ; legal drive? bhi.s nobpb ; no -- ignore it noalias1: cmp.w #$14,d0 ; drive U:? beq.s nochng ; yes, no change move.l _old_mediach+8,a0 ; not our drive jmp (a0) ; call the old vector for it nochng: moveq.l #0,d0 ; 0 means "definitely no change" rts _new_rwabs: move.w $e(sp),d0 ; check the drive cmp.w #$1f,d0 ; legal drive? bhi.s noalias2 ; no move.w d0,d1 ; get index add.w d0,d1 ; convert to index lea _aliasdrv,a0 move.w 0(a0,d1.w),d1 ; alias drive? beq.s noalias2 move.w d1,d0 subq.w #1,d0 ; adjust for aliasdrv base cmp.w #$1f,d0 ; legal drive? bhi.s nobpb ; no -- ignore it noalias2: cmp.w #$14,d0 ; drive U:? beq.s rwdone ; yes, fake it move.l _old_rwabs+8,a0 ; not our drive jmp (a0) ; call the old vector for it rwdone: moveq.l #0,d0 ; 0 means "successful operation" rts DATA ; buffer for faked mouse packet (actually only 3 bytes) faked_packet: dc.l 0 ; here we store the additional button state third_button: dc.w 0 END
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.