--- trunk/reactos/boot/freeldr/bootsect/isoboot.asm 2006-01-31 07:37:05 UTC (rev 63)
+++ trunk/reactos/boot/freeldr/bootsect/isoboot.asm 2006-01-31 18:58:49 UTC (rev 64)
@@ -0,0 +1,1015 @@
+; ****************************************************************************
+;
+; 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
+.kbd_buffer_test:
+ call pollchar
+ jz .kbd_buffer_empty
+ call getchar
+ jmp .kbd_buffer_test
+.kbd_buffer_empty:
+
+ ; Check if there is harddisk
+ pusha
+ mov ax, 0800h
+ mov dx, 0080h
+ int 13h
+ popa
+ jc .boot_cdrom
+
+ ; 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
+ 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
+ jmp 0:0x8000 ; jump into OSLoader
+
+
+
+;
+; 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
+ call getchar
+ cli
+ mov word [BIOS_magic], 0 ; Cold reboot
+ jmp 0F000h:0FFF0h ; Reset vector address
+
+getchar:
+.again:
+ mov ah, 1 ; Poll keyboard
+ int 16h
+ jz .again
+.kbd:
+ xor ax, ax ; Get keyboard input
+ int 16h
+.func_key:
+ ret
+
+
+;
+; pollchar: check if we have an input character pending (ZF = 0)
+;
+pollchar:
+ pushad
+ mov ah,1 ; Poll keyboard
+ int 16h
+ popad
+ ret
+
+
+
+isolinux_banner db CR, LF, 'Loading IsoBoot...', CR, LF, 0
+copyright_str db ' Copyright (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 'Starting up, DL = ', 0
+spec_ok_msg: db 'Loaded spec packet OK, drive = ', 0
+secsize_msg: db 'Sector size appears to be ', 0
+rootloc_msg: db 'Root directory location: ', 0
+rootlen_msg: db 'Root directory length: ', 0
+rootsect_msg: db 'Root directory length(sectors): ', 0
+fileloc_msg: db 'SETUPLDR.SYS location: ', 0
+filelen_msg: db 'SETUPLDR.SYS length: ', 0
+filesect_msg: db 'SETUPLDR.SYS length(sectors): ', 0
+findfail_msg: db 'Failed to find file!', 0
+startldr_msg: db 'Starting SETUPLDR.SYS', 0
+%endif
+
+nosecsize_msg: db 'Failed to get sector size, assuming 0800', CR, LF, 0
+spec_err_msg: db 'Loading spec packet failed, trying to wing it...', CR, LF, 0
+maybe_msg: db 'Found something at drive = ', 0
+alright_msg: db 'Looks like it might be right, continuing...', CR, LF, 0
+nothing_msg: db 'Failed to locate CD-ROM device; 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, 'Boot failed: press a key to retry...'
+isolinux_dir db '\LOADER', 0
+no_dir_msg db 'Could not find the LOADER directory.', CR, LF, 0
+isolinux_bin db 'SETUPLDR.SYS', 0
+no_isolinux_msg db 'Could not find SETUPLDR.SYS.', 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
[truncated at 1000 lines; 3426 more skipped]