/ .file "swap.s.386"
/ ident "@(#)cls4:lib/task/task/swap.s.386 1.4"
/ ##############################################################################
/
/ C++ source for the C++ Language System, Release 3.0. This product
/ is a new release of the original cfront developed in the computer
/ science research center of AT&T Bell Laboratories.
/
/ Copyright (c) 1993 UNIX System Laboratories, Inc.
/ Copyright (c) 1991, 1992 AT&T and UNIX System Laboratories, Inc.
/ Copyright (c) 1984, 1989, 1990 AT&T. All Rights Reserved.
/
/
/ THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE of AT&T and UNIX System
/
/ Laboratories, Inc. The copyright notice above does not evidence
/ any actual or intended publication of such source code.
/
/
/ ##############################################################################
/
/ swap of DEDICATED
/ call swap(*running_task, *to_run_task, is_new_child, running_is_terminated)
/ This routine saves the fp in running's t_framep.
/ If running is a SHARED task, we must save its stack size as well,
/ although the stack does not need to be copied out here.
/ It then restores to_run's t_framep to be the current fp.
/ If to_run is a new child, it explicitly restores the registers from
/ New_task_regs, and returns without restoring the regs saved in the stack.
/ If to_run is not a new child, it restores all the registers saved in
/ the frame on returning.
/ If running_task is TERMINATED, then we don't need to do a save.
/ NOTE: assumes all functions return values in eax.
.text
.globl swap
swap:
pushl %ebp / save caller's fp
movl %esp,%ebp / fp = sp
pushl %edi / save all user regs: edi, esi, ebx
pushl %esi
pushl %ebx
movl 12(%ebp),%edx / edx = to_run
movl 20(%ebp),%eax / eax = running_is_terminated
cmpl $1,%eax / if eax == 1
je .L_RESTORE / skip the save
movl 8(%ebp),%eax / eax = running
/ save state of running task
movl %ebp,20(%eax) / running->t_framep = fp (ebp)
movl 52(%eax),%ecx / %ecx = running->t_mode
cmpl $2,%ecx / if running-t_mode == SHARED
jne .L_RESTORE
/ the code here to save the t_size is the same as for sswap
movl 32(%eax),%ecx / ecx = running->t_basep
subl %esp,%ecx / ecx = running->t_basep - sp
addl $4,%ecx / (size in bytes)
shrl $2,%ecx / ecx /= 4 (size in ints)
movl %ecx,36(%eax) / running->t_size = ecx
.L_RESTORE:
movl 16(%ebp),%ecx / ecx = is_new_child
/ restore state of to_run task
movl 20(%edx),%ebp / ebp (fp) = to_run->t_framep
/ if is_new_child, restore registers
jcxz .L_RET / if ecx==0; go to .L_RET
/ new child task effectively returns from task::task, so we need
/ to set the return value to "this"
movl 24(%edx),%eax / eax = to_run->th
leal New_task_regs,%edx / edx = address of New_task_regs
movl 0(%edx),%edi
movl 4(%edx),%esi
movl 8(%edx),%ebx
/ Note: leave resets sp relative to fp, so don't need to reset sp
/ for NEW_CHILD case.
leave
ret
.L_RET:
/ The i386 restores registers relative to sp, so we need to reset
/ to-runs's sp. We add 3 words (n saved regs) to the fp to get the sp.
movl %ebp,%edx
sub $12,%edx
movl %edx,%esp
/ restore all user regs: edi, esi, ebx
popl %ebx
popl %esi
popl %edi
leave
ret
/ swap of SHARED
/ sswap(*running, *prevOnStack, *to_run, is_new_child, running_is_terminated)
/ This routine saves the fp in running's t_framep and the stack size in t_size.
/ Then it copies out the target stack to prevOnStack's t_savearea.
/ If to_run is not a new child, it then copies the saved stack of to_run
/ (from t_savearea) to the target stack, and then restores to_run's t_framep
/ to be the current fp. We don't need to restore state of a child
/ to_run object, because it's already in place.
/ If running_task is TERMINATED, then we don't need to do a save,
/ NOTE: assumes all functions return values in eax.
/ and if running_task is TERMINATED and equals prevOnStack, then we don't
/ have to do the stack copy.
.text
.globl sswap
sswap:
pushl %ebp / save caller's fp
movl %esp,%ebp / fp = sp
pushl %edi / save all user regs: edi, esi, ebx
pushl %esi
pushl %ebx
movl 8(%ebp),%eax / eax = running
movl 12(%ebp),%edi / edi = prevOnStack
movl 24(%ebp),%ecx / ecx = running_is_terminated
cmpl $1,%ecx / if ecx == 1
je .L_SKIP / skip the save
/save hw state of running
movl %ebp,20(%eax) / running->t_framep = fp (ebp)
movl 32(%eax),%ecx / ecx = running->t_basep
subl %esp,%ecx / ecx = running->t_basep - sp
addl $4,%ecx / (size in bytes)
shrl $2,%ecx / ecx /= 4 (size in ints)
movl %ecx,36(%eax) / running->t_size = ecx
jmp .L_SAVE
.L_SKIP: /if running is TERMINATED and running == prevOnStack,
/then we can skip the stack copy too
cmpl %eax,%edi / if running == prevOnStack
je .L_REST / skip save
.L_SAVE: /copy out target stack to prevOnStack->t_savearea
movl 36(%edi),%ecx / ecx = prevOnStack->t_size (count)
pushl %ecx / push count arg on stack
call swap_call_new / get count bytes of storage
popl %ecx / pop arg off stack
sall $2,%ecx / scale ecx to bytes
addl %ecx,%eax / eax = base of new stack, plus 1 long
subl $4,%eax / eax = base of new stack (to)
movl %eax,40(%edi) / prevOnStack->t_savearea = eax (to)
movl 32(%edi),%esi / esi = prevOnStack->t_basep (from)
movl %eax,%edi / edi = to
shrl $2,%ecx / ecx /= 4 = size in ints (count)
pushf / save old DF
std / set DF for copy from hi to lo addr
rep; smovl / copy words
popf / retore DF
.L_REST:
movl 20(%ebp),%eax / eax = is_new_child
testl %eax,%eax / if is_new_child != 0
jne .L6 / skip the copy-in loop
/copy into target stack from to_run->t_savearea
movl 16(%ebp),%ebx / ebx = to_run
movl 32(%ebx),%eax / eax = to_run->t_basep (to)
movl 36(%ebx),%ecx / ecx = to_run->t_size (count)
/ Kick up the sp if new stack will be taller than current.
sall $2,%ecx / ecx = new stack height in bytes
subl %ecx,%eax / eax = base - size = target sp (+ 1)
subl %esp,%eax / eax = eax - sp
testl %eax,%eax
jge .L3 / if eax < 0
addl %eax,%esp / kick up sp
.L3:
movl 32(%ebx),%edi / edi = to_run->t_basep (to)
movl 36(%ebx),%ecx / ecx = to_run->t_size (count)
movl 40(%ebx),%esi / esi = to_run->t_savearea (from)
pushf / save old DF
std / set DF for copy from hi to lo addr
rep; smovl / copy words
popf / retore DF
/ restore state of to_run
movl 20(%ebx),%ebp / fp (a6) = to_run->t_framep
/ to (edi) points to one word beyond new sp
addl $4,%edi
movl %edi,%esp / reset sp, so regs can be restored
/ finally, delete to_run's t_savearea
movl 36(%ebx),%ecx / ecx = to_run->t_size
sall $2,%ecx / scale size to bytes
movl 40(%ebx),%eax / eax = to_run->t_savearea
subl %ecx,%eax / get low address of savearea
addl $4,%eax
pushl %eax / push pointer to savearea on stack
call swap_call_delete / delete to_run->t_savearea
popl %eax / pop arg off stack
movl $0,40(%ebx) / to_run->t_savearea = 0
/ sp should be correct here, for both is and is not new child cases
.L6: / restore all user regs: edi, esi, ebx
popl %ebx
popl %esi
popl %edi
leave
ret
|