/*
 * pxe.S86  -  PXE API handling
 *
 * Copyright (C) 2003-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: pxe.S86,v 1.5 2007/01/06 18:30:51 gkminix Exp $
 *
 *====================================================================
 */


#include <common.i86>
#include <pxe/general.i86>
#include <pxe/entry.i86>

.file __FILE__
.line __LINE__



/*
 *====================================================================
 *
 * Start the text segment and define all public entry points
 */

	.text

	.global	initpxe
	.global	dopxe



/*
 *====================================================================
 *
 * Check if we have a valid PXENV+ structure
 * Input:  ES:BX  -  Pointer to PXENV+ structure
 * Output: AX     -  PXE error code
 * Registers changed: AX, CX, DX, SI, DI
 */
pxenv_chk:

	mov	ax,PXENV_STATUS_LOADER_NO_PXENV
	mov	si,offset pxenv_sig
	mov	di,bx			# check if the structure starts with the
	mov	cx,6			# signature
	repe	cmpsb
	jne	9f

	movzx	cx,byte ptr es:o_pe_length[bx]
	cmp	cx,pxentry_size - 4	# check size of structure (without !PXE
	jb	9f			# pointer)

	mov	dx,es:o_pe_version[bx]
	cmp	dh,2			# we have to have at least version
	jb	9f			# 2.0

	mov	di,bx
	xor	dl,dl			# compute checksum
1:	add	dl,es:[di]
	inc	di
	loop	1b
	or	dl,dl			# check if checksum is zero
	jnz	9f
	xor	ax,ax			# return without error
9:	ret



/*
 *====================================================================
 *
 * Check if we have a valid !PXE structure
 * Input:  ES:BX  -  Pointer to !PXE structure
 * Output: AX     -  PXE error code
 * Registers changed: AX, CX, EDX, DI
 */
pxe_chk:

	mov	ax,PXENV_STATUS_LOADER_NO_PXE
	mov	edx,[pxe_sig]		# check if the structure starts with
	cmp	edx,es:o_ps_sig[bx]	# the signature
	jne	9f

	movzx	cx,byte ptr es:o_ps_length[bx]
	cmp	cx,pxe_struct_size	# check size of structure
	jb	9f

	mov	di,bx
	xor	dl,dl			# compute checksum
1:	add	dl,es:[di]
	inc	di
	loop	1b
	or	dl,dl			# check if checksum is zero
	jnz	9f
	xor	ax,ax			# return without error
9:	ret



/*
 *====================================================================
 *
 * Initialize PXE API handling
 * Input:  ES:BX  -  Address of either !PXE or PXENV+ structure
 * Output: AX     -  PXE error code
 * Registers changed: AX, CX, EDX, SI, DI
 */
initpxe:

	push	es
	push	bx
	mov	ax,es			# check if address is valid
	or	ax,bx
	jz	1f

	call	pxenv_chk		# check if its a PXENV+ pointer
	or	ax,ax
	jz	2f
	call	pxe_chk			# check if its a !PXE pointer
	or	ax,ax
	jnz	1f			# save !PXE pointer and exit
	mov	word ptr [pxestruct + 0],bx
	mov	word ptr [pxestruct + 2],es
	jmp	9f

1:	mov	ax,PXE_IN_MAGIC
	int	INT_PXE			# get PXENV+ pointer
	cmp	ax,PXE_OUT_MAGIC
	mov	ax,PXENV_STATUS_LOADER_NO_PXE
	jne	9f
	call	pxenv_chk		# check if we got a valid PXENV+
	or	ax,ax			# pointer
	jnz	9f

2:	xor	ax,ax			# save PXENV+ pointer
	mov	word ptr [pxenvstruct + 0],bx
	mov	word ptr [pxenvstruct + 2],es
	mov	dx,es:o_pe_version[bx]
	cmp	dh,2
	jb	9f
	ja	3f			# check that we have at least version
	cmp	dl,1			# 2.1 of the PXENV+ structure, if not
	jb	9f			# there is no !PXE pointer

3:	les	bx,es:o_pe_pxe_ptr[bx]	# get !PXE pointer
	call	pxe_chk
	or	ax,ax			# the !PXE pointer has to be valid
	jnz	9f
	mov	word ptr [pxestruct + 0],bx
	mov	word ptr [pxestruct + 2],es

9:	pop	bx
	pop	es
	ret



/*
 *====================================================================
 *
 * Call the PXE API
 * Input:  DI  -  Offset to parameter structure
 *         BX  -  Function opcode
 * Output: AX  -  Error code
 * Registers changed: AX
 */
dopxe:

	push	es
	push	si

	les	si,[pxestruct]
	mov	ax,es			# check if we have a !PXE structure
	or	ax,si
	jz	1f
	push	ds
	push	di
	push	bx			# call PXE API using !PXE convention
	lcall	es:o_ps_pxentry16[si]
	add	sp,6
	jmp	9f

1:	les	si,[pxenvstruct]
	mov	ax,es			# check if we have a PXENV+ structure
	or	ax,si
	jz	8f
	push	bp
	mov	bp,sp
	push	dword ptr es:o_pe_rm_entry[si]
	mov	ax,ds
	mov	es,ax
	lcall	[bp - 4]		# call PXE API using PXENV+
	add	sp,4			# convention
	pop	bp
	jmp	9f

8:	mov	ax,PXENV_EXIT_FAILURE	# return with error if no API found
	mov	word ptr [di],PXENV_STATUS_BAD_FUNC
9:	pop	si
	pop	es
	ret




/*
 *====================================================================
 *
 * String and constant definitions
 */
	_rodata

/* Structure signatures */
pxenv_sig:	.ascii	"PXENV+"
pxe_sig:	.ascii	"!PXE"




/*
 *====================================================================
 *
 * Variable definitions
 */
	.bss

	.global	pxestruct
	.global	pxenvstruct

	.lcomm	pxestruct,4		# pointer to !PXE structure
	.lcomm	pxenvstruct,4		# pointer to PXENV+ structure




/*
 *====================================================================
 */
	.end

