--- /dev/null
+; ****************************************************************************\r
+;\r
+; isolinux.asm\r
+;\r
+; A program to boot Linux kernels off a CD-ROM using the El Torito\r
+; boot standard in "no emulation" mode, making the entire filesystem\r
+; available. It is based on the SYSLINUX boot loader for MS-DOS\r
+; floppies.\r
+;\r
+; Copyright (C) 1994-2001 H. Peter Anvin\r
+;\r
+; This program is free software; you can redistribute it and/or modify\r
+; it under the terms of the GNU General Public License as published by\r
+; the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,\r
+; USA; either version 2 of the License, or (at your option) any later\r
+; version; incorporated herein by reference.\r
+; \r
+; ****************************************************************************\r
+;\r
+; THIS FILE IS A MODIFIED VERSION OF ISOLINUX.ASM\r
+; MODIFICATION DONE BY MICHAEL K TER LOUW\r
+; LAST UPDATED 3-9-2002\r
+; SEE "COPYING" FOR INFORMATION ABOUT THE LICENSE THAT APPLIES TO THIS RELEASE\r
+;\r
+; ****************************************************************************\r
+;\r
+; This file is a modified version of ISOLINUX.ASM.\r
+; Modification done by Eric Kohl\r
+; Last update 04-25-2002\r
+;\r
+; ****************************************************************************\r
+;\r
+; This file is a modified version of ISOLINUX.ASM.\r
+; (for ReactOS regression testing)\r
+; Modification done by Christoph von Wittich\r
+; Last update 08-27-2006\r
+;\r
+; ****************************************************************************\r
+\r
+\r
+; Note: The Makefile builds one version with DEBUG_MESSAGES automatically.\r
+;%define DEBUG_MESSAGES ; Uncomment to get debugging messages\r
+\r
+%define WAIT_FOR_KEY\r
+\r
+\r
+; ---------------------------------------------------------------------------\r
+; BEGIN THE BIOS/CODE/DATA SEGMENT\r
+; ---------------------------------------------------------------------------\r
+\r
+ absolute 0400h\r
+serial_base resw 4 ; Base addresses for 4 serial ports\r
+ absolute 0413h\r
+BIOS_fbm resw 1 ; Free Base Memory (kilobytes)\r
+ absolute 046Ch\r
+BIOS_timer resw 1 ; Timer ticks\r
+ absolute 0472h\r
+BIOS_magic resw 1 ; BIOS reset magic\r
+ absolute 0484h\r
+BIOS_vidrows resb 1 ; Number of screen rows\r
+\r
+;\r
+; Memory below this point is reserved for the BIOS and the MBR\r
+;\r
+ absolute 1000h\r
+trackbuf resb 8192 ; Track buffer goes here\r
+trackbufsize equ $-trackbuf\r
+; trackbuf ends at 3000h\r
+\r
+ struc open_file_t\r
+file_sector resd 1 ; Sector pointer (0 = structure free)\r
+file_left resd 1 ; Number of sectors left\r
+ endstruc\r
+\r
+ struc dir_t\r
+dir_lba resd 1 ; Directory start (LBA)\r
+dir_len resd 1 ; Length in bytes\r
+dir_clust resd 1 ; Length in clusters\r
+ endstruc\r
+\r
+\r
+MAX_OPEN_LG2 equ 2 ; log2(Max number of open files)\r
+MAX_OPEN equ (1 << MAX_OPEN_LG2)\r
+SECTORSIZE_LG2 equ 11 ; 2048 bytes/sector (El Torito requirement)\r
+SECTORSIZE equ (1 << SECTORSIZE_LG2)\r
+CR equ 13 ; Carriage Return\r
+LF equ 10 ; Line Feed\r
+retry_count equ 6 ; How patient are we with the BIOS?\r
+\r
+\r
+\r
+ absolute 5000h ; Here we keep our BSS stuff\r
+\r
+DriveNo resb 1 ; CD-ROM BIOS drive number\r
+DiskError resb 1 ; Error code for disk I/O\r
+RetryCount resb 1 ; Used for disk access retries\r
+TimeoutCount resb 1 ; Timeout counter\r
+ISOFlags resb 1 ; Flags for ISO directory search\r
+RootDir resb dir_t_size ; Root directory\r
+CurDir resb dir_t_size ; Current directory\r
+ISOFileName resb 64 ; ISO filename canonicalization buffer\r
+ISOFileNameEnd equ $\r
+\r
+\r
+ alignb open_file_t_size\r
+Files resb MAX_OPEN*open_file_t_size\r
+\r
+\r
+\r
+ section .text\r
+ org 7000h\r
+\r
+start:\r
+ cli ; Disable interrupts\r
+ xor ax, ax ; ax = segment zero\r
+ mov ss, ax ; Initialize stack segment\r
+ mov sp, start ; Set up stack\r
+ mov ds, ax ; Initialize other segment registers\r
+ mov es, ax\r
+ mov fs, ax\r
+ mov gs, ax\r
+ sti ; Enable interrupts\r
+ cld ; Increment pointers\r
+\r
+ mov cx, 2048 >> 2 ; Copy the bootsector\r
+ mov si, 0x7C00 ; from 0000:7C00\r
+ mov di, 0x7000 ; to 0000:7000\r
+ rep movsd ; copy the program\r
+ jmp 0:relocate ; jump into relocated code\r
+\r
+relocate:\r
+ ; Display the banner and copyright\r
+%ifdef DEBUG_MESSAGES\r
+ mov si, isolinux_banner ; si points to hello message\r
+ call writestr ; display the message\r
+ mov si,copyright_str\r
+ call writestr\r
+%endif\r
+\r
+\r
+ ; Make sure the keyboard buffer is empty\r
+%ifdef WAIT_FOR_KEY\r
+.kbd_buffer_test:\r
+ call pollchar\r
+ jz .kbd_buffer_empty\r
+ call getchar\r
+ jmp .kbd_buffer_test\r
+.kbd_buffer_empty:\r
+\r
+ ; Check if there is harddisk\r
+ pusha\r
+ mov ax, 0800h\r
+ mov dx, 0080h\r
+ int 13h\r
+ popa\r
+ jmp .boot_cdrom\r
+\r
+ ; Display the 'Press key' message and wait for a maximum of 5 seconds\r
+ call crlf\r
+ mov si, presskey_msg ; si points to 'Press key' message\r
+ call writestr ; display the message\r
+\r
+ mov byte [TimeoutCount], 5\r
+.next_second:\r
+ mov eax, [BIOS_timer] ; load current tick counter\r
+ add eax, 19 ; \r
+\r
+.poll_again:\r
+ call pollchar\r
+ jnz .boot_cdrom\r
+\r
+ mov ebx, [BIOS_timer]\r
+ cmp eax, ebx\r
+ jnz .poll_again\r
+\r
+ mov si, dot_msg ; print '.'\r
+ call writestr\r
+ dec byte [TimeoutCount] ; decrement timeout counter\r
+ jz .boot_harddisk\r
+ jmp .next_second\r
+\r
+.boot_harddisk:\r
+ call crlf\r
+\r
+ ; Boot first harddisk (drive 0x80)\r
+ mov ax, 0201h\r
+ mov dx, 0080h\r
+ mov cx, 0001h\r
+ mov bx, 7C00h\r
+ int 13h\r
+ jnc .go_hd\r
+ jmp kaboom\r
+.go_hd:\r
+ mov ax, cs\r
+ mov ds, ax\r
+ mov es, ax\r
+ mov fs, ax\r
+ mov gs, ax\r
+ mov dx, 0080h\r
+\r
+ jmp 0:0x7C00\r
+%endif\r
+\r
+.boot_cdrom:\r
+%ifdef WAIT_FOR_KEY\r
+ call crlf\r
+ call crlf\r
+%endif\r
+\r
+ ; Save and display the boot drive number\r
+ mov [DriveNo], dl\r
+%ifdef DEBUG_MESSAGES\r
+ mov si, startup_msg\r
+ call writemsg\r
+ mov al, dl\r
+ call writehex2\r
+ call crlf\r
+%endif\r
+\r
+ ; Now figure out what we're actually doing\r
+ ; Note: use passed-in DL value rather than 7Fh because\r
+ ; at least some BIOSes will get the wrong value otherwise\r
+ mov ax, 4B01h ; Get disk emulation status\r
+ mov dl, [DriveNo]\r
+ mov si, spec_packet\r
+ int 13h\r
+ jc near spec_query_failed ; Shouldn't happen (BIOS bug)\r
+ mov dl, [DriveNo]\r
+ cmp [sp_drive], dl ; Should contain the drive number\r
+ jne near spec_query_failed\r
+\r
+%ifdef DEBUG_MESSAGES\r
+ mov si, spec_ok_msg\r
+ call writemsg\r
+ mov al, byte [sp_drive]\r
+ call writehex2\r
+ call crlf\r
+%endif\r
+\r
+found_drive:\r
+ ; Get drive information\r
+ mov ah, 48h\r
+ mov dl, [DriveNo]\r
+ mov si, drive_params\r
+ int 13h\r
+ jnc params_ok\r
+\r
+ ; mov si, nosecsize_msg No use in reporting this\r
+ ; call writemsg\r
+\r
+params_ok:\r
+ ; Check for the sector size (should be 2048, but\r
+ ; some BIOSes apparently think we're 512-byte media)\r
+ ;\r
+ ; FIX: We need to check what the proper behaviour\r
+ ; is for getlinsec when the BIOS thinks the sector\r
+ ; size is 512!!! For that, we need such a BIOS, though...\r
+%ifdef DEBUG_MESSAGES\r
+ mov si, secsize_msg\r
+ call writemsg\r
+ mov ax, [dp_secsize]\r
+ call writehex4\r
+ call crlf\r
+%endif\r
+\r
+\r
+ ;\r
+ ; Clear Files structures\r
+ ;\r
+ mov di, Files\r
+ mov cx, (MAX_OPEN*open_file_t_size)/4\r
+ xor eax, eax\r
+ rep stosd\r
+\r
+ ;\r
+ ; Now, we need to sniff out the actual filesystem data structures.\r
+ ; mkisofs gave us a pointer to the primary volume descriptor\r
+ ; (which will be at 16 only for a single-session disk!); from the PVD\r
+ ; we should be able to find the rest of what we need to know.\r
+ ;\r
+get_fs_structures:\r
+ mov eax, 16 ; Primary Volume Descriptor (sector 16)\r
+ mov bx, trackbuf\r
+ call getonesec\r
+\r
+ mov eax, [trackbuf+156+2]\r
+ mov [RootDir+dir_lba],eax\r
+ mov [CurDir+dir_lba],eax\r
+%ifdef DEBUG_MESSAGES\r
+ mov si, rootloc_msg\r
+ call writemsg\r
+ call writehex8\r
+ call crlf\r
+%endif\r
+\r
+ mov eax,[trackbuf+156+10]\r
+ mov [RootDir+dir_len],eax\r
+ mov [CurDir+dir_len],eax\r
+%ifdef DEBUG_MESSAGES\r
+ mov si, rootlen_msg\r
+ call writemsg\r
+ call writehex8\r
+ call crlf\r
+%endif\r
+ add eax,SECTORSIZE-1\r
+ shr eax,SECTORSIZE_LG2\r
+ mov [RootDir+dir_clust],eax\r
+ mov [CurDir+dir_clust],eax\r
+%ifdef DEBUG_MESSAGES\r
+ mov si, rootsect_msg\r
+ call writemsg\r
+ call writehex8\r
+ call crlf\r
+%endif\r
+\r
+ ; Look for the "REACTOS" directory, and if found,\r
+ ; make it the current directory instead of the root\r
+ ; directory.\r
+ mov di,isolinux_dir\r
+ mov al,02h ; Search for a directory\r
+ call searchdir_iso\r
+ jnz .dir_found\r
+ mov si,no_dir_msg\r
+ call writemsg\r
+ jmp kaboom\r
+\r
+.dir_found:\r
+ mov [CurDir+dir_len],eax\r
+ mov eax,[si+file_left]\r
+ mov [CurDir+dir_clust],eax\r
+ xor eax,eax ; Free this file pointer entry\r
+ xchg eax,[si+file_sector]\r
+ mov [CurDir+dir_lba],eax\r
+\r
+\r
+ mov di, isolinux_bin ; di points to Isolinux filename\r
+ call searchdir ; look for the file\r
+ jnz .isolinux_opened ; got the file\r
+ mov si, no_isolinux_msg ; si points to error message\r
+ call writemsg ; display the message\r
+ jmp kaboom ; fail boot\r
+\r
+.isolinux_opened:\r
+ mov di, si ; save file pointer\r
+\r
+%ifdef DEBUG_MESSAGES\r
+ mov si, filelen_msg\r
+ call writemsg\r
+ call writehex8\r
+ call crlf\r
+%endif\r
+\r
+ mov ecx, eax ; calculate sector count\r
+ shr ecx, 11\r
+ test eax, 0x7FF\r
+ jz .full_sector\r
+ inc ecx\r
+.full_sector:\r
+\r
+%ifdef DEBUG_MESSAGES\r
+ mov eax, ecx\r
+ mov si, filesect_msg\r
+ call writemsg\r
+ call writehex8\r
+ call crlf\r
+%endif\r
+\r
+ mov bx, 0x8000 ; bx = load address\r
+ mov si, di ; restore file pointer\r
+ mov cx, 0xFFFF ; load the whole file\r
+ call getfssec ; get the whole file\r
+\r
+%ifdef DEBUG_MESSAGES\r
+ mov si, startldr_msg\r
+ call writemsg\r
+ call crlf\r
+%endif\r
+\r
+ mov dl, [DriveNo] ; dl = boot drive\r
+ mov dh, 0 ; dh = boot partition\r
+ jmp 0:0x8000 ; jump into OSLoader\r
+\r
+\r
+\r
+;\r
+; searchdir:\r
+;\r
+; Open a file\r
+;\r
+; On entry:\r
+; DS:DI = filename\r
+; If successful:\r
+; ZF clear\r
+; SI = file pointer\r
+; DX:AX or EAX = file length in bytes\r
+; If unsuccessful\r
+; ZF set\r
+;\r
+\r
+;\r
+; searchdir_iso is a special entry point for ISOLINUX only. In addition\r
+; to the above, searchdir_iso passes a file flag mask in AL. This is useful\r
+; for searching for directories.\r
+;\r
+alloc_failure:\r
+ xor ax,ax ; ZF <- 1\r
+ ret\r
+\r
+searchdir:\r
+ xor al,al\r
+searchdir_iso:\r
+ mov [ISOFlags],al\r
+ call allocate_file ; Temporary file structure for directory\r
+ jnz alloc_failure\r
+ push es\r
+ push ds\r
+ pop es ; ES = DS\r
+ mov si,CurDir\r
+ cmp byte [di],'\' ; If filename begins with slash\r
+ jne .not_rooted\r
+ inc di ; Skip leading slash\r
+ mov si,RootDir ; Reference root directory instead\r
+.not_rooted:\r
+ mov eax,[si+dir_clust]\r
+ mov [bx+file_left],eax\r
+ mov eax,[si+dir_lba]\r
+ mov [bx+file_sector],eax\r
+ mov edx,[si+dir_len]\r
+\r
+.look_for_slash:\r
+ mov ax,di\r
+.scan:\r
+ mov cl,[di]\r
+ inc di\r
+ and cl,cl\r
+ jz .isfile\r
+ cmp cl,'\'\r
+ jne .scan\r
+ mov [di-1],byte 0 ; Terminate at directory name\r
+ mov cl,02h ; Search for directory\r
+ xchg cl,[ISOFlags]\r
+ push di\r
+ push cx\r
+ push word .resume ; Where to "return" to\r
+ push es\r
+.isfile:\r
+ xchg ax,di\r
+\r
+.getsome:\r
+ ; Get a chunk of the directory\r
+ mov si,trackbuf\r
+ pushad\r
+ xchg bx,si\r
+ mov cx,1 ; load one sector\r
+ call getfssec\r
+ popad\r
+\r
+.compare:\r
+ movzx eax, byte [si] ; Length of directory entry\r
+ cmp al, 33\r
+ jb .next_sector\r
+ mov cl, [si+25]\r
+ xor cl, [ISOFlags]\r
+ test cl, byte 8Eh ; Unwanted file attributes!\r
+ jnz .not_file\r
+ pusha\r
+ movzx cx, byte [si+32] ; File identifier length\r
+ add si, byte 33 ; File identifier offset\r
+ call iso_compare_names\r
+ popa\r
+ je .success\r
+.not_file:\r
+ sub edx, eax ; Decrease bytes left\r
+ jbe .failure\r
+ add si, ax ; Advance pointer\r
+\r
+.check_overrun:\r
+ ; Did we finish the buffer?\r
+ cmp si, trackbuf+trackbufsize\r
+ jb .compare ; No, keep going\r
+\r
+ jmp short .getsome ; Get some more directory\r
+\r
+.next_sector:\r
+ ; Advance to the beginning of next sector\r
+ lea ax, [si+SECTORSIZE-1]\r
+ and ax, ~(SECTORSIZE-1)\r
+ sub ax, si\r
+ jmp short .not_file ; We still need to do length checks\r
+\r
+.failure:\r
+%ifdef DEBUG_MESSAGES\r
+ mov si, findfail_msg\r
+ call writemsg\r
+ call crlf\r
+%endif\r
+ xor eax, eax ; ZF = 1\r
+ mov [bx+file_sector], eax\r
+ pop es\r
+ ret\r
+\r
+.success:\r
+ mov eax, [si+2] ; Location of extent\r
+ mov [bx+file_sector], eax\r
+ mov eax, [si+10] ; Data length\r
+ push eax\r
+ add eax, SECTORSIZE-1\r
+ shr eax, SECTORSIZE_LG2\r
+ mov [bx+file_left], eax\r
+ pop eax\r
+ mov edx, eax\r
+ shr edx, 16\r
+ and bx, bx ; ZF = 0\r
+ mov si, bx\r
+ pop es\r
+ ret\r
+\r
+.resume:\r
+ ; We get here if we were only doing part of a lookup\r
+ ; This relies on the fact that .success returns bx == si\r
+ xchg edx, eax ; Directory length in edx\r
+ pop cx ; Old ISOFlags\r
+ pop di ; Next filename pointer\r
+\r
+ mov byte [di-1], '\' ; restore the backslash in the filename\r
+\r
+ mov [ISOFlags], cl ; Restore the flags\r
+ jz .failure ; Did we fail? If so fail for real!\r
+ jmp .look_for_slash ; Otherwise, next level\r
+\r
+;\r
+; allocate_file: Allocate a file structure\r
+;\r
+; If successful:\r
+; ZF set\r
+; BX = file pointer\r
+; In unsuccessful:\r
+; ZF clear\r
+;\r
+allocate_file:\r
+ push cx\r
+ mov bx, Files\r
+ mov cx, MAX_OPEN\r
+.check:\r
+ cmp dword [bx], byte 0\r
+ je .found\r
+ add bx, open_file_t_size ; ZF = 0\r
+ loop .check\r
+ ; ZF = 0 if we fell out of the loop\r
+.found:\r
+ pop cx\r
+ ret\r
+\r
+;\r
+; iso_compare_names:\r
+; Compare the names DS:SI and DS:DI and report if they are\r
+; equal from an ISO 9660 perspective. SI is the name from\r
+; the filesystem; CX indicates its length, and ';' terminates.\r
+; DI is expected to end with a null.\r
+;\r
+; Note: clobbers AX, CX, SI, DI; assumes DS == ES == base segment\r
+;\r
+iso_compare_names:\r
+ ; First, terminate and canonicalize input filename\r
+ push di\r
+ mov di, ISOFileName\r
+.canon_loop:\r
+ jcxz .canon_end\r
+ lodsb\r
+ dec cx\r
+ cmp al, ';'\r
+ je .canon_end\r
+ and al, al\r
+ je .canon_end\r
+ stosb\r
+ cmp di, ISOFileNameEnd-1 ; Guard against buffer overrun\r
+ jb .canon_loop\r
+.canon_end:\r
+ cmp di, ISOFileName\r
+ jbe .canon_done\r
+ cmp byte [di-1], '.' ; Remove terminal dots\r
+ jne .canon_done\r
+ dec di\r
+ jmp short .canon_end\r
+.canon_done:\r
+ mov [di], byte 0 ; Null-terminate string\r
+ pop di\r
+ mov si, ISOFileName\r
+.compare:\r
+ lodsb\r
+ mov ah, [di]\r
+ inc di\r
+ and ax, ax\r
+ jz .success ; End of string for both\r
+ and al, al ; Is either one end of string?\r
+ jz .failure ; If so, failure\r
+ and ah, ah\r
+ jz .failure\r
+ or ax, 2020h ; Convert to lower case\r
+ cmp al, ah\r
+ je .compare\r
+.failure:\r
+ and ax, ax ; ZF = 0 (at least one will be nonzero)\r
+.success:\r
+ ret\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+;\r
+; getfssec: Get multiple clusters from a file, given the file pointer.\r
+;\r
+; On entry:\r
+; ES:BX -> Buffer\r
+; SI -> File pointer\r
+; CX -> Cluster count; 0FFFFh = until end of file\r
+; On exit:\r
+; SI -> File pointer (or 0 on EOF)\r
+; CF = 1 -> Hit EOF\r
+;\r
+getfssec:\r
+ cmp cx, [si+file_left]\r
+ jna .ok_size\r
+ mov cx, [si+file_left]\r
+\r
+.ok_size:\r
+ mov bp, cx\r
+ push cx\r
+ push si\r
+ mov eax, [si+file_sector]\r
+ call getlinsec\r
+ xor ecx, ecx\r
+ pop si\r
+ pop cx\r
+\r
+ add [si+file_sector], ecx\r
+ sub [si+file_left], ecx\r
+ ja .not_eof ; CF = 0\r
+\r
+ xor ecx, ecx\r
+ mov [si+file_sector], ecx ; Mark as unused\r
+ xor si,si\r
+ stc\r
+\r
+.not_eof:\r
+ ret\r
+\r
+\r
+\r
+; INT 13h, AX=4B01h, DL=<passed in value> failed.\r
+; Try to scan the entire 80h-FFh from the end.\r
+spec_query_failed:\r
+ mov si,spec_err_msg\r
+ call writemsg\r
+\r
+ mov dl, 0FFh\r
+.test_loop:\r
+ pusha\r
+ mov ax, 4B01h\r
+ mov si, spec_packet\r
+ mov byte [si], 13 ; Size of buffer\r
+ int 13h\r
+ popa\r
+ jc .still_broken\r
+\r
+ mov si, maybe_msg\r
+ call writemsg\r
+ mov al, dl\r
+ call writehex2\r
+ call crlf\r
+\r
+ cmp byte [sp_drive], dl\r
+ jne .maybe_broken\r
+\r
+ ; Okay, good enough...\r
+ mov si, alright_msg\r
+ call writemsg\r
+ mov [DriveNo], dl\r
+.found_drive:\r
+ jmp found_drive\r
+\r
+ ; Award BIOS 4.51 apparently passes garbage in sp_drive,\r
+ ; but if this was the drive number originally passed in\r
+ ; DL then consider it "good enough"\r
+.maybe_broken:\r
+ cmp byte [DriveNo], dl\r
+ je .found_drive\r
+\r
+.still_broken:\r
+ dec dx\r
+ cmp dl, 80h\r
+ jnb .test_loop\r
+\r
+fatal_error:\r
+ mov si, nothing_msg\r
+ call writemsg\r
+\r
+.norge:\r
+ jmp short .norge\r
+\r
+\r
+\r
+ ; Information message (DS:SI) output\r
+ ; Prefix with "isolinux: "\r
+ ;\r
+writemsg:\r
+ push ax\r
+ push si\r
+ mov si, isolinux_str\r
+ call writestr\r
+ pop si\r
+ call writestr\r
+ pop ax\r
+ ret\r
+\r
+;\r
+; crlf: Print a newline\r
+;\r
+crlf:\r
+ mov si, crlf_msg\r
+ ; Fall through\r
+\r
+;\r
+; writestr: write a null-terminated string to the console, saving\r
+; registers on entry.\r
+;\r
+writestr:\r
+ pushfd\r
+ pushad\r
+.top:\r
+ lodsb\r
+ and al, al\r
+ jz .end\r
+ call writechr\r
+ jmp short .top\r
+.end:\r
+ popad\r
+ popfd\r
+ ret\r
+\r
+\r
+;\r
+; writehex[248]: Write a hex number in (AL, AX, EAX) to the console\r
+;\r
+writehex2:\r
+ pushfd\r
+ pushad\r
+ shl eax, 24\r
+ mov cx, 2\r
+ jmp short writehex_common\r
+writehex4:\r
+ pushfd\r
+ pushad\r
+ shl eax, 16\r
+ mov cx, 4\r
+ jmp short writehex_common\r
+writehex8:\r
+ pushfd\r
+ pushad\r
+ mov cx, 8\r
+writehex_common:\r
+.loop:\r
+ rol eax, 4\r
+ push eax\r
+ and al, 0Fh\r
+ cmp al, 10\r
+ jae .high\r
+.low:\r
+ add al, '0'\r
+ jmp short .ischar\r
+.high:\r
+ add al, 'A'-10\r
+.ischar:\r
+ call writechr\r
+ pop eax\r
+ loop .loop\r
+ popad\r
+ popfd\r
+ ret\r
+\r
+;\r
+; Write a character to the screen. There is a more "sophisticated"\r
+; version of this in the subsequent code, so we patch the pointer\r
+; when appropriate.\r
+;\r
+\r
+writechr:\r
+ pushfd\r
+ pushad\r
+ mov ah, 0Eh\r
+ xor bx, bx\r
+ int 10h\r
+ popad\r
+ popfd\r
+ ret\r
+\r
+;\r
+; Get one sector. Convenience entry point.\r
+;\r
+getonesec:\r
+ mov bp, 1\r
+ ; Fall through to getlinsec\r
+\r
+;\r
+; Get linear sectors - EBIOS LBA addressing, 2048-byte sectors.\r
+;\r
+; Note that we can't always do this as a single request, because at least\r
+; Phoenix BIOSes has a 127-sector limit. To be on the safe side, stick\r
+; to 32 sectors (64K) per request.\r
+;\r
+; Input:\r
+; EAX - Linear sector number\r
+; ES:BX - Target buffer\r
+; BP - Sector count\r
+;\r
+getlinsec:\r
+ mov si,dapa ; Load up the DAPA\r
+ mov [si+4],bx\r
+ mov bx,es\r
+ mov [si+6],bx\r
+ mov [si+8],eax\r
+.loop2:\r
+ push bp ; Sectors left\r
+ cmp bp,[MaxTransfer]\r
+ jbe .bp_ok\r
+ mov bp,[MaxTransfer]\r
+.bp_ok:\r
+ mov [si+2],bp\r
+ push si\r
+ mov dl,[DriveNo]\r
+ mov ah,42h ; Extended Read\r
+ call xint13\r
+ pop si\r
+ pop bp\r
+ movzx eax,word [si+2] ; Sectors we read\r
+ add [si+8],eax ; Advance sector pointer\r
+ sub bp,ax ; Sectors left\r
+ shl ax,SECTORSIZE_LG2-4 ; 2048-byte sectors -> segment\r
+ add [si+6],ax ; Advance buffer pointer\r
+ and bp,bp\r
+ jnz .loop2\r
+ mov eax,[si+8] ; Next sector\r
+ ret\r
+\r
+ ; INT 13h with retry\r
+xint13:\r
+ mov byte [RetryCount], retry_count\r
+.try:\r
+ pushad\r
+ int 13h\r
+ jc .error\r
+ add sp, byte 8*4 ; Clean up stack\r
+ ret\r
+.error:\r
+ mov [DiskError], ah ; Save error code\r
+ popad\r
+ dec byte [RetryCount]\r
+ jz .real_error\r
+ push ax\r
+ mov al,[RetryCount]\r
+ mov ah,[dapa+2] ; Sector transfer count\r
+ cmp al,2 ; Only 2 attempts left\r
+ ja .nodanger\r
+ mov ah,1 ; Drop transfer size to 1\r
+ jmp short .setsize\r
+.nodanger:\r
+ cmp al,retry_count-2\r
+ ja .again ; First time, just try again\r
+ shr ah,1 ; Otherwise, try to reduce\r
+ adc ah,0 ; the max transfer size, but not to 0\r
+.setsize:\r
+ mov [MaxTransfer],ah\r
+ mov [dapa+2],ah\r
+.again:\r
+ pop ax\r
+ jmp .try\r
+\r
+.real_error:\r
+ mov si, diskerr_msg\r
+ call writemsg\r
+ mov al, [DiskError]\r
+ call writehex2\r
+ mov si, ondrive_str\r
+ call writestr\r
+ mov al, dl\r
+ call writehex2\r
+ call crlf\r
+ ; Fall through to kaboom\r
+\r
+;\r
+; kaboom: write a message and bail out. Wait for a user keypress,\r
+; then do a hard reboot.\r
+;\r
+kaboom:\r
+ mov ax, cs\r
+ mov ds, ax\r
+ mov es, ax\r
+ mov fs, ax\r
+ mov gs, ax\r
+ sti\r
+ mov si, err_bootfailed\r
+ call writestr\r
+ call getchar\r
+ cli\r
+ mov word [BIOS_magic], 0 ; Cold reboot\r
+ jmp 0F000h:0FFF0h ; Reset vector address\r
+\r
+getchar:\r
+.again:\r
+ mov ah, 1 ; Poll keyboard\r
+ int 16h\r
+ jz .again\r
+.kbd:\r
+ xor ax, ax ; Get keyboard input\r
+ int 16h\r
+.func_key:\r
+ ret\r
+\r
+\r
+;\r
+; pollchar: check if we have an input character pending (ZF = 0)\r
+;\r
+pollchar:\r
+ pushad\r
+ mov ah,1 ; Poll keyboard\r
+ int 16h\r
+ popad\r
+ ret\r
+\r
+\r
+\r
+isolinux_banner db CR, LF, 'Loading IsoBoot...', CR, LF, 0\r
+copyright_str db ' Copyright (C) 1994-2002 H. Peter Anvin', CR, LF, 0\r
+presskey_msg db 'Press any key to boot from CD', 0\r
+dot_msg db '.',0\r
+\r
+%ifdef DEBUG_MESSAGES\r
+startup_msg: db 'Starting up, DL = ', 0\r
+spec_ok_msg: db 'Loaded spec packet OK, drive = ', 0\r
+secsize_msg: db 'Sector size appears to be ', 0\r
+rootloc_msg: db 'Root directory location: ', 0\r
+rootlen_msg: db 'Root directory length: ', 0\r
+rootsect_msg: db 'Root directory length(sectors): ', 0\r
+fileloc_msg: db 'SETUPLDR.SYS location: ', 0\r
+filelen_msg: db 'SETUPLDR.SYS length: ', 0\r
+filesect_msg: db 'SETUPLDR.SYS length(sectors): ', 0\r
+findfail_msg: db 'Failed to find file!', 0\r
+startldr_msg: db 'Starting SETUPLDR.SYS', 0\r
+%endif\r
+\r
+nosecsize_msg: db 'Failed to get sector size, assuming 0800', CR, LF, 0\r
+spec_err_msg: db 'Loading spec packet failed, trying to wing it...', CR, LF, 0\r
+maybe_msg: db 'Found something at drive = ', 0\r
+alright_msg: db 'Looks like it might be right, continuing...', CR, LF, 0\r
+nothing_msg: db 'Failed to locate CD-ROM device; boot failed.', CR, LF, 0\r
+isolinux_str db 'IsoBoot: ', 0\r
+crlf_msg db CR, LF, 0\r
+diskerr_msg: db 'Disk error ', 0\r
+ondrive_str: db ', drive ', 0\r
+err_bootfailed db CR, LF, 'Boot failed: press a key to retry...'\r
+isolinux_dir db '\LOADER', 0\r
+no_dir_msg db 'Could not find the LOADER directory.', CR, LF, 0\r
+isolinux_bin db 'SETUPLDR.SYS', 0\r
+no_isolinux_msg db 'Could not find SETUPLDR.SYS.', CR, LF, 0\r
+\r
+;\r
+; El Torito spec packet\r
+;\r
+ align 8, db 0\r
+spec_packet: db 13h ; Size of packet\r
+sp_media: db 0 ; Media type\r
+sp_drive: db 0 ; Drive number\r
+sp_controller: db 0 ; Controller index\r
+sp_lba: dd 0 ; LBA for emulated disk image\r
+sp_devspec: dw 0 ; IDE/SCSI information\r
+sp_buffer: dw 0 ; User-provided buffer\r
+sp_loadseg: dw 0 ; Load segment\r
+sp_sectors: dw 0 ; Sector count\r
+sp_chs: db 0,0,0 ; Simulated CHS geometry\r
+sp_dummy: db 0 ; Scratch, safe to overwrite\r
+\r
+;\r
+; EBIOS drive parameter packet\r
+;\r
+ align 8, db 0\r
+drive_params: dw 30 ; Buffer size\r
+dp_flags: dw 0 ; Information flags\r
+dp_cyl: dd 0 ; Physical cylinders\r
+dp_head: dd 0 ; Physical heads\r
+dp_sec: dd 0 ; Physical sectors/track\r
+dp_totalsec: dd 0,0 ; Total sectors\r
+dp_secsize: dw 0 ; Bytes per sector\r
+dp_dpte: dd 0 ; Device Parameter Table\r
+dp_dpi_key: dw 0 ; 0BEDDh if rest valid\r
+dp_dpi_len: db 0 ; DPI len\r
+ db 0\r
+ dw 0\r
+dp_bus: times 4 db 0 ; Host bus type\r
+dp_interface: times 8 db 0 ; Interface type\r
+db_i_path: dd 0,0 ; Interface path\r
+db_d_path: dd 0,0 ; Device path\r
+ db 0\r
+db_dpi_csum: db 0 ; Checksum for DPI info\r
+\r
+;\r
+; EBIOS disk address packet\r
+;\r
+ align 8, db 0\r
+dapa: dw 16 ; Packet size\r
+.count: dw 0 ; Block count\r
+.off: dw 0 ; Offset of buffer\r
+.seg: dw 0 ; Segment of buffer\r
+.lba: dd 0 ; LBA (LSW)\r
+ dd 0 ; LBA (MSW)\r
+\r
+ alignb 4, db 0\r
+MaxTransfer dw 2 ;32 ; Max sectors per transfer\r
+\r
+ times 2046-($-$$) db 0 ; Pad to file offset 2046\r
+ dw 0aa55h ; BootSector signature\r