/*
 **************************************************************************
 *
 * Boot-ROM-Code to load an operating system across a TCP/IP network.
 *
 * Module:  utility.S86
 * Purpose: Various functions for the image loader routines, which are
 *          better written in assembler
 * Entries: _exec_image, _getfbm, _setfbm
 *
 **************************************************************************
 *
 * Copyright (C) 1995-2007 Gero Kuhlmann <gero@gkminix.han.de>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 * $Id: utility.S86,v 1.10 2007/01/06 18:30:46 gkminix Exp $
 *
 */


/*
 **************************************************************************
 *
 * Include assembler macros:
 *
 */
#include <common.i86>
#include <romconfig.i86>
#include <system/bios.i86>

.file __FILE__
.line __LINE__



/*
 **************************************************************************
 *
 * Start code segment.
 *
 */
	.text

	.global	_exec_image
	.global	_getfbm
	.global	_setfbm

	.extern	stkptr
	.extern	rmdata




/*
 **************************************************************************
 *
 * Determine current base of free memory
 * Input:  none
 * Output: base of free memory (in kB)
 * Registers changed: AX
 */
_getfbm:

	push	es
	mov	ax,BIOS_SEG
	mov	es,ax
	mov	ax,es:[BIOS_BASEMEM]
	pop	es
	ret



/*
 **************************************************************************
 *
 * Set base of free memory
 * Input:  1. arg  -  base of free memory (AX)
 * Output: none
 * Registers changed: none
 */
_setfbm:

	push	es
	push	dx
	mov	dx,BIOS_SEG
	mov	es,dx
	mov	es:[BIOS_BASEMEM],ax
	pop	dx
	pop	es
	ret



/*
 **************************************************************************
 *
 * Execute the boot image
 * Input: 1. arg  -  load mode (AX)
 *        2. arg  -  far pointer to execution point
 *        3. arg  -  far pointer to header
 *        4. arg  -  near pointer to parameter block
 * Output: A non-zero value in AX means to reload a new image.
 * Registers changed: EAX
 */
_exec_image:

	enter	0,0
	push	esi			# save index registers for return
	push	edi			# to C code
	push	ebx
	push	ecx
	push	edx
	push	ds
	push	es

#define execptr	_ARG(0)
#define hdrptr	_ARG(1)
#define parmptr	_ARG(2)

/*
 * First setup the new stack, and copy all required parameters onto
 * it. Also set the return address and the address to call. The switch
 * to the new stack.
 */

	mov	dx,ax
	mov	word ptr cs:[stkptr],sp

	mov	ax,ds
	mov	bx,cs			# compute new stack address
	cmp	ax,bx
	jae	3f
	mov	bx,ax
3:	sub	bx,0x1000
	mov	es,bx			# let ES:DI point to top of new
	mov	di,0xFFFA		# stack

	std				# copy from top down
	shl	eax,16
	mov	ax,[bp + parmptr]	# save parameter pointer onto the
	stosd				# new stack
	mov	eax,[bp + hdrptr]	# save the header pointer onto the
	stosd				# new stack
	cmp	dx,3
	jne	1f
	mov	eax,[pxeptr]
	stosd				# copy pointer to PXE structure
1:	mov	ax,cs
	shl	eax,16			# copy return address
	mov	ax,offset 2f
	stosd
	mov	eax,[bp + execptr]	# copy address to call
	stosd
	shr	eax,16
	mov	cx,ax			# save executable segment for later
	mov	eax,[pxenvptr]
	stosd				# copy pointer to PXENV structure
	mov	es:[di + 2],cx		# save new data segment
	cld

	cli
	mov	ss,bx			# switch to new stack
	lea	sp,[di + 2]
	sti

/*
 * Now call the image. We have the pointer to the PXENV structure, the
 * address to call and the return address already on the stack
 */

	pop	ds			# get new data segment
	pop	bx			# get pointer to PXENV structure
	pop	es
	lret				# call the loaded image

/*
 * The loaded image will return here, so restore the old stack.
 */

2:	cli
	mov	ss,cs:[rmdata]
	mov	sp,cs:[stkptr]		# restore old stack pointer
	sti

	pop	es
	pop	ds			# restore all previously saved
	pop	edx			# registers
	pop	ecx
	pop	edx
	pop	edi
	pop	esi
	leave
	ret

#undef execptr
#undef hdrptr
#undef parmptr




/*
 **************************************************************************
 *
 * BSS segment:
 */
	.bss

	.extern	pxeptr
	.extern	pxenvptr




/*
 **************************************************************************
 *
 */

	.end

