.text

.align 4 

.globl _Sync_Save_Context
.def _Sync_Save_Context; .scl 2; .type 32; .endef

.globl _Load_Context 
.def _Load_Context; .scl 2; .type 32; .endef


/* Investiigating the possiblility of passing the scheduler */
/* function address as parameter so to save replication of  */
/* code */
_Sync_Save_Context:

/* ------------------------------------------------------------ */
/* |                    SYNC_SAVE_CONTEXT                     | */
/* |  This function is used to store the context of the       | */
/* |  currently executing thread of execution.                | */
/* |  All registers are preserved (Except the segment regs    | */
/* |  which i couldnt touch for some reason).  It does not    | */
/* |  follow C calling conventions - I had trouble with it    | */
/* |  seg-faulting etc, when i tried.                         | */
/* |----------------------------------------------------------| */
/* | INSTRUCTION COUNT = 24 Excluding Segment Registers       | */
/* |----------------------------------------------------------| */

/*;;;  Switch off interrupts. */
/*;;;  cli  <- will leave this till a later date. */
			
/*;;;  Push the flags to the stack.*/

	/*pushfd*/

/*;;;  Push the two work registers to the stack.*/
	pushl %eax

/*;;;  Find the save area of the thread that has been interrupted.*/
	call _Find_Me


/*;;;  Re-enable interrupts.*/
/*;;;  sti  <-- as with cli, will implement later. (will require additional */
/*;;;  privilidged, which if the programs buggy will crash linux as nausum)*/
		
/*;;;  ebx has the save area location */

/*;;;  save the non-work registers. */

	movl %ebp, (%eax)  
	movl %ecx, 16(%eax)
	movl %edx, 20(%eax)
	movl %esi, 24(%eax)
	movl %edi, 28(%eax)
	movl %ebx, 12(%eax)

	
/*; ---------------------------------------------------------------*/
/*; |  Linux had a problem with reading and writing to segment    |*/
/*; |  registers.  hmmmmm...  seems to go ok anyway               |*/
/*; |  Ill keep the following saves and loads here to see if they |*/
/*; |  will run when i start running the program in supervisor    |*/
/*; |  mode.  Heres hoping....*/
/*; ---------------------------------------------------------------*/
/*;  ALSO CS IN HERE.*/
/*;       mov [eax + 34], ds*/
/*;       mov [eax + 36], ss*/
/*;       mov [eax + 38], es*/
/*;       mov [eax + 40], fs*/
/*;       mov [eax + 42], gs*/
		
/*;;;  Save the work registers */
/*;;;  this mov ecx, ebx might not be necessary since we can pop into*/
/*;;;  ecx as if it were ebx.*/

/*;;;  restore the origional values of ebx and eax off the stack.*/

	popl %ebx		/*; restore EAX's old value.*/

	movl %ebx, 8(%eax) 	/*; now store those values into their slots*/

/*;;  now ebx is stored it is usable, to put the flags into the save slot*/
/*	popl %ecx                 ; next up on the stack are the flags.*/
/*	movl %ecx, 44(%eax)	  ; which also have a slot in the save area.*/
		
/*;;;  store EIP in the save area.*/
	popl %ecx		/* Finally the instruction pointer is left*/
	movl %ecx, 48(%eax)	/*; and that goes in its slot too.*/

/*;;;  save the stack pointer now the stack is empty*/
	movl %esp, 4(%eax)

	call _Schedule	
	ret


/*;;; -------------------------------------------------------------*/
/*;;; |	   		    LOAD_CONTEXT                        |*/
/*;;; |  The function Load_Context takes the address of the save  |*/
/*;;; |  area of the thread to be run.  It does not use C calling |*/
/*;;; |  conventions as it has only one parameter, and its not    |*/
/*;;; |  necessary.                                               |*/
/*;;; |-----------------------------------------------------------|*/
/*;;; | INSTRUCTION COUNT	= 18 (Excluding Segment Registers)	|*/
/*;;; -------------------------------------------------------------*/

	
_Load_Context:

/*;  the first parameter sits at ebp + 8 when you have pushed EBP*/
	movl 4(%esp), %ebx

/*;;;  when flow of control hits here, its as if nothing in between*/
/*;;;  had ever happened. */
	
/*;;;  EBX now contains the save area.*/

/*;;;  These two instructions must not be interrupted as we could*/
/*;;;  only have a half working stack at the time. :-)*/

/*;;;  INTERRUPTS DISABLED*/
	movl (%ebx), %ebp
	movl 4(%ebx), %esp
/*;;;  INTERRUPTS ENABLED*/

	movl 8(%ebx), %eax
	movl 20(%ebx), %edx
	movl 24(%ebx), %esi
	movl 28(%ebx), %edi

/*;-------------------------------------------------------------*/
/*;|  See the above problem I had with the segment registers   |*/
/*;-------------------------------------------------------------*/
/*;       mov ds, [ebx + 34]*/
/*;       mov ss, [ebx + 36]*/
/*;       mov es, [ebx + 38]*/
/*;       mov fs, [ebx + 40]*/
/*;       mov gs, [ebx + 42]*/


	
/*;;;  Using ecx i now restore the flags*/
/*	movl 44(%ebx), %ecx */
/*	pushl %ecx */
	/*popfd*/
	
/*;;;  Note; the alternative JMP ecx will mean that ecx is destroyed on an*/
/*;;;  interrupt.  not something i find attactive... */
	movl 48(%ebx), %ecx
	pushl %ecx

	movl 16(%ebx), %ecx
	
/*;;;  The next 4 lines restore ebx.  eax is preserved.*/
	pushl %eax
	movl %ebx, %eax
	movl 12(%eax), %ebx
	popl %eax

	ret

