[comp.sys.isis] Bug report: NOSUNLWP under V1.3.1 on Sparc Stations

ken@gvax.cs.cornell.edu (Ken Birman) (03/13/90)

If you use ISISV1.3.1 on a Sparcstation you may have been tempted
to disable SUNLWP by my recent mail pointing out that the ISIS native
tasks are much faster and give smaller object codes.

We just identified a bug in this situation, however, and you should
patch clib/cl_setjmp.s and protos/pr_setjmp.s if you want to run ISIS
this way.  V2.0 fixes this bug, so you can also wait for the next release.

The following is the corrected code; it is shorted and "correct".
        ENTRY(isis_setjmp)
        t       ST_FLUSH_WINDOWS        ! (won't be needed here in V2.0)
        st      %o7, [%o0 + PCVAL]      ! return pc
        st      %sp, [%o0 + SPVAL]      ! save caller's sp
        retl
        clr     %o0                     ! return zero

        ENTRY(isis_longjmp)
        t       ST_FLUSH_WINDOWS        ! flush all reg windows to the stack.
        sub     %sp, WINDOWSIZE, %sp    ! establish new save area (paranoid)
        ld      [%o0 + SPVAL], %fp      ! build new stack frame
        ld      [%o0 + PCVAL], %o7      ! get new return pc
        retl
        restore %o1, 0, %o0             ! return (val)

The logic is as follows:

setjmp merely records the caller's frame; this will be used to force
a register restore when doing a long-jump.  It also notes the return address
to jump to.  No need to do anything else.  Returns 0 in this case.

The T_FLUSH_WINDOWS is actually not needed in most calls to setjmp; the only
time we really need to do this in a call to setjmp is immediately prior
to loading the new stack pointer value in cl_task.c or pr_task.c.  
Since many calls to swtch() switch tasks without creating a new one, in
V2.0 we have eliminated the extra (costly!) trap in setjmp and move it
to the asm sequence in pr_task.c. You can do this too if you like.  Put
a line asm("t   0x3");  right before the asm("sethi _stackp,%o0"); 
asm("ld   [%o0+_stackp],%sp") sequence.   0x3 is the code for T_FLUSH_WINDOWS.

Longjmp is the tricky case.  First, it flushes the callers registers to
the stack.  Then, it makes room for a frame that can be used if the kernel
fields an interrupt just after we load the destination framepointer
but before the restore is executed that forces the underflow trap and
loads in the destination registers.  With this new frame in place, we can
safely muck with the %i registers (in particular, loading the new %fp value,
which will become the new %sp value after the restore) and the return
address we want (%o7 gets this).  We do a retl-restore sequence even
though there was no prior save because we have artificially constructed
a frame as if save had been used at the entry.

Thanks to Steve Kleiman at SUN for helping us understand how to do this
correctly.