home *** CD-ROM | disk | FTP | other *** search
- ;
- ; Copyright 1992 Eric R. Smith
- ; Copyright 1992,1993 Atari Corporation
- ; All rights reserved.
-
- %include "magic.i"
- ;
- ; routines for saving/restoring user contexts
- ;
- ; long build_context(struct context *sav, short fmt):
- ; Called from an interrupt handler (such as the trap #1 routine
- ; for system calls) saves the context of the interrupted
- ; routine. Assumes that no user registers have been changed
- ; since the interrupt, and that the PC and status register
- ; are still on the stack. Returns the stack pointer being used
- ; at the time of the interrupt **in register a1**.
- ; The fmt parameter is used on the 68000 to communicate the exception
- ; vector number; on >=68010 we use the vector offset from the frame.
- ;
- ; long save_context(struct context *sav):
- ; Saves the context of the calling routine in the area pointed
- ; to by sav. Save_context always returns 0 when initially called;
- ; this is so processes can (by suitably manipulating the
- ; saved registers) tell when the return from save_context is
- ; actually caused by restoring the context, e.g.:
- ; if (save_context(sav) == 0) { <<-- L1
- ; /* do some stuff */
- ; sav.regs[D0] = 1; /* for restore context */
- ; restore_context(sav); /* goes back to L1 */
- ; }
- ; else /* this is the second time through */
- ;
- ; void restore_context(struct context *sav):
- ; Restores a context previously saved by build_context or save_context.
- ; Since the program counter is part of the context, this function
- ; will never return (it's like longjmp()). NOTE: this function should
- ; be used only to change contexts _within_ the same program, since
- ; it does NOT flush the ATC. See change_context
- ;
- ; void change_context(struct context *sav):
- ; Restores a context previously saved by build_context or save_context
- ; for a different process. Unlike restore_context, this one *does*
- ; flush the ATC.
-
- TEXT
-
- XDEF _build_context
- XDEF _save_context
- XDEF _restore_context
- XDEF _change_context
-
- XREF _fpu
- XREF _framesizes
- XREF _new_trace ; from intr.s
- XREF _no_mem_prot
-
- TEXT
- _build_context:
- move.l a0,-(sp) ; save a0; we'll use it for scratch
- move.l 8(sp),a0 ; get address of save area
-
- tst.w _no_mem_prot ; is there memory protection?
- bne.s noprot1
- pmove crp,C_CRP(a0) ; save CRP from MMU
- pmove tc,C_TC(a0) ; save TC from MMU
- noprot1:
- movem.l d0-d7/a0-a6,(a0) ; save registers D0-D7/A0-A6
- clr.b C_PTRACE(a0) ; no pending traces, thanks!
- lea 12(sp),a1 ; start of the interesting stack area
- move.w (a1)+,d0 ; 68000 fake frame format
-
- %ifndef ONLY030
- move.w ($59e).w,d7 ; get process frame flag
- bne.s nojunk ; we have some junk on the stack
- move.w d0,C_SFMT(a0) ; save fake frame format
- subq.w #$8,d0 ; if bus error (note: subq is faster than
- beq.s group0 ; cmp, and we won't need d0 later)
- subq.w #$4,d0 ; or address error ($C==$8+$4)
- bne.s nojunk
- group0: move.l (a1)+,C_INTERNAL(a0) ; stash it in the internal area
- move.l (a1)+,C_INTERNAL+4(a0) ; if a debugger's interested
- nojunk:
- %endif
- move.w (a1)+,d0 ; get SR of context
- move.w d0,C_SR(a0) ; save it
- move.l (a1)+,C_PC(a0) ; save PC of context
- %ifndef ONLY030
- tst.w d7 ; test longframe (AKP)
- beq.s short1 ; short
- %endif
- tst.w _fpu ; is there a true FPU in the system
- beq.s nofpu
- fsave C_FSTATE(a0) ; save internal state frame
- tst.b C_FSTATE(a0) ; if NULL frame then the FPU is not in use
- beq.s nofpu ; skip programmer's model save
- fmovem.x fp0-fp7,C_FREGS(a0) ; save data registers
- fmovem.l fpcr/fpsr/fpiar,C_FCTRL(a0) ; and control registers
- nofpu:
- lea C_SFMT(a0),a2
- move.w (a1)+,d1 ; fetch frame format word
- move.w d1,(a2)+ ; and stash it away for later
- lsr.w #8,d1 ; isolate the frame format identifier
- lsr.w #4,d1
- lea _framesizes,a3
- move.b 0(a3,d1.w),d1
- beq.s short1 ; if no data to save, skip this
- subq.w #1,d1 ; correct for first time through loop
- bcint: move.w (a1)+,(a2)+ ; copy CPU internal state
- bcover: dbf d1,bcint
- short1:
- move.l a1,C_SSP(a0) ; a1 now points above the state frame
- move.l usp,a1 ; save user stack pointer
- move.l a1,C_USP(a0)
- btst #13,d0 ; check for supervisor mode
- beq.s L_CONT1 ; user mode; we already have stack in a1
- L_SUPER1:
- ; moving from the save state buffer
- ; means not testing longframe again. (AKP)
- move.l C_SSP(a0),a1 ; was using super stack pointer before interrupt
- ;
- L_CONT1:
- move.l ($408).w,C_TERM(a0) ; save GEMDOS terminate vector
- move.l (sp)+,C_A0(a0) ; save old register a0
- rts
-
-
- _save_context:
- move.l a0,-(sp) ; save a0
- move.l 8(sp),a0 ; get address of context save area
-
- tst.w _no_mem_prot
- bne.s noprot2
- pmove crp,C_CRP(a0) ; save the CRP from the MMU
- pmove tc,C_TC(a0) ; save the TC from the MMU
- noprot2:
-
- ; if running with a true coprocessor we need to save the FPU state
- tst.w _fpu ; is there a true FPU in the system
- beq.s nofpu2
- fsave C_FSTATE(a0) ; save internal state frame
- tst.b C_FSTATE(a0) ; if NULL frame then the FPU is not in use
- beq.s nofpu2 ; skip programmer's model save
- fmovem.x fp0-fp7,C_FREGS(a0) ; save data registers
- fmovem.l fpcr/fpsr/fpiar,C_FCTRL(a0) ; and control registers
- nofpu2:
- ; note: I am somewhat unsure of this assumption, viz that save_context
- ; can never be called in a situation where a co-processor
- ; mid-instruction stack frame would be required. I suspect this is a
- ; valid assumption, in which case the above FPU code is redundant, the
- ; next line is not however!
-
- clr.w C_SFMT(a0) ; mark as a 4 word stack frame
- clr.b C_PTRACE(a0) ; no pending traces, thanks!
-
- movem.l d0-d7/a0-a6,(a0) ; save D0-D7/A0-A6
- lea 8(sp),a1
- move.l a1,C_SSP(a0) ; save supervisor stack pointer
- ; note that it should be pointing above the PC
- move.l -4(a1),C_PC(a0) ; save PC
- move.l usp,a1
- move.l a1,C_USP(a0) ; save user stack pointer
- move.w sr,C_SR(a0) ; save status register
- move.l ($408).w,C_TERM(a0) ; save GEMDOS terminate vector
- move.l (sp)+,C_A0(a0) ; save old a0
- moveq.l #0,d0 ; return 0
- rts
-
- _restore_context:
- ori.w #$0700,sr ; mask interrupts
- move.l 4(sp),a0 ; address of context save area
-
- ; Switch stacks now - starting now ssp is in the memory space of
- ; the process we're switching to. Thus, we can change memory context
- ; to there.
-
- move.l C_SSP(a0),a1 ; get supervisor stack pointer
- tst.b (a1) ; touch the page for virtual memory programs
- tst.b -63(a1) ; make sure stack can grow
- move.l a1,sp
- move.l C_USP(a0),a1
- move.l a1,usp ; set user stack pointer
- move.l C_TERM(a0),($408).w ; restore GEMDOS terminate vector
-
- ; Set memory context now: actually, this isn't necessary, since
- ; we're coming back to a context in the same process as is running
- ; now.
- ; tst.w _no_mem_prot
- ; bne.s noprot3
- ; pmove C_CRP(a0),crp ; restore MMU root pointer
- ; pmove C_TC(a0),tc ; restore MMU control register
- noprot3:
-
- %ifndef ONLY030
- tst.w ($59e).w ; test longframe (AKP)
- beq.s short3
- %endif
- ; was moveq.l #0,d0, but I don't think that's what was desired */
- moveq.l #0,d1
- lea C_SFMT(a0),a1
- move.w (a1)+,d0 ; fetch frame format word
- move.w d0,d1 ; copy it for later
- lsr.w #8,d1 ; isolate the frame format identifier
- lsr.w #4,d1
- lea _framesizes,a2
- move.b 0(a2,d1.w),d1
- beq.s rcovernc ; if no data to copy, skip the copy
- sub.w d1,sp
- sub.w d1,sp
- move.l sp,a2
- bra.s rcover
- subq.w #1,d1 ; correct for first time through loop
- rcint: move.w (a1)+,(a2)+
- rcover: dbf d1,rcint
- rcovernc:
- move.w d0,-(sp) ; frame format identifier
- ; if running with a true coprocessor we need to restore the FPU state
-
- tst.w _fpu ; is there a true FPU in the system
- beq.s short3
- tst.b C_FSTATE(a0) ; if NULL frame then the FPU is not in use
- beq.s short4 ; skip programmer's model restore
- fmovem.l C_FCTRL(a0),fpcr/fpsr/fpiar ; restore control registers
- fmovem.x C_FREGS(a0),fp0-fp7 ; and data registers
- short4: frestore C_FSTATE(a0) ; finally the internal state
- short3:
- move.l C_PC(a0),-(sp) ; push the PC
- move.w C_SR(a0),-(sp) ; push the status register
- tst.b C_PTRACE(a0) ; check for a pending trace
- movem.l (a0),d0-d7/a0-a6 ; restore registers d0-d7/a0-a6
- beq.s notrace
- jmp _new_trace
- notrace:
- rte ; jump back to old context
-
-
- _change_context:
- ori.w #$0700,sr ; mask interrupts
- move.l 4(sp),a0 ; address of context save area
-
- ; Switch stacks now - starting now ssp is in the memory space of
- ; the process we're switching to. Thus, we can change memory context
- ; to there.
-
- move.l C_SSP(a0),a1 ; get supervisor stack pointer
- tst.b (a1) ; touch the page for virtual memory programs
- tst.b -63(a1) ; make sure stack can grow
- move.l a1,sp
- move.l C_USP(a0),a1
- move.l a1,usp ; set user stack pointer
- move.l C_TERM(a0),($408).w ; restore GEMDOS terminate vector
-
- ; Set memory context now
- tst.w _no_mem_prot
- bne.s noprot4
- pmove C_CRP(a0),crp ; restore MMU root pointer
- pmove C_TC(a0),tc ; restore MMU control register
- noprot4:
- %ifndef ONLY030
- tst.w ($59e).w ; test longframe (AKP)
- beq.s short6
- %endif
- ; was moveq.l #0,d0, but I don't think that's what was desired */
- moveq.l #0,d1
- lea C_SFMT(a0),a1
- move.w (a1)+,d0 ; fetch frame format word
- move.w d0,d1 ; copy it for later
- lsr.w #8,d1 ; isolate the frame format identifier
- lsr.w #4,d1
- lea _framesizes,a2
- move.b 0(a2,d1.w),d1
- beq.s rcover2nc ; if no data to copy, skip it
- sub.w d1,sp
- sub.w d1,sp
- move.l sp,a2
- subq.w #1,d1 ; correct for first time through loop
- rcint2: move.w (a1)+,(a2)+
- rcover2: dbf d1,rcint2
- rcover2nc:
- move.w d0,-(sp) ; frame format identifier
- ; if running with a true coprocessor we need to restore the FPU state
-
- tst.w _fpu ; is there a true FPU in the system
- beq.s short6
- tst.b C_FSTATE(a0) ; if NULL frame then the FPU is not in use
- beq.s short5 ; skip programmer's model restore
- fmovem.l C_FCTRL(a0),fpcr/fpsr/fpiar ; restore control registers
- fmovem.x C_FREGS(a0),fp0-fp7 ; and data registers
- short5: frestore C_FSTATE(a0) ; finally the internal state
- short6:
- move.l C_PC(a0),-(sp) ; push the PC
- move.w C_SR(a0),-(sp) ; push status register
- tst.b C_PTRACE(a0) ; check for a pending trace
- movem.l (a0),d0-d7/a0-a6 ; restore registers d0-d7/a0-a6
- beq.s notrace2
- jmp _new_trace
- notrace2:
- rte ; jump back to old context
-
- END
-