/*
    LWThreads.S, Copyright  (c) by Claudio Jeker, Boris Lutz
    Swiss Federal Institute of Technology,
    Computer Engineering and Networks Laboratory.

    TOPSY -- A Teachable Operating System.
             Implementation of a tiny and simple
             micro kernel for teaching purposes.

    For further information, please visit http://www.tik.ee.ethz.ch/~topsy

    This software is provided under the terms of the GNU General Public Licence.

    A full copy of the GNU GPL is provided in the file COPYING found in the 
    development root of Topsy.
*/
/*
	
	File:                  $Source: /home/ruf/cvs_Topsy/cvs/Topsy/ThreadsLight/ia32/LWThreads.S,v $
	Author(s):             George Fankhauser, Claudio Jeker
	Affiliation:           ETH Zuerich, TIK
	Version:               $Revision: 2922 $
	Creation Date:         
	Last Date of Change:   $Date: 2007-03-19 17:48:52 +0100 (Mon, 19 Mär 2007) $      by: $Author: baderma $
	
*/

#include "asm.h"

/* Define the offsets for accessing the LWThreadContext, 
   if LWThreads.h changes this needs to be modified too */
/* struct LWThreadArrayDesc (LWTAD) */
#define	NNUM		0	// unsigned int N
#define nNUM		4	// unsigned int n
#define CUR			8	// ThreadId     current
#define STACK		12	// char*        stack
#define ARY			16	// LWThread     a
/* struct LWThreadDesc */
#define MSG			0
#define FROM		4
#define STATE		8
#define NEXT		12
#define PREV		16
#define STACKP		20
#define FRAMEP		24
#define	PROGC		28
#define SIZE		5	/* the size is 32 Byte or 1 << 0x5 */
/* THE SIZE_OF LWThreadDesc HAS TO BE 2^N */

	ASM_PROC_FRAME(lwSwitchTo)
	
	/* first save EBP and let it point to the same */
	/* location as ESP does to access arguments after */
	/* the context is saved */
	pushl	%ebp
	movl	%esp,%ebp
	
	/* save all important registers (es, ds, fs, gs) */
	/* don't need to be save since it's only a LWSwich */
	pushal

	/* let EBX point to the first arg */
	movl	ARG1,%ebx

	/* let's save some of the registers to the context */
	/* structure in lw (passed as arg1) */
	movl	ARY(%ebx),%eax	/* eax = lw->a */
	movl	CUR(%ebx),%ebx
	shll	$SIZE,%ebx
	add		%eax,%ebx		/* ebx = lw->a[lw->current] */
	movl	%esp,STACKP(%ebx)
	movl	0(%ebp),%ecx
	movl	%ecx,FRAMEP(%ebx)
	movl	4(%ebp),%ecx
	movl	%ecx,PROGC(%ebx)
	

	/* get the context of the new LW-Thread */
	movl	ARG1,%eax		/* lw */
	movl	ARG2,%ebx		/* to */
	movl	%ebx,CUR(%eax)	/* lw->current = to */
	shll	$SIZE,%ebx
	add		ARY(%eax),%ebx	/* ebx = lw->a[to] */
	movl	STACKP(%ebx),%esp
	popal
	/* popal has got a wrong ebp (change before pushal) */
	/* get back the saved ebp */
	popl	%ebp
	ret

//	.end lwSwitchTo

// extern lwJumpToParam(LWPool lw, ThreadId to, ThreadArg parameter);
	ASM_PROC_FRAME(lwJumpToParam)
	
	/* first save EBP and let it point to the same */
	/* location as ESP does to access arguments after */
	/* the context is saved */
	pushl	%ebp
	movl	%esp,%ebp
	
	/* save all important registers (es, ds, fs, gs) */
	/* don't need to be save since it's only a LWSwitch */
	pushal

	/* let EBX point to the first arg */
	movl	ARG1,%ebx

	/* let's save some of the registers to the context */
	/* structure in lw (passed as arg1) */
	movl	ARY(%ebx),%eax	/* eax = lw->a */
	movl	CUR(%ebx),%ebx
	shll	$SIZE,%ebx
	add		%eax,%ebx		/* ebx = lw->a[lw->current] */
	movl	%esp,STACKP(%ebx)
	movl	0(%ebp),%ecx
	movl	%ecx,FRAMEP(%ebx)
	movl	4(%ebp),%ecx
	movl	%ecx,PROGC(%ebx)
	

	/* get the context of the new LW-Thread */
	movl	ARG1,%eax		/* lw */
	movl	ARG2,%ebx		/* to */
	movl	%ebx,CUR(%eax)	/* lw->current = to */
	shll	$SIZE,%ebx
	add		ARY(%eax),%ebx	/* ebx = lw->a[to] */
	/* save parameter for later use */
	movl	ARG3,%eax
	movl	ARG1,%ecx
	movl	STACKP(%ebx),%esp
	movl	FRAMEP(%ebx),%ebp
	pushl	%eax /* parameter to new function */
	pushl	%ecx /* parameter to new function */
	/* jump or call the new function */
	call	PROGC(%ebx)
	
//	.end lwJumpToParam

