[comp.sys.atari.st] How to call the bios from within process termination handlers

dmb@TIS.COM (David M. Baggett) (01/06/90)

The original thread was about changing resolution from within a
process termination handler (i.e., a function installed at the GEM 
process termination vector 0x102).

Atari's Allan Pratt claimed that you can call Setscreen from within
such a handler.  He was indeed correct.  (I was a bit skeptical after
the 36th crash, but now I Believe.)

HOWEVER, my frustrating attempts to get this to work indicate that the
OS hooks are different in his compiler than in Sozobon C.  Calling
Setscreen with Sozobon's standard xbios() call will cause an exception.
I.e., adding *just*

	Setscreen(-1L, -1L, 1);

to my process termination handler causes the handler to RTS to an
illegal instruction.  Note that this call is #defined in
<osbind.h> and turns into 

	xbios(5, -1L, -1L, 1)

(i.e., it calls the xbios hook in dstart.o, provided with Sozobon).

For the hell of it, I tried writing my own xbios hook, assuming
Sozobon's stack checking was causing the problem.  It wasn't the
stack checking.  (At least, that wasn't the only thing.)

Saving the stack pointer before the trap and restoring it afterwards
fixes things.  I don't know why the bios trashes the stack when called
from a termination handler.  Perhaps a wizardly Atari person could
comment.

Also, I'm wondering if dstart.o is in error for not saving the 
stack pointer, or if Atari is in error for writing bios code
that trashes the stack pointer, or if somebody else is in
error (maybe me).  (Well, _somebody_ has to be in error!  Who
can we flame if no one's in error?)

In any case, anyone who's having trouble getting bios calls to work
from a termination handler (and I believe this is a problem in Laser C
as well) should try using the OS hooks below.  They work with Sozobon,
and as far as I know should work with other C's too.

Dave Baggett
dmb@TIS.COM

----------------------------------- >8 ---------------------------------------

;
; Operating system hooks for C with stack pointer saves.
; These are useful for calling bios routines from within a process termination
; function; i.e., a function installed at GEM process termination vector 0x102
;
; (Modified from Dlibs code in dstart.o)
;

.globl	__gemdos __bios __xbios

;
; long _gemdos(function, [parameter, ...])
;   int function;
;
__gemdos:

	move.l	(A7)+, traprtn		; save return address
	move.l	A7, saveA7		; save stack pointer
	trap	#1			; do gemdos trap
	move.l	saveA7, A7		; restore stack pointer
	move.l	traprtn, -(A7)		; put return address back
	rts				; return

;
; long _bios(function, [parameter, ...])
;   int function;
;
__bios:
	
	move.l	(A7)+, traprtn		; save return address
	move.l	A7, saveA7		; save stack pointer
	trap	#13			; do bios trap
	move.l	saveA7, A7		; restore stack pointer
	move.l	traprtn, -(A7)		; put return address back
	rts				; return

;
; long _xbios(function, [parameter, ...])
;   int function;
;
__xbios:
	move.l	(A7)+, traprtn		; save return address
	move.l	A7, saveA7		; save stack pointer
	trap	#14			; do xbios trap
	move.l	saveA7, A7		; restore stack pointer
	move.l	traprtn, -(A7)		; put return address back
	rts				; return

		bss
		even

traprtn:
	ds.l	1			; storage for return PC in trap hooks

saveA7:
	ds.l	1			; storage for stack pointer in traps

apratt@atari.UUCP (Allan Pratt) (01/10/90)

dmb@TIS.COM (David M. Baggett) writes:
>I.e., adding *just*
>	Setscreen(-1L, -1L, 1);
>to my process termination handler causes the handler to RTS to an
>illegal instruction.  Note that this call is #defined in
><osbind.h> and turns into 
>	xbios(5, -1L, -1L, 1)
>(i.e., it calls the xbios hook in dstart.o, provided with Sozobon).
>
>Saving the stack pointer before the trap and restoring it afterwards
>fixes things.

I don't believe it's a question of the stack pointer.  When you return
from the BIOS your sp is ALWAYS what it was before you went in.
(How else could anything work?)

I think it's a reentrancy problem.  The OS hooks seem to use external
storage, meaning they're non-reentrant.  Worse, they all use the SAME
external location, so in a given program, you can't call BIOS from
BIOS, but you also can't call XBIOS from BIOS! 

(Study the flow of a BIOS call which calls XBIOS when both go through
the same hook: the mainline calls BIOS, saving the return PC someplace.
That BIOS code calls XBIOS, saving it's return PC IN THE SAME PLACE!)

On the other hand, it shouldn't matter, since the Pterm call in question
never returns.

Hooks like this can be made reentrant by changing how they work:
instead of this:

	move.l	(sp)+,trapret		; save return PC
	trap	#$x
	move.l	trapret,-(sp)		; restore return PC
	rts

you could use this:

	movem.l	4(sp),d0-d2/a0-a2	; get 6 longs' worth of args
	movem.l	d0-d2/a0-a2,-(sp)	; push them
	trap	#$x
	add.w	#24,sp
	rts

This uses no external storage (and therefore is reentrant).  The point
is to give the trap the intended args without the hook's own return PC
in the way.  The first method pops the PC off and saves it, while the
second method does it by copying the args into a new stack frame.

dmb@TIS.COM (David M. Baggett) (01/10/90)

Oops, I screwed up.  As Allan Pratt and Dave Berger have pointed out,
you can't call GEMDOS from within a process termination handler.  So
ignore the new _gemdos hook in my original posting.  It most definitely
will not work.  The _bios and _xbios hooks are fine, though.

Sorry 'bout that.

Dave Baggett
dmb@TIS.COM