; ****************************************************************************
;
;  isolinux.asm
;
;  A program to boot Linux kernels off a CD-ROM using the El Torito
;  boot standard in "no emulation" mode, making the entire filesystem
;  available.  It is based on the SYSLINUX boot loader for MS-DOS
;  floppies.
;
;   Copyright (C) 1994-2001  H. Peter Anvin
;
;  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, Inc., 675 Mass Ave, Cambridge MA 02139,
;  USA; either version 2 of the License, or (at your option) any later
;  version; incorporated herein by reference.
; 
; ****************************************************************************
;
; THIS FILE IS A MODIFIED VERSION OF ISOLINUX.ASM
; MODIFICATION DONE BY MICHAEL K TER LOUW
; LAST UPDATED 3-9-2002
; SEE "COPYING" FOR INFORMATION ABOUT THE LICENSE THAT APPLIES TO THIS RELEASE
;
; ****************************************************************************
;
; This file is a modified version of ISOLINUX.ASM.
; Modification done by Eric Kohl
; Last update 04-25-2002
;
; ****************************************************************************

; Note: The Makefile builds one version with DEBUG_MESSAGES automatically.
;%define DEBUG_MESSAGES                ; Uncomment to get debugging messages

%define WAIT_FOR_KEY


; ---------------------------------------------------------------------------
;   BEGIN THE BIOS/CODE/DATA SEGMENT
; ---------------------------------------------------------------------------

		absolute 0400h
serial_base	resw 4			; Base addresses for 4 serial ports
		absolute 0413h
BIOS_fbm	resw 1			; Free Base Memory (kilobytes)
		absolute 046Ch
BIOS_timer	resw 1			; Timer ticks
		absolute 0472h
BIOS_magic	resw 1			; BIOS reset magic
		absolute 0484h
BIOS_vidrows	resb 1			; Number of screen rows

;
; Memory below this point is reserved for the BIOS and the MBR
;
		absolute 1000h
trackbuf	resb 8192		; Track buffer goes here
trackbufsize	equ $-trackbuf
;		trackbuf ends at 3000h

		struc open_file_t
file_sector	resd 1			; Sector pointer (0 = structure free)
file_left	resd 1			; Number of sectors left
		endstruc

		struc dir_t
dir_lba		resd 1			; Directory start (LBA)
dir_len		resd 1			; Length in bytes
dir_clust	resd 1			; Length in clusters
		endstruc


MAX_OPEN_LG2	equ 2			; log2(Max number of open files)
MAX_OPEN	equ (1 << MAX_OPEN_LG2)
SECTORSIZE_LG2	equ 11			; 2048 bytes/sector (El Torito requirement)
SECTORSIZE	equ (1 << SECTORSIZE_LG2)
CR		equ 13			; Carriage Return
LF		equ 10			; Line Feed
retry_count	equ 6			; How patient are we with the BIOS?



	absolute 5000h				; Here we keep our BSS stuff

DriveNo		resb 1			; CD-ROM BIOS drive number
DiskError	resb 1			; Error code for disk I/O
RetryCount	resb 1			; Used for disk access retries
TimeoutCount	resb 1			; Timeout counter
ISOFlags	resb 1			; Flags for ISO directory search
RootDir		resb dir_t_size		; Root directory
CurDir		resb dir_t_size		; Current directory
ISOFileName	resb 64			; ISO filename canonicalization buffer
ISOFileNameEnd	equ $


		alignb open_file_t_size
Files		resb MAX_OPEN*open_file_t_size



	section .text
	org 7000h

start:
	cli					; Disable interrupts
	xor	ax, ax				; ax = segment zero
	mov	ss, ax				; Initialize stack segment
	mov	sp, start			; Set up stack
	mov	ds, ax				; Initialize other segment registers
	mov	es, ax
	mov	fs, ax
	mov	gs, ax
	sti					; Enable interrupts
	cld					; Increment pointers

	mov	cx, 2048 >> 2			; Copy the bootsector
	mov	si, 0x7C00			; from 0000:7C00
	mov	di, 0x7000			; to 0000:7000
	rep	movsd				; copy the program
	jmp	0:relocate			; jump into relocated code

relocate:
	; Display the banner and copyright
%ifdef DEBUG_MESSAGES
	mov	si, isolinux_banner		; si points to hello message
	call	writestr			; display the message
	mov	si,copyright_str
	call	writestr
%endif


	; Make sure the keyboard buffer is empty
%ifdef WAIT_FOR_KEY
	call	pollchar_and_empty

	; Check for MBR on harddisk
	pusha
	mov	ax, 0201h
	mov	dx, 0080h
	mov	cx, 0001h
	mov	bx, trackbuf
	int	13h
	popa
	jc	.boot_cdrom ; could not read hdd

	push ax
	mov ax, word [trackbuf]
	cmp ax, 0
	je	.boot_cdrom ; no boot sector found (hopefully there are no weird bootsectors which begin with 0)
	pop ax

	; Display the 'Press key' message and wait for a maximum of 5 seconds
	call	crlf
	mov	si, presskey_msg		; si points to 'Press key' message
	call	writestr			; display the message

	mov	byte [TimeoutCount], 5
.next_second:
	mov	eax, [BIOS_timer]		; load current tick counter
	add	eax, 19				; 

.poll_again:
	call	pollchar_and_empty
	jnz	.boot_cdrom

	mov	ebx, [BIOS_timer]
	cmp	eax, ebx
	jnz	.poll_again

	mov	si, dot_msg			; print '.'
	call	writestr
	dec	byte [TimeoutCount]		; decrement timeout counter
	jz	.boot_harddisk
	jmp	.next_second

.boot_harddisk:
	call	crlf

	; Boot first harddisk (drive 0x80)
	mov	ax, 0201h
	mov	dx, 0080h
	mov	cx, 0001h
	mov	bx, 7C00h
	int	13h
	jnc	.go_hd
	jmp	kaboom
.go_hd:
	mov	ax, cs
	mov	ds, ax
	mov	es, ax
	mov	fs, ax
	mov	gs, ax
	mov	dx, 0080h

	jmp	0:0x7C00
%endif

.boot_cdrom:
%ifdef WAIT_FOR_KEY
	call	crlf
	call	crlf
%endif

	; Save and display the boot drive number
	mov	[DriveNo], dl
%ifdef DEBUG_MESSAGES
	mov	si, startup_msg
	call	writemsg
	mov	al, dl
	call	writehex2
	call	crlf
%endif

	; Now figure out what we're actually doing
	; Note: use passed-in DL value rather than 7Fh because
	; at least some BIOSes will get the wrong value otherwise
	mov	ax, 4B01h			; Get disk emulation status
	mov	dl, [DriveNo]
	mov	si, spec_packet
	int	13h
	jc	near spec_query_failed		; Shouldn't happen (BIOS bug)
	mov	dl, [DriveNo]
	cmp	[sp_drive], dl			; Should contain the drive number
	jne	near spec_query_failed

%ifdef DEBUG_MESSAGES
	mov	si, spec_ok_msg
	call	writemsg
	mov	al, byte [sp_drive]
	call	writehex2
	call	crlf
%endif

found_drive:
	; Get drive information
	mov	ah, 48h
	mov	dl, [DriveNo]
	mov	si, drive_params
	int	13h
	jnc	params_ok

	; mov	si, nosecsize_msg	No use in reporting this
	; call	writemsg

params_ok:
	; Check for the sector size (should be 2048, but
	; some BIOSes apparently think we're 512-byte media)
	;
	; FIX: We need to check what the proper behaviour
	; is for getlinsec when the BIOS thinks the sector
	; size is 512!!!  For that, we need such a BIOS, though...
%ifdef DEBUG_MESSAGES
	mov	si, secsize_msg
	call	writemsg
	mov	ax, [dp_secsize]
	call	writehex4
	call	crlf
%endif


	;
	; Clear Files structures
	;
	mov	di, Files
	mov	cx, (MAX_OPEN*open_file_t_size)/4
	xor	eax, eax
	rep	stosd

	;
	; Now, we need to sniff out the actual filesystem data structures.
	; mkisofs gave us a pointer to the primary volume descriptor
	; (which will be at 16 only for a single-session disk!); from the PVD
	; we should be able to find the rest of what we need to know.
	;
get_fs_structures:
	mov	eax, 16			; Primary Volume Descriptor (sector 16)
	mov	bx, trackbuf
	call	getonesec

	mov	eax, [trackbuf+156+2]
	mov	[RootDir+dir_lba],eax
	mov	[CurDir+dir_lba],eax
%ifdef DEBUG_MESSAGES
	mov	si, rootloc_msg
	call	writemsg
	call	writehex8
	call	crlf
%endif

	mov	eax,[trackbuf+156+10]
	mov	[RootDir+dir_len],eax
	mov	[CurDir+dir_len],eax
%ifdef DEBUG_MESSAGES
	mov	si, rootlen_msg
	call	writemsg
	call	writehex8
	call	crlf
%endif
	add	eax,SECTORSIZE-1
	shr	eax,SECTORSIZE_LG2
	mov	[RootDir+dir_clust],eax
	mov	[CurDir+dir_clust],eax
%ifdef DEBUG_MESSAGES
	mov	si, rootsect_msg
	call	writemsg
	call	writehex8
	call	crlf
%endif

	; Look for the "REACTOS" directory, and if found,
	; make it the current directory instead of the root
	; directory.
	mov	di,isolinux_dir
	mov	al,02h				; Search for a directory
	call	searchdir_iso
	jnz	.dir_found
	mov	si,no_dir_msg
	call	writemsg
	jmp	kaboom

.dir_found:
	mov	[CurDir+dir_len],eax
	mov	eax,[si+file_left]
	mov	[CurDir+dir_clust],eax
	xor	eax,eax				; Free this file pointer entry
	xchg	eax,[si+file_sector]
	mov	[CurDir+dir_lba],eax


	mov	di, isolinux_bin		; di points to Isolinux filename
	call	searchdir			; look for the file
	jnz	.isolinux_opened		; got the file
	mov	si, no_isolinux_msg		; si points to error message
	call	writemsg			; display the message
	jmp	kaboom				; fail boot

.isolinux_opened:
	mov	di, si				; save file pointer

%ifdef DEBUG_MESSAGES
	mov	si, filelen_msg
	call	writemsg
	call	writehex8
	call	crlf
%endif

	mov ecx, eax			; calculate sector count
	shr ecx, 11
	test eax, 0x7FF
	jz .full_sector
	inc ecx
.full_sector:

%ifdef DEBUG_MESSAGES
	mov eax, ecx
	mov	si, filesect_msg
	call	writemsg
	call	writehex8
	call	crlf
%endif

	mov	bx, 0x8000			; bx = load address
	mov	si, di				; restore file pointer
	mov	cx, 0xFFFF			; load the whole file
	call	getfssec			; get the whole file

%ifdef DEBUG_MESSAGES
	mov	si, startldr_msg
	call	writemsg
	call	crlf
%endif

	mov	dl, [DriveNo]			; dl = boot drive
	mov dh, 0					; dh = boot partition
	push 0						; push segment (0x0000)
	mov eax, [0x8000 + 0xA8]	; load the RVA of the EntryPoint into eax
	add eax, 0x8000				; RVA -> VA
	push ax						; push offset
	retf						; Transfer control to ROSLDR



;
; searchdir:
;
; Open a file
;
;  On entry:
;	DS:DI	= filename
;  If successful:
;	ZF clear
;	SI		= file pointer
;	DX:AX or EAX	= file length in bytes
;  If unsuccessful
;	ZF set
;

;
; searchdir_iso is a special entry point for ISOLINUX only.  In addition
; to the above, searchdir_iso passes a file flag mask in AL.  This is useful
; for searching for directories.
;
alloc_failure:
	xor	ax,ax				; ZF <- 1
	ret

searchdir:
	xor	al,al
searchdir_iso:
	mov	[ISOFlags],al
	call	allocate_file			; Temporary file structure for directory
	jnz	alloc_failure
	push	es
	push	ds
	pop	es				; ES = DS
	mov	si,CurDir
	cmp	byte [di],'\'			; If filename begins with slash
	jne	.not_rooted
	inc	di				; Skip leading slash
	mov	si,RootDir			; Reference root directory instead
.not_rooted:
	mov	eax,[si+dir_clust]
	mov	[bx+file_left],eax
	mov	eax,[si+dir_lba]
	mov	[bx+file_sector],eax
	mov	edx,[si+dir_len]

.look_for_slash:
	mov	ax,di
.scan:
	mov	cl,[di]
	inc	di
	and	cl,cl
	jz	.isfile
	cmp	cl,'\'
	jne	.scan
	mov	[di-1],byte 0			; Terminate at directory name
	mov	cl,02h				; Search for directory
	xchg	cl,[ISOFlags]
	push	di
	push	cx
	push	word .resume			; Where to "return" to
	push	es
.isfile:
	xchg	ax,di

.getsome:
	; Get a chunk of the directory
	mov	si,trackbuf
	pushad
	xchg	bx,si
	mov	cx,1				; load one sector
	call	getfssec
	popad

.compare:
	movzx	eax, byte [si]			; Length of directory entry
	cmp	al, 33
	jb	.next_sector
	mov	cl, [si+25]
	xor	cl, [ISOFlags]
	test	cl, byte 8Eh			; Unwanted file attributes!
	jnz	.not_file
	pusha
	movzx	cx, byte [si+32]		; File identifier length
	add	si, byte 33			; File identifier offset
	call	iso_compare_names
	popa
	je	.success
.not_file:
	sub	edx, eax			; Decrease bytes left
	jbe	.failure
	add	si, ax				; Advance pointer

.check_overrun:
	; Did we finish the buffer?
	cmp	si, trackbuf+trackbufsize
	jb	.compare			; No, keep going

	jmp	short .getsome			; Get some more directory

.next_sector:
	; Advance to the beginning of next sector
	lea	ax, [si+SECTORSIZE-1]
	and	ax, ~(SECTORSIZE-1)
	sub	ax, si
	jmp	short .not_file			; We still need to do length checks

.failure:
%ifdef DEBUG_MESSAGES
	mov	si, findfail_msg
	call	writemsg
	call	crlf
%endif
	xor	eax, eax			; ZF = 1
	mov	[bx+file_sector], eax
	pop	es
	ret

.success:
	mov	eax, [si+2]			; Location of extent
	mov	[bx+file_sector], eax
	mov	eax, [si+10]			; Data length
	push	eax
	add	eax, SECTORSIZE-1
	shr	eax, SECTORSIZE_LG2
	mov	[bx+file_left], eax
	pop	eax
	mov	edx, eax
	shr	edx, 16
	and	bx, bx				; ZF = 0
	mov	si, bx
	pop	es
	ret

.resume:
	; We get here if we were only doing part of a lookup
	; This relies on the fact that .success returns bx == si
	xchg	edx, eax			; Directory length in edx
	pop	cx				; Old ISOFlags
	pop	di				; Next filename pointer

	mov	byte [di-1], '\'		; restore the backslash in the filename

	mov	[ISOFlags], cl			; Restore the flags
	jz	.failure			; Did we fail?  If so fail for real!
	jmp	.look_for_slash			; Otherwise, next level

;
; allocate_file: Allocate a file structure
;
;		If successful:
;		  ZF set
;		  BX = file pointer
;		In unsuccessful:
;		  ZF clear
;
allocate_file:
	push	cx
	mov	bx, Files
	mov	cx, MAX_OPEN
.check:
	cmp	dword [bx], byte 0
	je	.found
	add	bx, open_file_t_size		; ZF = 0
	loop	.check
	; ZF = 0 if we fell out of the loop
.found:
	pop	cx
	ret

;
; iso_compare_names:
;	Compare the names DS:SI and DS:DI and report if they are
;	equal from an ISO 9660 perspective.  SI is the name from
;	the filesystem; CX indicates its length, and ';' terminates.
;	DI is expected to end with a null.
;
;	Note: clobbers AX, CX, SI, DI; assumes DS == ES == base segment
;
iso_compare_names:
	; First, terminate and canonicalize input filename
	push	di
	mov	di, ISOFileName
.canon_loop:
	jcxz	.canon_end
	lodsb
	dec	cx
	cmp	al, ';'
	je	.canon_end
	and	al, al
	je	.canon_end
	stosb
	cmp	di, ISOFileNameEnd-1		; Guard against buffer overrun
	jb	.canon_loop
.canon_end:
	cmp	di, ISOFileName
	jbe	.canon_done
	cmp	byte [di-1], '.'		; Remove terminal dots
	jne	.canon_done
	dec	di
	jmp	short .canon_end
.canon_done:
	mov	[di], byte 0			; Null-terminate string
	pop	di
	mov	si, ISOFileName
.compare:
	lodsb
	mov	ah, [di]
	inc	di
	and	ax, ax
	jz	.success			; End of string for both
	and	al, al				; Is either one end of string?
	jz	.failure			; If so, failure
	and	ah, ah
	jz	.failure
	or	ax, 2020h			; Convert to lower case
	cmp	al, ah
	je	.compare
.failure:
	and	ax, ax				; ZF = 0 (at least one will be nonzero)
.success:
	ret







;
; getfssec: Get multiple clusters from a file, given the file pointer.
;
;  On entry:
;	ES:BX	-> Buffer
;	SI	-> File pointer
;	CX	-> Cluster count; 0FFFFh = until end of file
;  On exit:
;	SI	-> File pointer (or 0 on EOF)
;	CF = 1	-> Hit EOF
;
getfssec:
	cmp	cx, [si+file_left]
	jna	.ok_size
	mov	cx, [si+file_left]

.ok_size:
	mov	bp, cx
	push	cx
	push	si
	mov	eax, [si+file_sector]
	call	getlinsec
	xor	ecx, ecx
	pop	si
	pop	cx

	add	[si+file_sector], ecx
	sub	[si+file_left], ecx
	ja	.not_eof			; CF = 0

	xor	ecx, ecx
	mov	[si+file_sector], ecx		; Mark as unused
	xor	si,si
	stc

.not_eof:
	ret



; INT 13h, AX=4B01h, DL=<passed in value> failed.
; Try to scan the entire 80h-FFh from the end.
spec_query_failed:
	mov	si,spec_err_msg
	call	writemsg

	mov	dl, 0FFh
.test_loop:
	pusha
	mov	ax, 4B01h
	mov	si, spec_packet
	mov	byte [si], 13			; Size of buffer
	int	13h
	popa
	jc	.still_broken

	mov	si, maybe_msg
	call	writemsg
	mov	al, dl
	call	writehex2
	call	crlf

	cmp	byte [sp_drive], dl
	jne	.maybe_broken

	; Okay, good enough...
	mov	si, alright_msg
	call	writemsg
	mov	[DriveNo], dl
.found_drive:
	jmp	found_drive

	; Award BIOS 4.51 apparently passes garbage in sp_drive,
	; but if this was the drive number originally passed in
	; DL then consider it "good enough"
.maybe_broken:
	cmp	byte [DriveNo], dl
	je	.found_drive

.still_broken:
	dec dx
	cmp	dl, 80h
	jnb	.test_loop

fatal_error:
	mov	si, nothing_msg
	call	writemsg

.norge:
	jmp	short .norge



	; Information message (DS:SI) output
	; Prefix with "isolinux: "
	;
writemsg:
	push	ax
	push	si
	mov	si, isolinux_str
	call	writestr
	pop	si
	call	writestr
	pop	ax
	ret

;
; crlf: Print a newline
;
crlf:
	mov	si, crlf_msg
	; Fall through

;
; writestr: write a null-terminated string to the console, saving
;           registers on entry.
;
writestr:
	pushfd
	pushad
.top:
	lodsb
	and	al, al
	jz	.end
	call	writechr
	jmp	short .top
.end:
	popad
	popfd
	ret


;
; writehex[248]: Write a hex number in (AL, AX, EAX) to the console
;
writehex2:
	pushfd
	pushad
	shl	eax, 24
	mov	cx, 2
	jmp	short writehex_common
writehex4:
	pushfd
	pushad
	shl	eax, 16
	mov	cx, 4
	jmp	short writehex_common
writehex8:
	pushfd
	pushad
	mov	cx, 8
writehex_common:
.loop:
	rol	eax, 4
	push	eax
	and	al, 0Fh
	cmp	al, 10
	jae	.high
.low:
	add	al, '0'
	jmp	short .ischar
.high:
	add	al, 'A'-10
.ischar:
	call	writechr
	pop	eax
	loop	.loop
	popad
	popfd
	ret

;
; Write a character to the screen.  There is a more "sophisticated"
; version of this in the subsequent code, so we patch the pointer
; when appropriate.
;

writechr:
	pushfd
	pushad
	mov	ah, 0Eh
	xor	bx, bx
	int	10h
	popad
	popfd
	ret

;
; Get one sector.  Convenience entry point.
;
getonesec:
	mov	bp, 1
	; Fall through to getlinsec

;
; Get linear sectors - EBIOS LBA addressing, 2048-byte sectors.
;
; Note that we can't always do this as a single request, because at least
; Phoenix BIOSes has a 127-sector limit.  To be on the safe side, stick
; to 32 sectors (64K) per request.
;
; Input:
;	EAX	- Linear sector number
;	ES:BX	- Target buffer
;	BP	- Sector count
;
getlinsec:
	mov si,dapa			; Load up the DAPA
	mov [si+4],bx
	mov bx,es
	mov [si+6],bx
	mov [si+8],eax
.loop2:
	push bp				; Sectors left
	cmp bp,[MaxTransfer]
	jbe .bp_ok
	mov bp,[MaxTransfer]
.bp_ok:
	mov [si+2],bp
	push si
	mov dl,[DriveNo]
	mov ah,42h			; Extended Read
	call xint13
	pop si
	pop bp
	movzx eax,word [si+2]		; Sectors we read
	add [si+8],eax			; Advance sector pointer
	sub bp,ax			; Sectors left
	shl ax,SECTORSIZE_LG2-4		; 2048-byte sectors -> segment
	add [si+6],ax			; Advance buffer pointer
	and bp,bp
	jnz .loop2
	mov eax,[si+8]			; Next sector
	ret

	; INT 13h with retry
xint13:
	mov	byte [RetryCount], retry_count
.try:
	pushad
	int	13h
	jc	.error
	add	sp, byte 8*4			; Clean up stack
	ret
.error:
	mov	[DiskError], ah		; Save error code
	popad
	dec byte [RetryCount]
	jz .real_error
	push ax
	mov al,[RetryCount]
	mov ah,[dapa+2]			; Sector transfer count
	cmp al,2			; Only 2 attempts left
	ja .nodanger
	mov ah,1			; Drop transfer size to 1
	jmp short .setsize
.nodanger:
	cmp al,retry_count-2
	ja .again			; First time, just try again
	shr ah,1			; Otherwise, try to reduce
	adc ah,0			; the max transfer size, but not to 0
.setsize:
	mov [MaxTransfer],ah
	mov [dapa+2],ah
.again:
	pop ax
	jmp .try

.real_error:
	mov	si, diskerr_msg
	call	writemsg
	mov	al, [DiskError]
	call	writehex2
	mov	si, ondrive_str
	call	writestr
	mov	al, dl
	call	writehex2
	call	crlf
	; Fall through to kaboom

;
; kaboom: write a message and bail out.  Wait for a user keypress,
;	  then do a hard reboot.
;
kaboom:
	mov	ax, cs
	mov	ds, ax
	mov	es, ax
	mov	fs, ax
	mov	gs, ax
	sti
	mov	si, err_bootfailed
	call	writestr
	xor	ax, ax		; Wait for keypress
	int	16h
	cli
	mov	word [BIOS_magic], 0	; Cold reboot
	jmp	0F000h:0FFF0h		; Reset vector address


;
; pollchar_and_empty: check if we have an input character pending (ZF = 0) and empty the input buffer afterwards
;
pollchar_and_empty:
	pushad
	mov ah, 1		; Did the user press a key?
	int 16h
	jz	.end		; No, then we're done
	mov ah, 0		; Otherwise empty the buffer by reading it
	int 16h
.end:
	popad
	ret



isolinux_banner	db CR, LF, 'Loading IsoBoot...', CR, LF, 0
copyright_str	db ' (C) 1994-2002 H. Peter Anvin', CR, LF, 0
presskey_msg	db 'Press any key to boot from CD', 0
dot_msg		db '.',0

%ifdef DEBUG_MESSAGES
startup_msg:	db 'Startup, DL = ', 0
spec_ok_msg:	db 'packet OK, drive = ', 0
secsize_msg:	db 'size appears to be ', 0
rootloc_msg:	db 'Root dir loc: ', 0
rootlen_msg:	db 'Root dir len: ', 0
rootsect_msg:	db 'Root dir len(sect): ', 0
fileloc_msg:	db 'SETUPLDR loc: ', 0
filelen_msg:	db 'SETUPLDR len: ', 0
filesect_msg:	db 'SETUPLDR len(sect): ', 0
findfail_msg:	db 'Failed to find file!', 0
startldr_msg:	db 'Starting SETUPLDR.SYS', 0
%endif

nosecsize_msg:	db 'No sector size, assume 0800', CR, LF, 0
spec_err_msg:	db 'Load spec failed, trying wing ...', CR, LF, 0
maybe_msg:	db 'Found smth at drive = ', 0
alright_msg:	db 'might be ok, continuing...', CR, LF, 0
nothing_msg:	db 'Failed locate CD-ROM; boot failed.', CR, LF, 0
isolinux_str	db 'IsoBoot: ', 0
crlf_msg	db CR, LF, 0
diskerr_msg:	db 'Disk error ', 0
ondrive_str:	db ', drive ', 0
err_bootfailed	db CR, LF, 'failed..', 0
isolinux_dir	db '\LOADER', 0
no_dir_msg	db 'LOADER dir not found.', CR, LF, 0
isolinux_bin	db 'SETUPLDR.SYS', 0
no_isolinux_msg	db 'SETUPLDR not found.', CR, LF, 0

;
; El Torito spec packet
;
		align 8, db 0
spec_packet:	db 13h				; Size of packet
sp_media:	db 0				; Media type
sp_drive:	db 0				; Drive number
sp_controller:	db 0				; Controller index
sp_lba:		dd 0				; LBA for emulated disk image
sp_devspec:	dw 0				; IDE/SCSI information
sp_buffer:	dw 0				; User-provided buffer
sp_loadseg:	dw 0				; Load segment
sp_sectors:	dw 0				; Sector count
sp_chs:		db 0,0,0			; Simulated CHS geometry
sp_dummy:	db 0				; Scratch, safe to overwrite

;
; EBIOS drive parameter packet
;
		align 8, db 0
drive_params:	dw 30				; Buffer size
dp_flags:	dw 0				; Information flags
dp_cyl:		dd 0				; Physical cylinders
dp_head:	dd 0				; Physical heads
dp_sec:		dd 0				; Physical sectors/track
dp_totalsec:	dd 0,0				; Total sectors
dp_secsize:	dw 0				; Bytes per sector
dp_dpte:	dd 0				; Device Parameter Table
dp_dpi_key:	dw 0				; 0BEDDh if rest valid
dp_dpi_len:	db 0				; DPI len
		db 0
		dw 0
dp_bus:		times 4 db 0			; Host bus type
dp_interface:	times 8 db 0			; Interface type
db_i_path:	dd 0,0				; Interface path
db_d_path:	dd 0,0				; Device path
		db 0
db_dpi_csum:	db 0				; Checksum for DPI info

;
; EBIOS disk address packet
;
		align 8, db 0
dapa:		dw 16				; Packet size
.count:		dw 0				; Block count
.off:		dw 0				; Offset of buffer
.seg:		dw 0				; Segment of buffer
.lba:		dd 0				; LBA (LSW)
		dd 0				; LBA (MSW)

		alignb 4, db 0
MaxTransfer	dw 2 ;32				; Max sectors per transfer

		times 2046-($-$$) db 0		; Pad to file offset 2046
		dw 0aa55h			; BootSector signature
