/*
 * loader/loader-bsect.S
 *
 * Bootsector loader.
 *
 * Copyright (c) Tuomo Valkonen 1996-1998.
 */

#include <chos/module.h>
#include <chos/chos.h>
#include <chos/mapfile.h>
#include <chos/address.h>
#include <chos/module.h>

.globl _main

.org    LOADER_OFF

_main:	jmp	load_bootsect

.org    LOADER_OFF+2
chos_id:	.ascii	"CHO"		  ! cs:2 = "COS"
chos_stage:	.byte	BIT_BOOTSECT|0x10 ! cs:3 = type
chos_major:	.byte	CHOS_MAJOR	  ! cs:6 = major version #
chos_minor:	.byte   CHOS_MINOR	  ! cs:7 = minor version #

load_bootsect:
	CALL(tell_loading)

	mov	di,#BSECT_OFF
	mov	si,#MAP_OFF
	mov	cx,#256
	rep
	movsw

// Bootsector rewrite support code
////////////////////////////////////
#ifdef SUPPORT_REWRITE

	mov	si,image
	cmp	byte ptr (si+BID_RWDEV_OFF),#0
	je	boit

	/* load MBR */
/*	mov	ax,#0x0000	! set es = $0000
	push	ax		! to load to 
	pop	es		! $0000:$0600
	mov	bx,#0x0600	! set bx = $0600

	mov	ch,#0x0		! cylinder
	mov	cl,#0x1		! sector (bit 6&7 noch cylinder)
	mov	dh,#0x0		! head
	mov	dl,(si+BID_RWDEV_OFF) !#0x80	! /dev/hda

	mov	ah,#0x02	! read sector function
	mov	al,#0x01	! read 1 sector
	int	0x13	
*/
	/* compare flags */	
	mov	al, [0x07be]	! compare active flag part1
	cmp	al, [0x7dbe]
	jnz	rewrite

	mov	al, [0x07c2]	! compare part1 type
	cmp	al, [0x7dc2]
	jnz	rewrite

	mov	al, [0x07ce]	! compare active flag part2
	cmp	al, [0x7dce]
	jnz	rewrite

	mov	al, [0x07d2]	! compare part2 type
	cmp	al, [0x7dd2]
	jnz	rewrite

	mov	al, [0x07de]	! compare active flag part3
	cmp	al, [0x7dde]
	jnz	rewrite

	mov	al, [0x07e2]	! compare part3 type
	cmp	al, [0x7de2]
	jnz	rewrite

	mov	al, [0x07ee]	! compare active flag part4
	cmp	al, [0x7dee]
	jnz	rewrite

	mov	al, [0x07f2]	! compare part4 type
	cmp	al, [0x7df2]
	jnz	rewrite
boit:
	jmp	bootit

rewrite:
#ifndef NO_BEEP
	/* beep */
        mov     ah,#0x0e	! print char
        mov     al,#0x07	! "bell"
        mov     bl,#0x00	! no color	
        int     0x10		! do "beep" 
#endif

	/* copy flags */
	mov 	al,[0x7dbe]	! copy part1 active flag
	mov 	[0x07be],al
	mov 	al,[0x7dc2]	! copy part1 type
	mov 	[0x07c2],al

	mov 	al,[0x7dce]	! copy part2 active flag
	mov 	[0x07ce],al
	mov 	al,[0x7dd2]	! copy part2 type
	mov 	[0x07d2],al

	mov 	al,[0x7dde]	! copy part3 active flag
	mov 	[0x07de],al
	mov 	al,[0x7de2]	! copy part3 type
	mov 	[0x07e2],al

	mov 	al,[0x7dee]	! copy part4 active flag
	mov 	[0x07ee],al
	mov 	al,[0x7df2]	! copy part4 type
	mov 	[0x07f2],al

	/* rewrite MBR */
	mov	ax,#0x0000	! set es = $0000
	push	ax		! to save from
	pop	es		! $0000:$0600
	mov	bx,#0x0600	! set bx = $0600

	mov	ch,#0x0		! cylinder
	mov	cl,#0x1		! sector (bit 6&7 noch cylinder)
	mov	dh,#0x0		! head
	mov	dl,(si+BID_RWDEV_OFF) !#0x80	! /dev/hda

	mov	ah,#0x03	! save sector function
	mov	al,#0x01	! save 1 sector
	int	0x13	

bootit:

#endif /* SUPPORT_REWRITE */

	CALL(end_load)

// Restore image descriptor address in si if necessary
////////////////////////////////////////////////////////
#if defined(SUPPORT_DRIVESWAP) || \
    defined(SUPPORT_DOS4BOOT)  || \
    defined(SUPPORT_DOSMENUKEY)
	mov	si,image
#endif

// Do possible drive swapping
///////////////////////////////
#ifdef SUPPORT_DRIVESWAP
	xor	al,al
	test	(si+BID_FLAGS_OFF),#BS_SWAPHD
	jz	no_swaphd
	inc	al
	mov	byte ptr swaphd,#1
no_swaphd:
	test	(si+BID_FLAGS_OFF),#BS_SWAPFD
	jz	no_swapfd
	inc	al
	mov	byte ptr swapfd,#1
no_swapfd:	
	cmp	al,#0
	je	no_swap_at_all
	push	si
	call	instswap13
	pop	si
no_swap_at_all:
#endif

// Possibly tell dos4.0+ to boot off hdb
//////////////////////////////////////////
#ifdef SUPPORT_DOS4BOOT
	test	(si+BID_FLAGS_OFF),#BS_DOS4BOOT
	jz	no_dos4swap
#ifdef VERIFY_DOS4
	cmp	byte ptr BSECT_OFF+0x26,#0x29
	je	dos4
	mov	si,#baddos
	CALL(print)
no_dos4:
	jmp	no_dos4
dos4:
#endif
	mov	byte ptr BSECT_OFF+0x24,#0x81
no_dos4swap:
#endif

// Possibly put some keystrokes into buffer
/////////////////////////////////////////////
#ifdef SUPPORT_DOSMENUKEY
	cmp	word ptr (si+BID_KEYPRESS_OFF),#0
	je	no_keypress

	cmp	byte ptr ask_cmdline,#1
	je	no_keypress

	call	empty_keyboard_buffer

	// Put the key into buffer
	mov	ah,#0x5
	mov	cx,word ptr(si+BID_KEYPRESS_OFF)
	int	#0x16
	cmp	al,#0
	jne	keypress_fail

	// Put enter into buffer
	mov	ah,#0x5
	mov	cx,#0x1c0d
	int	#0x16
	cmp	al,#0
	je	no_keypress
keypress_fail:
	push	si
	mov	si,#str_fail_doskey
	CALL(print)
	call	empty_keyboard_buffer
	pop	si
no_keypress:
#endif

// Go!
////////
	// Uncommenting this may help some boot problems...
#if 0
	mov	dh,(si+BID_DRIV_OFF)
	mov	dl,#0x0		// Actually should be head number but
	mov	si,#0x7be0	//  this'll have to do...
	xor	ax,ax
	mov	ds,ax
	mov	es,ax
	mov	bp,#0
	mov	ax,#0xaa55
#endif
#if 0	
	jmpi	#0,#BOOT_SEG
#else
	// FreeDOS fails with the above.
	// --> Jump to 0000:7c00 instead of 07c0:0000
	//     Seems to work...

	jmpi	#BOOT_SEG*16,#0
#endif

#ifdef SUPPORT_DOSMENUKEY
// Empties bios keyboard buffer
/////////////////////////////////
empty_keyboard_buffer:
#ifndef __NO_ALTERNATE_KEYBOARD_BUFFER_EMPTY
	// This may not work on some non-standard systems.
	mov	ax,#0x40
	mov	es,ax
	seg	es
	mov	ax,[0x1c]	// Get buffer tail
	seg	es
	mov	[0x1a],ax	// Set buffer head
	ret
#else
	// This doesn't seem to work as it should. If you in the menu, say,
	// press 'down' many times, this just hangs:
	// int16/1 claims there is a key waiting in the buffer (in this case
	// down-key! And yet there shouldn't be such key in the buffer since
	// you've last pressed 'enter'!) but int16/0 waits for the user to
	// press a key and after that int16/1 still thinks there is
	// a key waiting... bios bug??

	mov	ah,#0x1
	int	#0x16
	//cmp	ax,#0
	//jne	keyboard_not_empty
	jnz	keyboard_not_empty
	ret
keyboard_not_empty:
	mov	ah,#0x0
	int	#0x16
	jmp	empty_keyboard_buffer
#endif

str_fail_doskey:.ascii "Could not put a keypress in buffer!"
		.byte	0xd,0
#endif

// Data
/////////
baddos:	.ascii	"Not DOS 4.0+! (maybe compile without -DVERIFY_DOS4?)"
	.byte	0xd,0

// Drive swapper
//
// Stole this from lilo - i was too lazy to write my own.
// I did, though, some enhancements - you can swap both fd and hd.
//
// TODO: swap any hd with any hd/any fd with any fd
//
// **** THIS CODE IS UNTESTED ***
////////////////////////////////////////////////////////////////////////

#ifdef SUPPORT_DRIVESWAP

instswap13:
	seg	es		! allocate 1 kB
	dec	word ptr [0x413]
	int	0x12		! get start segment
	mov	cl,#6
	shl	ax,cl
	cli			! disable interrupts
	xor	bx,bx		! zero a few registers
	mov	di,bx
	seg	es		! change offset
	xchg	bx,[0x4c]
	mov	old13of,bx
	mov	bx,ax		! change segment
	seg	es
	xchg	bx,[0x4e]
	mov	old13sg,bx
	mov	es,ax		! move drive swapper
	mov	si,#new13
	mov	cx,#new13end-new13
	rep
	movsb
	sti			! enable interrupts
	ret			! done

new13:	seg	cs		! save function code
	mov	fcode-new13,ah
	test	dl,#0x80	! hard disk drive ?
	jz	floppy
	seg	cs
	cmp	byte ptr swaphd-new13,#1
	jne	noswap
	jmp	swap
floppy:
	seg	cs
	cmp	byte ptr swapfd-new13,#1
	jne	noswap
swap:
	xor	dl,#1		! swap drive 0 and 1
	seg	cs
	mov	byte ptr didswap-new13,#1
noswap:	pushf
	.byte	0x9a		! CALL FAR
old13of:.word	0
old13sg:.word	0
	pushf			! fix drive number if necessary
	seg	cs
	cmp	byte ptr fcode-new13,#8	! do not fix
	je	done13
	seg	cs
	cmp	byte ptr fcode-new13,#0x15 ! do not fix
	je	done13
	seg	cs
	cmp	byte ptr didswap-new13,#1
	jne	done13
	xor	dl,#1		! fix it
	seg	cs
	mov	byte ptr didswap-new13,#0
done13:	seg	cs
	mov	tmpbx-new13,bx	! restore flags
	mov	bx,sp
	seg	ss
	pop	6(bx)
	seg	cs
	mov	bx,tmpbx-new13
	iret			! done
//new13end:
fcode:	.byte	0		! function code
tmpbx:	.word	0
swapfd:	.byte	0
swaphd:	.byte	0
didswap:.byte	0
new13end:

#endif /* SUPPORT_DRIVESWAP */
