#if 0
;  first.S  -  LILO first stage boot loader with LBA32 support */
Copyright 1992-1998 Werner Almesberger.
Copyright 1999-2003 John Coffman.
All rights reserved.

Licensed under the terms contained in the file 'COPYING' in the 
source directory.

#endif
#define LILO_ASM
#include "lilo.h"
get common.s		/* as86 "include" will bypass the CPP */

#if VERSION_MINOR>=50 && VERSION_MINOR<90
# define DEBUG
#endif


!  DELL_DIRTY_HACK	for those systems that disable the video on boot
!	= 0		first stage does not enable video
!	= 1		use get vid mode/set vid mode to enable
!	= 2		use VGA enable call to enable video
!			(cannot use, as code gets too big)
!
#define DELL_DIRTY_HACK 2

! do not change the following -- it must correspond to the code in bsect.c
#define RELOCATABLE -1
#define JRC_NOCOMPACT


	.text

	.globl	_main

	.org	0

zero:
_main:	cli			! NT 4 blows up if this is missing
	jmp	start
	nop
;;	.org	4
reloc:
#if RELOCATABLE
	.word	theend-zero	! size of the code & params
#else
	.word	0		! no size indication
#endif
	.org	6

! Boot device parameters. They are set by the installer.

sig:	.ascii	"LILO"
stage:	.word	STAGE_FIRST
vers:	.word	VERSION



port:	.byte	0		! COM port (0 = unused, 1 = COM1, etc.)
sparam:	.byte	0		! serial port parameters (0 = unused)

raid:	.long	0		! raid sector offset
tstamp:	.long	0		! timestamp
mapstamp: .long 0		! map timestamp

map_serial_no:	.long	0		! volume S/N containing map file


timeout:.word	0		! input timeout
delay:	.word	0		! boot delay

kt_cx:	.word	0		! keyboard translation table
kt_dx:	.word	0
kt_al:	.byte	0

d_addr:	.word	0		! second stage sector map of addresses
	.word	0
	.byte	0

ms_len:	.word	0		! initial greeting message

prompt:	.byte	0		! indicates whether to always enter prompt
				! contains many other flags, too

;;;	.org	CODE_START_1
#if 0
!  These locations are referenced as EX_OFF and must be at CODE_START_1
ext_si:	.word	0		! external interface
ext_es:	.word	0		! these locations are referenced in second.S
ext_bx:	.word	0		! do not disturb the ordering
ext_dl:	.byte	0		! second.S will check this magic number
ext_dh:	.byte	0		! not referenced, but must align stack
ext_stack:
#endif
	
/***************************************************/
!	The following instruction MUST be
!	first instruction after the CLI/JMP short
!	at the start of the file; otherwise
!	the boot sector relocation fails.
!
start:
	mov	ax,#BOOTSEG	! use DS,ES,SS = 0x07C0
/***************************************************/

	mov	ss,ax
	mov	sp,#SETUP_STACKSIZE	! set the stack for First Stage
	sti			! now it is safe

	push	dx		! set ext_dl (and ext_dh, which is not used)
	push	bx		! WATCH the order of pushes
	push	es		! set ext_es
	push	si		! set ext_si

#define JRC_DS_EQ_SS

	cld			! do not forget to do this !!!
	mov	ds,ax		! address data area
	xor	bp,bp		! shorted addressing

#if DELL_DIRTY_HACK && !defined(DEBUG)
#if DELL_DIRTY_HACK==1
	mov	ah,#15		! get video mode
	int	0x10
	cbw
#else
	mov	ax,#0x1200	! enable video (VGA)
	mov	bl,#0x36	! (probably a nop on EGA or MDA)
#endif
	int	0x10		! video call
#endif

#ifdef DEBUG
	mov	ax,#3		! set video mode 3
	int	0x10		! set video mode
#endif

#if DELL_DIRTY_HACK!=1 && !defined(DEBUG)
	mov	al,#0x0d	! gimme a CR ...
	call	display
	mov	al,#0x0a	! ... an LF ...
	call	display
#endif

#if defined(DEBUG)
;;;	mov	ax,dx
	mov	ah,dl
	call	bout		! code in AH
;;;	call	bout		! code in AL
#endif
	mov	al,#0x4c	! ... an 'L' ...
	call	display

	cmp	dl,#EX_DL_MAG	! possible boot command line (chain.S)
	jne	boot_in_dl
	mov	dl,dh		! code passed in DH instead
boot_in_dl:

lagain:
	push	ds
	pop	es		! use buffer at end of boot sector
	mov	bx,#map2	! buffer for volume search
	mov	dh,[d_addr+sa_device](bp)  ! map device & flags to DH

! map is on boot device for RAID1, and if so marked; viz.,

	test	byte ptr [prompt](bp),#FLAG_MAP_ON_BOOT
	jnz	use_boot	! as passed in from BIOS or MBR loader

	mov	dl,dh		! device code to DL
	mov	edi,[map_serial_no](bp)	! to search for
	or	edi,edi
	jz	done_search

	push	dx		! save flags
	mov	dx,#0x80-1	! device 80, head=0
vagain:
	inc	dx
	mov	cx,#1		! cyl=0, sect=1
	mov	ax,#0x201
	int	0x13
	jnc	ck_vol

	pop	dx		! search error
	jmp	done_search	! use code in sector address
ck_vol:
	cmp	edi,[PART_TABLE_OFFSET-6](bx)
	jne	vagain

	pop	ax		! flags in AH
	mov	dh,ah		! flags in DH
use_boot:
done_search:

;;;	mov	bx,#map2	! read second stage map to ES:BX
	mov	si,#d_addr	! ready to load the second stage loader
	push	bx		! save for later in SI
	call	pread		! read using pointer in DS:SI
	mov	ah,#0x99	! possible error code
	cmp	dword (bx-4),#EX_MAG_HL	! "LILO"
	jne	no2idx
	pop	si		! point at #map2

#if 0
	int	0x12		! get memory available
	shl	ax,#6		! convert to paragraphs
	sub	ax,[dataend](bp)	! allow for PARMLINE
	push	ax
#else
	push	#SETUP_STACKSIZE/16 + BOOTSEG + SECTOR_SIZE/16
#endif
	pop	es
	xor	bx,bx

sload:	call	pread		! read using map at DS:SI
	jnz	sload		! into memory at ES:BX (auto increment)

! Verify second stage loader signature
	
	mov	si,#sig		! pointer to signature area
	mov	di,si
	cmpsd			! check Signature 1 & 2
	jne	no2nd		! check Signature 2
#if DELL_DIRTY_HACK==1 && !defined(DEBUG)
/* it would be nice to re-incorporate this check */
	seg es
	  cmp	byte (di),#STAGE_SECOND
	jne	no2nd
#endif
	cmpsw		! skip Stage & Flags

	cmpsw			! check VERSION
	jne	no2nd

! Start the second stage loader     DS=location of Params

	mov	al,#0x49	! display an 'I'
	call	display

	push	es		! segment of second stage
	push	bp		! BP==0
	retf

! error exits below

no2nd:
	mov	ah,#0x9A
no2idx:	push	cx		! display error 99 or 9A

! no return from error
error:
	pop	dx		! restore flags in DH, device code in DL
	pop	cx		! pop return address to  pread or errAH
#ifndef LCF_NO1STDIAG
        mov	al,#32          ! display a space
	call	display

	call	bout
#endif
	xor	ax,ax		! reset the FDC
	int	0x13
	dec	byte [zero](bp)		!  CLI == 0xFA == 250
	jnz	near lagain		! redo from start
#if 1
zzz:
#ifndef DEBUG
	hlt
#endif
	jmp	zzz		! spin; wait for Ctrl-Alt-Del
#else
	mov	cx,#3<<4	! delay 3 seconds, DX does not matter
	mov	ah,#0x86
	int	0x15		! delay call

	int	0x18		! exit to BIOS
#endif

! Pointer Read -- read using pointer in DS:SI

pread:
	push	dx		! protect flags in DX
	lodsw			! get CX
	xchg	cx,ax
        lodsb
	test    al,#LINEAR_FLAG|LBA32_FLAG	! MUST be AL, not DL
	lodsw			! does not affect the flags
        jnz     use_linear

	or	ah,ah		! test count for end of sequence
	jz      done

	mov	dh,al		! heads to DH
	mov     ax,#0x201       ! read command, 1 sector
        int     0x13            ! BIOS read
rd_done:
	jc	error		! error -> start over again
	add	bh,#2    	! next sector
done:
	pop	dx		! restore device code in DL & flags
	ret

use_linear:
	test    dh,#LBA32_FLAG
	jnz     is_lba
	xor     ah,ah           ! was LINEAR, zero the hi-nibble (was count)
is_lba:
        xchg    ax,di
;;;	test	dh,#RAID_REL_FLAG	! I think this can be deleted
;;;	jz	skip_reloc

	add	cx,[raid](bp)	! **** RAID *****
	adc	di,[raid+2](bp)	! **** RAID *****
skip_reloc:

#define JRC_NORETURN
#define JRC_FLAGS_IN_DH
;;;	call	lba_read
#include "read.S"
	br	rd_done

#ifndef LCF_NO1STDIAG
bout:	rol     ax,4            ! bring hi-nibble to position
	call	nout
	rol     ax,4            ! bring lo-nibble to position
nout:	and	al,#0x0F	! display one nibble
	daa			! shorter conversion routine
	add	al,#0xF0
	adc	al,#0x40	! is now a hex char 0..9A..F
#endif
; display - write byte in AL to console
;	clobbers BX
; 
display:  push  ax              ! new display does not affect AX
	mov	bx,#7		!  BH=0, BL=07
	mov	ah,#14
	int	0x10
	pop     ax
	ret			! side effect, BH=0


theend:

!
!   If 'first' loads as the MBR, then there must be space for the partition
!   table.  If 'first' loads as the boot record of some partition, then
!   the space reserved below is not used.  But we must reserve the area
!   as a hedge against the first case.
!
!
	.org	MAX_BOOT_SIZE	!
	.word	0,0,0,0		! space for NT, DRDOS, and LILO volume S/N

!	.org	0x1be		! spot for the partition table
p_table:
	.blkb	16
	.blkb	16
	.blkb	16
	.blkb	16
	.word	0xAA55		! boot block signature

! Better be exactly 0x200

map2	equ	*		! addressed as ES:[map2]
