/*
 * osload.S86  -  MGL boot image startup program
 *
 * 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: osload.S86,v 1.7 2007/01/06 18:31:38 gkminix Exp $
 *
 *====================================================================
 */
#define DEF_HEAP_SIZE
#define DEF_STACK_SIZE

#include <common.i86>
#include <system/bios.i86>
#include "headers/osload.i86"

.file __FILE__
.line __LINE__



/*
 *====================================================================
 *
 * Definition of heap and stack size
 */

/* Define some minimal stack */
__stack_size = 1024

/* We dont need any heap */
__heap_size = 0




.line __LINE__
/*
 *====================================================================
 *
 * Define the text segment.
 */

	.text

	.extern	movmem			# externals from runtime library


	.global	_start


_start:

/*
 * Initialize the data and BSS segments. We always assume seperate
 * text and data segments.
 * It is also possible to simply set the stack to a new value, because
 * there is no return once this program has been called.
 */

	call	1f
1:	pop	bx
	sub	bx,offset 1b
	shr	bx,4			# normalize CS to start at zero
	mov	dx,cs
	add	dx,bx
	mov	bx,offset 2f
	push	dx			# jump to normalized address
	push	bx
	lret

2:	mov	bx,offset __text_end
	add	bx,0x000F
	shr	bx,4			# set the data segment to the end
	add	dx,bx			# of the text segment
	mov	ds,dx
	mov	es,dx

	cld
	mov	di,offset __bss_start
	mov	cx,offset __bss_end
	sub	cx,di
	inc	cx			# clear out the BSS segment
	shr	cx,1
	xor	ax,ax
	rep	stosw

	mov	[oldSS],ss		# save old stack pointer
	mov	[oldSP],sp

	mov	ax,(OSLOAD_END - OSLOAD_ADDR) / 16
	sub	ax,bx			# compute end of data area
	shl	ax,4
	sub	ax,2
	add	di,stack_size_value
	cmp	ax,di			# check if we have enough memory space
	jb	8f			# for a stack

	cli
	mov	ss,dx			# set new stack pointer
	mov	sp,ax			# this is necessary because all runtime
	sti				# library routines assume SS = DS

/*
 * We can now go ahead and copy all parts of the boot image to their
 * destination.
 */

	call	getext			# get highest available memory location
	shl	eax,10
	add	eax,0x00100000
	mov	[endmem],eax

	push	es
	mov	ax,IMAGE_REC_ADDR / 16
	mov	es,ax
	mov	si,_I(image_addrs)
1:	mov	eax,es:copy_srcaddr[si]
	mov	ebx,es:copy_destaddr[si]
	mov	ecx,es:copy_copysize[si]
	mov	edx,ebx
	add	edx,ecx
	add	si,COPY_STRUCT_SIZE

	cmp	edx,[endmem]		# check that we are not writing into
	jae	2f			# locations past the physical end
	cmp	ebx,IMAGE_REC_ADDR
	jb	3f			# check that we are not overwriting
	cmp	ebx,OSLOAD_END		# our own program
	jae	4f
2:	pop	es			# terminate with error
	jmp	8f

3:	cmp	edx,IMAGE_REC_ADDR
	jae	2b
4:	call	movmem			# now actually move the memory
	jc	2b
	dec	word ptr es:[image_addrnum]
	jnz	1b			# continue with next copy record

/*
 * Now set all registers as expected for the booted image
 */

5:	cli
	mov	ss,[oldSS]		# switch back to old stack
	mov	sp,[oldSP]
	sti

	push	dword ptr es:[image_startaddr]
	push	word ptr es:[image_reg_es]
	mov	ax,es:[image_reg_ax]
	mov	bx,es:[image_reg_bx]
	mov	cx,es:[image_reg_cx]
	mov	dx,es:[image_reg_dx]
	mov	si,es:[image_reg_si]
	mov	di,es:[image_reg_di]
	mov	ds,es:[image_reg_ds]
	pop	es
	lret				# finally call the loaded image


/*
 * Print an error message and return to the bootrom or BIOS boot vector
 */

8:	cld
	mov	si,offset cpyerr
	call	prnstr			# print error message
	xor	ah,ah			# wait for key press
	int	INT_KBD

	cli
	mov	ss,[oldSS]		# switch back to old stack
	mov	sp,[oldSP]
	sti
	lret				# return to the bootrom



/*
 *====================================================================
 *
 * Print a string onto the console.
 * Input:  DS:SI -  Pointer to string
 * Output: none
 * Changed registers: AX, BX
 */
1:	mov	ah,0x0E			# use BIOS to print character
	mov	bx,0x0007
	int	INT_VIDEO
prnstr:	lodsb				# loop over all characters of
	or	al,al			# string
	jnz	1b
	ret




/*
 *====================================================================
 *
 * Read-only Data area
 */
	_rodata


/* Error message */
cpyerr:	.ascii	"Unable to copy boot image"
	.byte	0x0D,0x0A
	.ascii	"Press any key to reboot..."
	.byte	0




/*
 *====================================================================
 *
 * BSS segment
 */
	.bss


	.lcomm	endmem,4		# end of memory
	.lcomm	oldSS,2			# old stack segment
	.lcomm	oldSP,2			# old stack pointer




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

