File:  [Atari MiNT] / MiNT / src / context.spp
Revision 1.1.1.5 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 17:59:02 2018 UTC (8 years, 1 month ago) by root
Branches: mint, MAIN
CVS tags: mint112, HEAD
MiNT 1.12

;

; Copyright 1992 Eric R. Smith

; Copyright 1992,1993,1994 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

	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


unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.