Author: cfinck
Date: Tue Jan 24 22:45:37 2017
New Revision: 73594
URL:
http://svn.reactos.org/svn/reactos?rev=73594&view=rev
Log:
[BOOTSECT]
Overhaul our ISO boot sector:
- Add another entry point for hybrid booting (called by isombr) and the hybrid signature
needed for isohybrid.
- Import latest isolinux.asm "API" from
http://repo.or.cz/syslinux.git/blob/8bbb10b70905339b7ca6b58d6833b6a95ab03da…
(latest version to date) and
http://repo.or.cz/syslinux.git/blob/9141c603930ef23da1e08e487a0c26750fbb4fb…
(latest version that came with all functions in ASM).
Among other things, this brings us getlinsec_ebios (for reading setupldr.sys in
hybrid/MBR mode) and BrokenAwardHack (for working around broken Award BIOSes)
- Fix upstream getlinsec_ebios to load files >64K.
- Load the HDD boot sector directly to 0x7C00 instead of trackbuf. This way, we don't
have to load it again when the user decides to boot from HDD.
- Check for the 0xAA55 signature to decide if the HDD contains a valid MBR. This was done
differently and inconsistently for isoboot and isobtrt.
- Adapt the file and comment style to ReactOS guidelines. Add meaningful comments to our
main code. Remove stuff that was just taken from isolinux.asm, but makes no sense for our
version.
- Remove DEBUG_MESSAGES ifdef. There is no chance they can ever fit into the 2K sector
with all the added features. Debugging can still happen using Bochs or adding specific
messages.
Tested with Bochs, QEMU, VMware, VirtualBox and four real computers.
Many thanks to Hermès for all the helpful suggestions and additional investigations! :)
CORE-12648
Modified:
trunk/reactos/boot/freeldr/bootsect/isoboot.S
Modified: trunk/reactos/boot/freeldr/bootsect/isoboot.S
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/boot/freeldr/bootsect/isob…
==============================================================================
--- trunk/reactos/boot/freeldr/bootsect/isoboot.S [iso-8859-1] (original)
+++ trunk/reactos/boot/freeldr/bootsect/isoboot.S [iso-8859-1] Tue Jan 24 22:45:37 2017
@@ -1,63 +1,47 @@
/*
- * COPYRIGHT: See COPYING in the top level directory
- * PROJECT: ReactOS Bootsector for ISO file system
- * FILE: boot/freeldr/bootsect/isoboot.S
- * PURPOSE:
- * PROGRAMMERS: ?
- */
+ * PROJECT: ReactOS Boot Sector for ISO file system (based on ISOLINUX)
+ * LICENSE: GNU GPLv2 or any later version as published by the Free Software
Foundation
+ * PROGRAMMERS: H. Peter Anvin
+ * Michael K. Ter Louw
+ * Eric Kohl
+ * Timo Kreuzer <timo.kreuzer(a)reactos.org>
+ * Colin Finck <colin(a)reactos.org>
+ *
+ *****************************************************************************
+ *
+ * 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 1994-2009 H. Peter Anvin - All Rights Reserved
+ * Copyright 2009 Intel Corporation *author: 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., 53 Temple Place Ste 330,
+ * Boston MA 02111-1307, USA *either version 2 of the License, or
+ * (at your option) any later version *incorporated herein by reference.
+ *
+ *****************************************************************************/
/* INCLUDES ******************************************************************/
-
#include <asm.inc>
#include <freeldr/include/arch/pc/x86common.h>
-.code16
-
-// ****************************************************************************
-//
-// 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
-//
-// ****************************************************************************
-
-//#define DEBUG_MESSAGES /* Uncomment to get debugging messages */
#ifndef ROS_REGTEST
#define WAIT_FOR_KEY
#endif
-// ****************************************************************************
-// BEGIN THE BIOS/CODE/DATA SEGMENT
-// ****************************************************************************
-serial_base = HEX(0400) // Base addresses for 4 serial ports (4 words)
-BIOS_fbm = HEX(0413) // Free Base Memory (kilobytes) (1 word)
+
+.code16
+ASSUME CS:.text, DS:.text, ES:.text
+
+/* CONSTANTS ******************************************************************/
BIOS_timer = HEX(046C) // Timer ticks (1 word)
BIOS_magic = HEX(0472) // BIOS reset magic (1 word)
-BIOS_vidrows = HEX(0484) // Number of screen rows (1 byte)
// Memory below this point is reserved for the BIOS and the MBR
trackbuf = HEX(1000) // Track buffer goes here (8192 bytes)
@@ -65,132 +49,150 @@
// struct open_file_t
file_sector = 0 // Sector pointer (0 = structure free)
-file_left = 4 // Number of sectors left
-
-//struct dir_t
+file_bytesleft = 4 // Number of bytes left
+file_left = 8 // Number of sectors left
+// Another unused DWORD follows here in ISOLINUX
+#define open_file_t_size 16
+
+// struct dir_t
dir_lba = 0 // Directory start (LBA)
dir_len = 4 // Length in bytes
dir_clust = 8 // Length in clusters
-
#define dir_t_size 12
-#define open_file_t_size 8
MAX_OPEN_LG2 = 2 // log2(Max number of open files)
MAX_OPEN = 4
-SECTORSIZE_LG2 = 11 // 2048 bytes/sector (El Torito requirement)
-SECTORSIZE = 2048
-retry_count = 6 // How patient are we with the BIOS?
-
-/******************************************************************************/
+SECTOR_SHIFT = 11 // 2048 bytes/sector (El Torito requirement)
+SECTOR_SIZE = 2048
+retry_count = 6 // How patient are we with the BIOS?
+
+/* UNINITIALIZED VARIABLES ****************************************************/
absolute HEX(5000) // Here we keep our BSS stuff
-resb DriveNo, 1 // CD-ROM BIOS drive number (BYTE)
-resb DiskError, 1 // Error code for disk I/O (BYTE)
-resb RetryCount, 1 // Used for disk access retries (BYTE)
-resb TimeoutCount, 1 // Timeout counter (BYTE)
-resb ISOFlags, 1 // Flags for ISO directory search (BYTE)
-resb RootDir, dir_t_size // Root directory (dir_t_size BYTES)
-resb CurDir, dir_t_size // Current directory (dir_t_size BYTES)
resb ISOFileName, 64 // ISO filename canonicalization buffer
resb ISOFileNameEnd, 1
+resb CurrentDir, dir_t_size // Current directory
+resb RootDir, dir_t_size // Root directory
+resb DiskSys, 2 // Last INT 13h call
+resb GetlinsecPtr, 2 // The sector-read pointer
+resb DiskError, 1 // Error code for disk I/O
+resb DriveNumber, 1 // CD-ROM BIOS drive number
+resb ISOFlags, 1 // Flags for ISO directory search
+resb RetryCount, 1 // Used for disk access retries
//align open_file_t_size
-absolute HEX(5060)
+absolute HEX(5070)
resb Files, (MAX_OPEN * open_file_t_size)
-/******************************************************************************/
-
-
+/* ENTRY POINTS ***************************************************************/
+
+// Entry point when booted from CD (El Torito standard)
start:
- cli // Disable interrupts
- xor ax, ax // ax = segment zero
- mov ss, ax // Initialize stack segment
- mov sp, offset start // Set up stack
- mov ds, ax // Initialize other segment registers
+ mov bx, offset getlinsec_cdrom
+ // Fall through
+
+start_common:
+ // Set up our stack and a flat addressing model.
+ cli
+ xor ax, ax
+ mov ss, ax
+ mov sp, offset start
+ mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
- sti // Enable interrupts
- cld // Increment pointers
-
- mov cx, 2048 / 4 // Copy the bootsector
- mov si, HEX(7C00) // from 0000:7C00
- mov di, HEX(7000) // to 0000:7000
- rep movsd // copy the program
-
- ljmp16 0, relocate // jump into relocated code
-
-relocate:
-#ifdef DEBUG_MESSAGES
- // Display the banner and copyright
- mov si, offset isolinux_banner // si points to hello message
- call writestr // display the message
- mov si, offset copyright_str
- call writestr
-#endif
+ sti
+
+ // Our boot sector has been loaded to address 0x7C00.
+ // Relocate our 2048 bytes boot sector to the given base address (should be 0x7000).
+ cld
+ mov cx, 2048 / 4
+ mov si, HEX(7C00)
+ mov di, offset start
+ rep movsd
+
+ ljmp16 0, relocated // jump into relocated code
+
+.org 64
+hybrid_signature:
+ .long HEX(7078c0fb)
+
+// Entry point when booted through ISOMBR from a drive (isohybrid mode)
+start_hybrid:
+ mov bx, offset getlinsec_ebios
+ jmp start_common
+
+relocated:
+ // Save our passed variables (BX from the entry point, DL from the BIOS) before
anybody clobbers the registers.
+ mov word ptr ds:[GetlinsecPtr], bx
+ mov byte ptr ds:[DriveNumber], dl
// Make sure the keyboard buffer is empty
call pollchar_and_empty
- // Check for MBR on harddisk
- pusha
- mov ax, HEX(0201)
- mov dx, HEX(0080)
- mov cx, HEX(0001)
- mov bx, trackbuf
- int HEX(13)
- popa
- jc .boot_cdrom // could not read hdd
-
- push ax
-#ifdef ROS_REGTEST // this change is taken from the original isobtrt.asm
- mov ax, word ptr ds:[trackbuf+510]
-#else
- mov ax, word ptr ds:[trackbuf]
-#endif
- cmp ax, 0
- je .boot_cdrom // no boot sector found (hopefully there are no weird bootsectors
which begin with 0)
- pop ax
-
-#ifdef WAIT_FOR_KEY
- // Display the 'Press key' message and wait for a maximum of 5 seconds
- call crlf
- mov si, offset presskey_msg // si points to 'Press key' message
- call writestr // display the message
-
- mov byte ptr ds:[TimeoutCount], 5
-.next_second:
- mov eax, ds:[BIOS_timer] // load current tick counter
- add eax, 19
-
-.poll_again:
- call pollchar_and_empty
- jnz .boot_cdrom
-
- mov ebx, ds:[BIOS_timer]
- cmp eax, ebx
- jnz .poll_again
-
- mov si, offset dot_msg // print '.'
- call writestr
- dec byte ptr ds:[TimeoutCount] // decrement timeout counter
- jz .boot_harddisk
- jmp .next_second
-#endif
-
-.boot_harddisk:
- call crlf
-
- // Boot first harddisk (drive 0x80)
+ // If we're booting in hybrid mode and our boot drive is the first HDD (drive
80h),
+ // we have no other option than booting into SETUPLDR.
+ cmp word ptr ds:[GetlinsecPtr], offset getlinsec_ebios
+ jne .read_mbr
+ cmp byte ptr ds:[DriveNumber], HEX(80)
+ je .boot_setupldr
+
+.read_mbr:
+ // Read the first sector (MBR) from the first hard disk (drive 80h) to 7C00h.
+ // If we then decide to boot from HDD, we already have it at the right place.
+ // In case of an error (indicated by the Carry Flag), just boot SETUPLDR from our
ReactOS Medium.
mov ax, HEX(0201)
mov dx, HEX(0080)
mov cx, HEX(0001)
mov bx, HEX(7C00)
- int HEX(13)
- jnc .go_hd
- jmp kaboom
-.go_hd:
+ call int13
+ jc .boot_setupldr
+
+ // Verify the signature of the read MBR.
+ // If it's invalid, there is probably no OS installed and we just boot SETUPLDR
from our ReactOS Medium.
+ mov ax, word ptr ds:[HEX(7C00)+510]
+ cmp ax, HEX(AA55)
+ jne .boot_setupldr
+
+#ifdef WAIT_FOR_KEY
+ // We could either boot from the ReactOS Medium or from hard disk. Let the user
decide!
+ // Display the 'Press key' message.
+ call crlf_early
+ mov si, offset presskey_msg
+ call writestr_early
+
+ // Count down 5 seconds.
+ mov cx, 5
+
+.next_second:
+ // Count in seconds using the BIOS Timer, which runs roughly at 19 ticks per second.
+ // Load its value plus one second into EAX for comparison later.
+ mov eax, ds:[BIOS_timer]
+ add eax, 19
+
+.poll_again:
+ // Check for a keypress, boot SETUPLDR from our ReactOS Medium if a key was pressed.
+ call pollchar_and_empty
+ jnz .boot_setupldr
+
+ // Check if another second has passed (in BIOS Timer ticks).
+ mov ebx, ds:[BIOS_timer]
+ cmp eax, ebx
+ jnz .poll_again
+
+ // Another second has passed, so print the dot and decrement the second counter.
+ // If the user hasn't pressed a key after the entire 5 seconds have elapsed, just
boot from the first hard disk.
+ mov si, offset dot_msg
+ call writestr_early
+ dec cx
+ jz .boot_harddisk
+ jmp .next_second
+#endif
+
+.boot_harddisk:
+ // Restore a clean context for the hard disk MBR and boot the already loaded MBR.
+ call crlf_early
mov ax, cs
mov ds, ax
mov es, ax
@@ -200,336 +202,425 @@
ljmp16 0, HEX(7C00)
-.boot_cdrom:
+.boot_setupldr:
#ifdef WAIT_FOR_KEY
- call crlf
- call crlf
+ call crlf_early
+ call crlf_early
#endif
- // Save and display the boot drive number
- mov byte ptr ds:[DriveNo], dl
-#ifdef DEBUG_MESSAGES
- mov si, offset startup_msg
+ // The BIOS gave us a boot drive number, so in a perfect world we could just use that
one now.
+ // Unfortunately, there are many broken BIOSes around, which is why ISOLINUX verifies
it and applies some hacks if the number is wrong.
+ // Let's do exactly the same here to achieve maximum compatibility.
+
+ // Don't do this if we are running in hybrid mode.
+ cmp word ptr ds:[GetlinsecPtr], offset getlinsec_ebios
+ je found_drive
+
+ // Use the INT 13 function 4B01h (Get Disk Emulation Status) to fetch the El Torito
Spec Packet.
+ // We can use this information to verify that our passed boot drive number really
belongs to our CD.
+ mov ax, HEX(4B01)
+ mov dl, byte ptr ds:[DriveNumber]
+ mov si, offset spec_packet
+ call int13
+
+ // If this INT 13 function yields an error, we may be on a broken AWARD BIOS.
+ // Check this and patch if possible.
+ jc award_hack
+
+ // Check that our passed boot drive number and the number in the Spec Packet match.
+ // If not, try some workarounds to find our drive anyway.
+ mov dl, byte ptr ds:[DriveNumber]
+ cmp byte ptr ds:[sp_drive], dl
+ jne spec_query_failed
+
+found_drive:
+ // Clear Files structures
+ mov di, Files
+ mov cx, (MAX_OPEN*open_file_t_size)/4
+ xor eax, eax
+ rep stosd
+
+ // Read the entire 2K-sized ISO9660 Primary Volume Descriptor at sector 16 (32K).
+ // This calculation only holds for single-session ISOs, but we should never encounter
anything else.
+ mov eax, 16
+ mov bx, trackbuf
+ call getonesec
+
+ // Read the LBA address (offset 2 in the Directory Record) of the root directory
(offset 156 in the Primary Volume Descriptor).
+ mov eax, dword ptr ds:[trackbuf+156+2]
+ mov dword ptr ds:[RootDir+dir_lba], eax
+ mov dword ptr ds:[CurrentDir+dir_lba], eax
+
+ // Read the data length (offset 10 in the Directory Record) of the root directory
(offset 156 in the Primary Volume Descriptor).
+ mov eax, dword ptr ds:[trackbuf+156+10]
+ mov dword ptr ds:[RootDir+dir_len], eax
+ mov dword ptr ds:[CurrentDir+dir_len], eax
+
+ // Calculate the number of clusters and write that to our RootDir and CurrentDir
structures.
+ add eax, SECTOR_SIZE-1
+ shr eax, SECTOR_SHIFT
+ mov dword ptr ds:[RootDir+dir_clust],eax
+ mov dword ptr ds:[CurrentDir+dir_clust],eax
+
+ // Look for the "LOADER" directory (directory is indicated by AL = 2 when
using searchdir_iso).
+ mov di, offset loader_dir
+ mov al, 2
+ call searchdir_iso
+ jnz .dir_found
+
+ // No directory was found, so bail out with an error message.
+ mov si, offset no_dir_msg
+ call writemsg
+ jmp kaboom
+
+.dir_found:
+ // The directory was found, so update the information in our CurrentDir structure.
+ // Free the file pointer entry at SI in the process.
+ mov dword ptr ds:[CurrentDir+dir_len], eax
+ mov eax, dword ptr ds:[si+file_left]
+ mov dword ptr ds:[CurrentDir+dir_clust], eax
+ xor eax, eax
+ xchg eax, dword ptr ds:[si+file_sector]
+ mov dword ptr ds:[CurrentDir+dir_lba], eax
+
+ // Look for the "SETUPLDR.SYS" file.
+ mov di, offset setupldr_sys
+ call searchdir
+ jnz .setupldr_found
+
+ // The SETUPLDR file was not found, so bail out with an error message.
+ mov si, offset no_setupldr_msg
+ call writemsg
+ jmp kaboom
+
+.setupldr_found:
+ // Calculate the rounded up number of 2K sectors that need to be read.
+ mov ecx, eax
+ shr ecx, SECTOR_SHIFT
+ test eax, HEX(7FF)
+ jz .load_setupldr
+ inc ecx
+
+.load_setupldr:
+ // Load the entire SETUPLDR.SYS (parameter CX = FFFFh) to its designated base address
FREELDR_BASE.
+ // Using a high segment address with offset 0 instead of segment 0 with offset
FREELDR_BASE apparently increases compatibility with some BIOSes.
+ mov bx, FREELDR_BASE / 16
+ mov es, bx
+ xor ebx, ebx
+ mov cx, HEX(FFFF)
+ call getfssec
+
+ // Fetch our stored drive number to DL and set the boot partition to 0 in DH.
+ mov dl, byte ptr ds:[DriveNumber]
+ mov dh, 0
+
+ // Transfer execution to the bootloader.
+ ljmp16 0, FREELDR_BASE
+
+
+/* FUNCTIONS *****************************************************************/
+
+///////////////////////////////////////////////////////////////////////////////
+// Start of BrokenAwardHack --- 10-nov-2002 Knut_Petersen(a)t-online.de
+///////////////////////////////////////////////////////////////////////////////
+//
+// There is a problem with certain versions of the AWARD BIOS ...
+// the boot sector will be loaded and executed correctly, but, because the
+// int 13 vector points to the wrong code in the BIOS, every attempt to
+// load the spec packet will fail. We scan for the equivalent of
+//
+// mov ax,0201h
+// mov bx,7c00h
+// mov cx,0006h
+// mov dx,0180h
+// pushf
+// call <direct far>
+//
+// and use <direct far> as the new vector for int 13. The code above is
+// used to load the boot code into ram, and there should be no reason
+// for anybody to change it now or in the future. There are no opcodes
+// that use encodings relativ to IP, so scanning is easy. If we find the
+// code above in the BIOS code we can be pretty sure to run on a machine
+// with an broken AWARD BIOS ...
+//
+///////////////////////////////////////////////////////////////////////////////
+award_oldint13:
+ .long 0
+award_string:
+ .byte
HEX(0b8),1,2,HEX(0bb),0,HEX(7c),HEX(0b9),6,0,HEX(0ba),HEX(80),1,HEX(09c),HEX(09a)
+
+award_hack:
+ mov si, offset spec_err_msg // Moved to this place from
+ call writemsg // spec_query_failed
+
+ mov eax, dword ptr ds:[HEX(13)*4]
+ mov dword ptr ds:[award_oldint13], eax
+
+ push es
+ mov ax, HEX(F000) // ES = BIOS Seg
+ mov es, ax
+ cld
+ xor di, di // start at ES:DI = f000:0
+award_loop:
+ push di // save DI
+ mov si, offset award_string // scan for award_string
+ mov cx, 7 // length of award_string = 7dw
+ repz cmpsw // compare
+ pop di // restore DI
+ jcxz award_found // jmp if found
+ inc di // not found, inc di
+ jno award_loop
+
+award_failed:
+ pop es // No, not this way :-((
+award_fail2:
+ mov eax, dword ptr ds:[award_oldint13] // restore the original int
+ or eax, eax // 13 vector if there is one
+ jz spec_query_failed // and try other workarounds
+ mov dword ptr ds:[HEX(13)*4], eax
+ jmp spec_query_failed
+
+award_found:
+ mov eax, dword ptr es:[di+HEX(0e)] // load possible int 13 addr
+ pop es // restore ES
+
+ cmp eax, dword ptr ds:[award_oldint13] // give up if this is the
+ jz award_failed // active int 13 vector,
+ mov dword ptr ds:[HEX(13)*4], eax // otherwise change 0:13h*4
+
+ mov ax, HEX(4B01) // try to read the spec packet
+ mov dl, byte ptr ds:[DriveNumber] // now ... it should not fail
+ mov si, offset spec_packet // any longer
+ int HEX(13)
+ jc award_fail2
+
+ jmp found_drive // and leave error recovery code
+///////////////////////////////////////////////////////////////////////////////
+// End of BrokenAwardHack ---- 10-nov-2002 Knut_Petersen(a)t-online.de
+///////////////////////////////////////////////////////////////////////////////
+
+
+// INT 13h, AX=4B01h, DL=<passed in value> failed.
+// Try to scan the entire 80h-FFh from the end.
+spec_query_failed:
+ // some code moved to BrokenAwardHack
+
+ mov dl, HEX(FF)
+
+.test_loop:
+ pusha
+ mov ax, HEX(4B01)
+ mov si, offset spec_packet
+ mov byte ptr ds:[si], HEX(13) // Size of buffer
+ call int13
+ popa
+ jc .still_broken
+
+ mov si, offset maybe_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, HEX(4B01) // Get disk emulation status
- mov dl, byte ptr ds:[DriveNo]
- mov si, offset spec_packet
- int HEX(13)
- jc spec_query_failed // Shouldn't happen (BIOS bug)
- mov dl, byte ptr ds:[DriveNo]
- cmp byte ptr ds:[sp_drive], dl // Should contain the drive number
- jne spec_query_failed
-
-#ifdef DEBUG_MESSAGES
- mov si, offset spec_ok_msg
+ call crlf_early
+
+ cmp byte ptr ds:[sp_drive], dl
+ jne .maybe_broken
+
+ // Okay, good enough...
+ mov si, offset alright_msg
call writemsg
- mov al, byte ptr ds:[sp_drive]
+.found_drive0:
+ mov byte ptr ds:[DriveNumber], 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:
+ mov al, byte ptr ds:[DriveNumber]
+ cmp al, dl
+ je .found_drive
+
+ // Intel Classic R+ computer with Adaptec 1542CP BIOS 1.02
+ // passes garbage in sp_drive, and the drive number originally
+ // passed in DL does not have 80h bit set.
+ or al, HEX(80)
+ cmp al, dl
+ je .found_drive0
+
+.still_broken:
+ dec dx
+ cmp dl, HEX(80)
+ jnb .test_loop
+
+ // No spec packet anywhere. Some particularly pathetic
+ // BIOSes apparently don't even implement function
+ // 4B01h, so we can't query a spec packet no matter
+ // what. If we got a drive number in DL, then try to
+ // use it, and if it works, then well...
+ mov dl, byte ptr ds:[DriveNumber]
+ cmp dl, HEX(81) // Should be 81-FF at least
+ jb fatal_error // If not, it's hopeless
+
+ // Write a warning to indicate we're on *very* thin ice now
+ mov si, offset nospec_msg
+ call writemsg
+ mov al, dl
call writehex2
- call crlf
-#endif
-
-found_drive:
- // Get drive information
- mov ah, HEX(48)
- mov dl, byte ptr ds:[DriveNo]
- mov si, offset drive_params
- int HEX(13)
- 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, offset secsize_msg
+ call crlf_early
+ jmp .found_drive // Pray that this works...
+
+fatal_error:
+ mov si, offset nothing_msg
call writemsg
- mov ax, word ptr ds:[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, dword ptr ds:[trackbuf+156+2]
- mov dword ptr ds:[RootDir+dir_lba],eax
- mov dword ptr ds:[CurDir+dir_lba],eax
-#ifdef DEBUG_MESSAGES
- mov si, offset rootloc_msg
- call writemsg
- call writehex8
- call crlf
-#endif
-
- mov eax, dword ptr ds:[trackbuf+156+10]
- mov dword ptr ds:[RootDir+dir_len],eax
- mov dword ptr ds:[CurDir+dir_len],eax
-#ifdef DEBUG_MESSAGES
- mov si, offset rootlen_msg
- call writemsg
- call writehex8
- call crlf
-#endif
- add eax,SECTORSIZE-1
- shr eax,SECTORSIZE_LG2
- mov dword ptr ds:[RootDir+dir_clust],eax
- mov dword ptr ds:[CurDir+dir_clust],eax
-#ifdef DEBUG_MESSAGES
- mov si, offset 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, offset isolinux_dir
- mov al, 2 // Search for a directory
- call searchdir_iso
- jnz .dir_found
- mov si, offset no_dir_msg
- call writemsg
- jmp kaboom
-
-.dir_found:
- mov dword ptr ds:[CurDir+dir_len],eax
- mov eax, dword ptr ds:[si+file_left]
- mov dword ptr ds:[CurDir+dir_clust],eax
- xor eax,eax // Free this file pointer entry
- xchg eax,dword ptr ds:[si+file_sector]
- mov dword ptr ds:[CurDir+dir_lba],eax
-
-
- mov di, offset isolinux_bin // di points to Isolinux filename
- call searchdir // look for the file
- jnz .isolinux_opened // got the file
- mov si, offset 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, offset filelen_msg
- call writemsg
- call writehex8
- call crlf
-#endif
-
- mov ecx, eax // calculate sector count
- shr ecx, 11
- test eax, HEX(7FF)
- jz .full_sector
- inc ecx
-.full_sector:
-
-#ifdef DEBUG_MESSAGES
- mov eax, ecx
- mov si, offset filesect_msg
- call writemsg
- call writehex8
- call crlf
-#endif
-
-// use high segment, as some bios can fail, when offset is too big
- mov bx, FREELDR_BASE / 16 // es = load segment
- mov es, bx
- xor ebx, ebx // bx = load offset
- mov si, di // restore file pointer
- mov cx, HEX(0FFFF) // load the whole file
- call getfssec // get the whole file
-
-#ifdef DEBUG_MESSAGES
- mov si, offset startldr_msg
- call writemsg
- call crlf
-#endif
-
- mov dl, byte ptr ds:[DriveNo] // dl = boot drive
- mov dh, 0 // dh = boot partition
-
- /* Transfer execution to the bootloader */
- ljmp16 0, FREELDR_BASE
+
+.norge:
+ jmp short .norge
//
// 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
-//
-
+// Open a file
+//
+// On entry:
+// DS:DI = filename
+// If successful:
+// ZF clear
+// SI = file pointer
+// EAX = file length in bytes
+// If unsuccessful
+// ZF set
+//
+// Assumes CS == DS == ES, and trashes BX and CX.
//
// 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
+ xor ax, ax // ZF <- 1
ret
searchdir:
- xor al, al
+ xor al, al
searchdir_iso:
- mov byte ptr ds:[ISOFlags],al
- call allocate_file // Temporary file structure for directory
+ mov byte ptr ds:[ISOFlags], al
+ call allocate_file // Temporary file structure for
directory
jnz alloc_failure
- push es
- push ds
- pop es // ES = DS
- mov si, offset CurDir
- cmp byte ptr ds:[di], 92 //'\' // If filename begins with slash
- jne .not_rooted
- inc di // Skip leading slash
- mov si, offset RootDir // Reference root directory instead
+ push es
+ push ds
+ pop es // ES = DS
+ mov si, offset CurrentDir
+ cmp byte ptr ds:[di], '/' // If filename begins with slash
+ jne .not_rooted
+ inc di // Skip leading slash
+ mov si, offset RootDir // Reference root directory instead
.not_rooted:
mov eax, dword ptr ds:[si+dir_clust]
- mov dword ptr ds:[bx+file_left],eax
- mov eax,dword ptr ds:[si+dir_lba]
- mov dword ptr ds:[bx+file_sector],eax
- mov edx,dword ptr ds:[si+dir_len]
+ mov dword ptr ds:[bx+file_left], eax
+ shl eax, SECTOR_SHIFT
+ mov dword ptr ds:[bx+file_bytesleft], eax
+ mov eax, dword ptr ds:[si+dir_lba]
+ mov dword ptr ds:[bx+file_sector], eax
+ mov edx, dword ptr ds:[si+dir_len]
.look_for_slash:
- mov ax,di
+ mov ax, di
.scan:
mov cl, byte ptr ds:[di]
- inc di
- and cl,cl
- jz .isfile
- cmp cl, 92 // '\'
- jne .scan
- mov byte ptr ds:[di-1], 0 // Terminate at directory name
- mov cl,2 // Search for directory
- xchg cl, byte ptr ds:[ISOFlags]
- push di
- push cx
- push offset .resume // Where to "return" to
- push es
+ inc di
+ and cl, cl
+ jz .isfile
+ cmp cl, '/'
+ jne .scan
+ mov byte ptr ds:[di-1], 0 // Terminate at directory name
+ mov cl, 2 // Search for directory
+ xchg cl, byte ptr ds:[ISOFlags]
+
+ push di // Save these...
+ push cx
+
+ // Create recursion stack frame...
+ push offset .resume // Where to "return" to
+ push es
.isfile:
- xchg ax,di
+ xchg ax, di
.getsome:
// Get a chunk of the directory
- mov si,trackbuf
+ // This relies on the fact that ISOLINUX doesn't change SI
+ mov si, trackbuf
pushad
- xchg bx,si
- mov cx,1 // load one sector
+ xchg bx, si
+ mov cx, word ptr ds:[BufSafe]
call getfssec
popad
.compare:
- movzx eax, byte ptr ds:[si] // Length of directory entry
+ movzx eax, byte ptr ds:[si] // Length of directory entry
cmp al, 33
- jb .next_sector
+ jb .next_sector
mov cl, byte ptr ds:[si+25]
- xor cl, byte ptr ds:[ISOFlags]
- test cl, HEX(8E) // Unwanted file attributes!
+ xor cl, byte ptr ds:[ISOFlags]
+ test cl, HEX(8E) // Unwanted file attributes!
jnz .not_file
pusha
- movzx cx, byte ptr ds:[si+32] // File identifier length
- add si, 33 // File identifier offset
+ movzx cx, byte ptr ds:[si+32] // File identifier length
+ add si, 33 // File identifier offset
call iso_compare_names
popa
- je .success
+ je .success
.not_file:
- sub edx, eax // Decrease bytes left
- jbe .failure
- add si, ax // Advance pointer
+ 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 .getsome // Get some more directory
+ 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, not (SECTORSIZE-1)
- sub ax, si
- jmp .not_file // We still need to do length checks
+ lea ax, [si+SECTOR_SIZE-1]
+ and ax, not (SECTOR_SIZE-1)
+ sub ax, si
+ jmp short .not_file // We still need to do length checks
.failure:
-#ifdef DEBUG_MESSAGES
- mov si, offset findfail_msg
- call writemsg
- call crlf
-#endif
- xor eax, eax // ZF = 1
+ xor eax, eax // ZF = 1
mov dword ptr ds:[bx+file_sector], eax
- pop es
+ pop es
ret
.success:
- mov eax, dword ptr ds:[si+2] // Location of extent
+ mov eax, dword ptr ds:[si+2] // Location of extent
mov dword ptr ds:[bx+file_sector], eax
- mov eax, dword ptr ds:[si+10] // Data length
- push eax
- add eax, SECTORSIZE-1
- shr eax, SECTORSIZE_LG2
+ mov eax, dword ptr ds:[si+10] // Data length
+ mov dword ptr ds:[bx+file_bytesleft], eax
+ push eax
+ add eax, SECTOR_SIZE-1
+ shr eax, SECTOR_SHIFT
mov dword ptr ds:[bx+file_left], eax
- pop eax
- mov edx, eax
- shr edx, 16
- and bx, bx // ZF = 0
+ pop eax
+ jz .failure // Empty file?
+ // ZF = 0
mov si, bx
- pop es
+ 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
-
- // restore the backslash in the filename
- mov byte ptr ds:[di-1], 92 // '\'
-
- mov byte ptr ds:[ISOFlags], cl // Restore the flags
- jz .failure // Did we fail? If so fail for real!
- jmp .look_for_slash // Otherwise, next level
+ xchg edx, eax // Directory length in edx
+ pop cx // Old ISOFlags
+ pop di // Next filename pointer
+ mov byte ptr ds:[di-1], '/' // Restore slash
+ mov byte ptr ds:[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
@@ -546,12 +637,12 @@
mov cx, MAX_OPEN
.check:
cmp dword ptr ds:[bx], 0
- je .found
- add bx, open_file_t_size // ZF = 0
- loop .check
+ je .found
+ add bx, open_file_t_size // ZF = 0
+ loop .check
// ZF = 0 if we fell out of the loop
.found:
- pop cx
+ pop cx
ret
//
@@ -565,236 +656,170 @@
//
iso_compare_names:
// First, terminate and canonicalize input filename
- push di
+ push di
mov di, offset ISOFileName
.canon_loop:
- jcxz .canon_end
+ jcxz .canon_end
lodsb
- dec cx
+ dec cx
cmp al, ';'
- je .canon_end
- and al, al
- je .canon_end
+ je .canon_end
+ and al, al
+ je .canon_end
stosb
- cmp di, offset ISOFileNameEnd-1 // Guard against buffer overrun
- jb .canon_loop
+ cmp di, offset ISOFileNameEnd-1 // Guard against buffer overrun
+ jb .canon_loop
.canon_end:
cmp di, ISOFileName
- jbe .canon_done
- cmp byte ptr ds:[di-1], '.' // Remove terminal dots
- jne .canon_done
- dec di
- jmp short .canon_end
+ jbe .canon_done
+ cmp byte ptr ds:[di-1], '.' // Remove terminal dots
+ jne .canon_done
+ dec di
+ jmp short .canon_end
.canon_done:
- mov byte ptr ds:[di], 0 // Null-terminate string
- pop di
+ mov byte ptr ds:[di], 0 // Null-terminate string
+ pop di
mov si, ISOFileName
.compare2:
lodsb
mov ah, byte ptr ds:[di]
- inc di
- and ax, ax
- jz .success2 // End of string for both
- and al, al // Is either one end of string?
- jz .failure2 // If so, failure
- and ah, ah
- jz .failure2
- or ax, HEX(2020) // Convert to lower case
+ inc di
+ and ax, ax
+ jz .success2 // End of string for both
+ and al, al // Is either one end of string?
+ jz .failure2 // If so, failure
+ and ah, ah
+ jz .failure2
+ or ax, HEX(2020) // Convert to lower case
cmp al, ah
- je .compare2
+ je .compare2
.failure2:
- and ax, ax // ZF = 0 (at least one will be nonzero)
+ and ax, ax // ZF = 0 (at least one will be nonzero)
.success2:
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
+// ES:BX -> Buffer
+// SI -> File pointer
+// CX -> Cluster count
// On exit:
-// SI -> File pointer (or 0 on EOF)
-// CF = 1 -> Hit EOF
+// SI -> File pointer (or 0 on EOF)
+// CF = 1 -> Hit EOF
+// ECX -> Bytes actually read
//
getfssec:
- cmp cx, word ptr ds:[si+file_left]
- jna .ok_size
- mov cx, word ptr ds:[si+file_left]
-
+ push ds
+ push cs
+ pop ds // DS <- CS
+
+ movzx ecx, cx
+ cmp ecx, dword ptr ds:[si+file_left]
+ jna .ok_size
+ mov ecx, dword ptr ds:[si+file_left]
.ok_size:
+ pushad
+ mov eax, dword ptr ds:[si+file_sector]
mov bp, cx
- push cx
- push si
- mov eax, dword ptr ds:[si+file_sector]
call getlinsec
- xor ecx, ecx
- pop si
- pop cx
-
- add dword ptr ds:[si+file_sector], ecx
- sub dword ptr ds:[si+file_left], ecx
- ja .not_eof // CF = 0
-
- xor ecx, ecx
- mov dword ptr ds:[si+file_sector], ecx // Mark as unused
- xor si,si
+ popad
+
+ // ECX[31:16] == 0 here...
+ add dword ptr ds:[si+file_sector], ecx
+ sub dword ptr ds:[si+file_left], ecx
+ shl ecx, SECTOR_SHIFT // Convert to bytes
+ cmp ecx, dword ptr ds:[si+file_bytesleft]
+ jb .not_all
+ mov ecx, dword ptr ds:[si+file_bytesleft]
+.not_all:
+ sub dword ptr ds:[si+file_bytesleft], ecx
+ jnz .ret // CF = 0 in this case...
+ push eax
+ xor eax, eax
+ mov dword ptr ds:[si+file_sector], eax // Unused
+ mov si, ax
+ pop eax
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, offset spec_err_msg
- call writemsg
-
- mov dl, HEX(0FF)
-.test_loop:
- pusha
- mov ax, HEX(4B01)
- mov si, offset spec_packet
- mov byte ptr ds:[si], 13 // Size of buffer
- int HEX(13)
- popa
- jc .still_broken
-
- mov si, offset maybe_msg
- call writemsg
- mov al, dl
- call writehex2
- call crlf
-
- cmp byte ptr ds:[sp_drive], dl
- jne .maybe_broken
-
- // Okay, good enough...
- mov si, offset alright_msg
- call writemsg
- mov byte ptr ds:[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 ptr ds:[DriveNo], dl
- je .found_drive
-
-.still_broken:
- dec dx
- cmp dl, HEX(80)
- jnb .test_loop
-
-fatal_error:
- mov si, offset nothing_msg
- call writemsg
-
-.norge:
- jmp .norge
-
-
-
+.ret:
+ pop ds
+ ret
+
+//
// Information message (DS:SI) output
-// Prefix with "isolinux: "
+// Prefix with "ISOBOOT: "
+//
writemsg:
- push ax
- push si
- mov si, offset isolinux_str
- call writestr
- pop si
- call writestr
- pop ax
- ret
-
-//
-// crlf: Print a newline
-crlf:
- mov si, offset crlf_msg
- // Fall through
-
-//
-// writestr: write a null-terminated string to the console, saving
-// registers on entry.
-//
-writestr:
+ push ax
+ push si
+ mov si, offset isoboot_str
+ call writestr_early
+ pop si
+ call writestr_early
+ pop ax
+ ret
+
+writestr_early:
pushfd
pushad
-writestr_top:
+.top:
lodsb
- and al, al
- jz writestr_end
+ and al, al
+ jz .end_writestr
call writechr
- jmp short writestr_top
-writestr_end:
+ jmp short .top
+.end_writestr:
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, HEX(0F)
- cmp al, 10
- jae .high
-.low:
- add al, '0'
- jmp short .ischar
-.high:
- add al, 'A'-10
-.ischar:
+crlf_early:
+ push ax
+ mov al, 13
call writechr
- pop eax
- loop .loop
- popad
- popfd
- ret
-
-//
-// writechr: 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.
+ mov al, 10
+ call writechr
+ pop ax
+ ret
+
+//
+// writechr: Write a character to the screen.
+//
writechr:
pushfd
pushad
mov ah, HEX(0E)
- xor bx, bx
+ xor bx, bx
int HEX(10)
popad
popfd
ret
//
+// int13: save all the segment registers and call INT 13h.
+// Some CD-ROM BIOSes have been found to corrupt segment registers
+// and/or disable interrupts.
+//
+int13:
+ pushf
+ push bp
+ push ds
+ push es
+ push fs
+ push gs
+ int HEX(13)
+ mov bp, sp
+ setc byte ptr ds:[bp+10] // Propagate CF to the caller
+ pop gs
+ pop fs
+ pop es
+ pop ds
+ pop bp
+ popf
+ ret
+
+//
// Get one sector. Convenience entry point.
//
getonesec:
@@ -804,48 +829,113 @@
//
// 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:
- push es // save es, we reset it later to 0
-
- mov si, offset dapa // Load up the DAPA
+ jmp word ptr cs:[GetlinsecPtr]
+
+//
+// getlinsec_ebios:
+//
+// getlinsec implementation for floppy/HDD EBIOS (EDD)
+//
+getlinsec_ebios:
+ xor edx, edx
+ shld edx, eax, 2
+ shl eax, 2 // Convert to HDD sectors
+ shl bp, 2
+
+.loop_ebios:
+ push bp // Sectors left
+.retry2:
+ call maxtrans // Enforce maximum transfer size
+ movzx edi, bp // Sectors we are about to read
+ mov cx, retry_count
+.retry:
+ // Form DAPA on stack
+ push edx
+ push eax
+ push es
+ push bx
+ push di
+ push 16
+ mov si, sp
+ pushad
+ mov dl, byte ptr ds:[DriveNumber]
+ push ds
+ push ss
+ pop ds // DS <- SS
+ mov ah, HEX(42) // Extended Read
+ call int13
+ pop ds
+ popad
+ lea sp, [si+16] // Remove DAPA
+ jc .error_ebios
+ pop bp
+ add eax, edi // Advance sector pointer
+ adc edx, 0
+ sub bp, di // Sectors left
+ shl di, 9 // 512-byte sectors
+ add bx, di // Advance buffer pointer
+ jnc .no_overflow // Check if we have read more than 64K
and need to adjust ES
+ mov di, es
+ add di, HEX(1000) // Adjust segment by 64K (1000h * 16 =
10000h = 64K + 1)
+ mov es, di
+.no_overflow:
+ and bp, bp
+ jnz .loop_ebios
+
+ ret
+
+.error_ebios:
+ pushad // Try resetting the device
+ xor ax, ax
+ mov dl, byte ptr ds:[DriveNumber]
+ call int13
+ popad
+ loop .retry // CX-- and jump if not zero
+
+ // Total failure.
+ jmp kaboom
+
+//
+// Truncate BP to MaxTransfer
+//
+maxtrans:
+ cmp bp, word ptr ds:[MaxTransfer]
+ jna .ok
+ mov bp, word ptr ds:[MaxTransfer]
+.ok:
+ ret
+
+//
+// This is the variant we use for real CD-ROMs:
+// LBA, 2K sectors, some special error handling.
+//
+getlinsec_cdrom:
+ mov si, offset dapa // Load up the DAPA
mov word ptr ds:[si+4], bx
- mov bx, es
- mov word ptr ds:[si+6], bx
- xor bx, bx // reset es to 0, some bioses (KVM) require that
- mov es, bx
+ mov word ptr ds:[si+6], es
mov dword ptr ds:[si+8], eax
-.loop2:
- push bp // Sectors left
- cmp bp, word ptr ds:[MaxTransfer]
+.loop_cdrom:
+ push bp // Sectors left
+ cmp bp, word ptr ds:[MaxTransferCD]
jbe .bp_ok
- mov bp, word ptr ds:[MaxTransfer]
+ mov bp, word ptr ds:[MaxTransferCD]
.bp_ok:
mov word ptr ds:[si+2], bp
push si
- mov dl, byte ptr ds:[DriveNo]
- mov ah, HEX(42) // Extended Read
+ mov dl, byte ptr ds:[DriveNumber]
+ mov ah, HEX(42) // Extended Read
call xint13
pop si
pop bp
- movzx eax,word ptr ds:[si+2] // Sectors we read
- add dword ptr ds:[si+8], eax // Advance sector pointer
- sub bp, ax // Sectors left
- shl ax, SECTORSIZE_LG2-4 // 2048-byte sectors -> segment
- add word ptr ds:[si+6], ax // Advance buffer pointer
+ movzx eax, word ptr ds:[si+2] // Sectors we read
+ add dword ptr ds:[si+8], eax // Advance sector pointer
+ sub bp, ax // Sectors left
+ shl ax, SECTOR_SHIFT-4 // 2048-byte sectors -> segment
+ add word ptr ds:[si+6], ax // Advance buffer pointer
and bp, bp
- jnz .loop2
- mov eax, dword ptr ds:[si+8] // Next sector
-
- pop es
+ jnz .loop_cdrom
+ mov eax, dword ptr ds:[si+8] // Next sector
ret
// INT 13h with retry
@@ -853,30 +943,31 @@
mov byte ptr ds:[RetryCount], retry_count
.try:
pushad
- int HEX(13)
- jc .error
- add sp, 8*4 // Clean up stack
- ret
-.error:
- mov byte ptr ds:[DiskError], ah // Save error code
+ call int13
+ jc .error_cdrom
+ add sp, 8*4 // Clean up stack
+ ret
+.error_cdrom:
+ mov byte ptr ds:[DiskError], ah // Save error code
popad
+ mov word ptr ds:[DiskSys], ax // Save system call number
dec byte ptr ds:[RetryCount]
jz .real_error
push ax
mov al, byte ptr ds:[RetryCount]
- mov ah, byte ptr ds:[dapa+2] // Sector transfer count
- cmp al,2 // Only 2 attempts left
+ mov ah, byte ptr ds:[dapa+2] // Sector transfer count
+ cmp al, 2 // Only 2 attempts left
ja .nodanger
- mov ah,1 // Drop transfer size to 1
+ 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
+ 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 byte ptr ds:[MaxTransfer],ah
- mov byte ptr ds:[dapa+2],ah
+ mov byte ptr ds:[MaxTransferCD], ah
+ mov byte ptr ds:[dapa+2], ah
.again:
pop ax
jmp .try
@@ -886,11 +977,15 @@
call writemsg
mov al, byte ptr ds:[DiskError]
call writehex2
+ mov si, offset oncall_str
+ call writestr_early
+ mov ax, word ptr ds:[DiskSys]
+ call writehex4
mov si, offset ondrive_str
- call writestr
+ call writestr_early
mov al, dl
call writehex2
- call crlf
+ call crlf_early
// Fall through to kaboom
//
@@ -898,187 +993,174 @@
// then do a hard reboot.
//
kaboom:
+ // Restore a clean context.
mov ax, cs
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
sti
+
+ // Display the failure message.
mov si, offset err_bootfailed
- call writestr
- xor ax, ax // Wait for keypress
+ call writestr_early
+
+ // Wait for a keypress.
+ xor ax, ax
int HEX(16)
+
+ // Disable interrupts and reset the system through a magic BIOS call.
cli
- mov word ptr ds:[BIOS_magic], 0 // Cold reboot
- ljmp16 HEX(0F000), HEX(0FFF0) // Reset vector address
-
-
-//
-// pollchar_and_empty: check if we have an input character pending (ZF = 0) and empty the
input buffer afterwards
+ mov word ptr ds:[BIOS_magic], 0
+ ljmp16 HEX(0F000), HEX(0FFF0)
+
+//
+// writehex[248]: Write a hex number in (AL, AX, EAX) to the console
+//
+writehex2:
+ pushfd
+ pushad
+ rol eax, 24
+ mov cx,2
+ jmp short writehex_common
+writehex4:
+ pushfd
+ pushad
+ rol eax, 16
+ mov cx, 4
+ jmp short writehex_common
+writehex8:
+ pushfd
+ pushad
+ mov cx, 8
+writehex_common:
+.loop_writehex:
+ rol eax, 4
+ push eax
+ and al, HEX(0F)
+ cmp al, 10
+ jae .high
+.low:
+ add al, '0'
+ jmp short .ischar
+.high:
+ add al, 'A'-10
+.ischar:
+ call writechr
+ pop eax
+ loop .loop_writehex
+ popad
+ popfd
+ ret
+
+//
+// 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?
+ mov ah, 1 // Did the user press a key?
int HEX(16)
- jz .end // No, then we're done
- mov ah, 0 // Otherwise empty the buffer by reading it
+ jz .end_pollchar // No, then we're done
+ mov ah, 0 // Otherwise empty the buffer by reading
it
int HEX(16)
-.end:
+.end_pollchar:
popad
ret
-isolinux_banner:
- .ascii CR, LF, "Loading IsoBoot...", CR, LF, NUL
-copyright_str:
- .ascii " (C) 1994-2002 H. Peter Anvin", CR, LF, NUL
+/* INITIALIZED VARIABLES *****************************************************/
presskey_msg:
- .ascii "Press any key to boot from CD", NUL
+ .ascii "Press any key to boot from the ReactOS Medium", NUL
dot_msg:
.ascii ".", NUL
-
-#ifdef DEBUG_MESSAGES
-startup_msg:
- .ascii "Startup, DL = '", NUL
-spec_ok_msg:
- .ascii "packet OK, drive = ", NUL
-secsize_msg:
- .ascii "size appears to be ", NUL
-rootloc_msg:
- .ascii "Root dir loc: ", NUL
-rootlen_msg:
- .ascii "Root dir len: ", NUL
-rootsect_msg:
- .ascii "Root dir len(sect): ", NUL
-fileloc_msg:
- .ascii "SETUPLDR loc: ", NUL
-filelen_msg:
- .ascii "SETUPLDR len: ", NUL
-filesect_msg:
- .ascii "SETUPLDR len(sect): ", NUL
-findfail_msg:
- .ascii "Failed to find file!", NUL
-startldr_msg:
- .ascii "Starting SETUPLDR.SYS", NUL
-#endif
-
+isoboot_str:
+ .ascii "ISOBOOT: ", NUL
spec_err_msg:
- .ascii "Load spec failed, trying wing ...", CR, LF, NUL
+ .ascii "Loading spec packet failed, trying to wing it...", CR, LF, NUL
maybe_msg:
- .ascii "Found smth at drive = ", NUL
+ .ascii "Found something at drive = ", NUL
alright_msg:
- .ascii "might be ok, continuing...", CR, LF, NUL
+ .ascii "Looks reasonable, continuing...", CR, LF, NUL
+nospec_msg:
+ .ascii "Extremely broken BIOS detected, last attempt with drive = ", NUL
nothing_msg:
- .ascii "Failed locate CD-ROM; boot failed.", CR, LF, NUL
-
-isolinux_str:
- .ascii "IsoBoot: ", NUL
-crlf_msg:
- .ascii CR, LF, NUL
+ .ascii "Failed to locate CD-ROM device; boot failed.", CR, LF, NUL
diskerr_msg:
.ascii "Disk error ", NUL
+oncall_str:
+ .ascii ", AX = ", NUL
ondrive_str:
.ascii ", drive ", NUL
-
err_bootfailed:
- .ascii CR, LF, "failed..", NUL
-isolinux_dir:
- .ascii "\\LOADER", NUL
+ .ascii CR, LF, "Boot failed: press a key to retry...", NUL
+loader_dir:
+ .ascii "/LOADER", NUL
no_dir_msg:
.ascii "LOADER dir not found.", CR, LF, NUL
-isolinux_bin:
+setupldr_sys:
.ascii "SETUPLDR.SYS", NUL
-no_isolinux_msg:
- .ascii "SETUPLDR not found.", CR, LF, NUL
-
+no_setupldr_msg:
+ .ascii "SETUPLDR.SYS not found.", CR, LF, NUL
+
+.align 4
+BufSafe:
+ .word trackbufsize/SECTOR_SIZE // Clusters we can load into trackbuf
+
+// Maximum transfer size
+.align 4
+MaxTransfer:
+ .word 127 // Hard disk modes
+MaxTransferCD:
+ .word 32 // CD mode
//
// El Torito spec packet
//
.align 8
spec_packet:
- .byte HEX(13) // Size of packet
+ .byte HEX(13) // Size of packet
sp_media:
- .byte 0 // Media type
+ .byte 0 // Media type
sp_drive:
- .byte 0 // Drive number
+ .byte 0 // Drive number
sp_controller:
- .byte 0 // Controller index
+ .byte 0 // Controller index
sp_lba:
- .long 0 // LBA for emulated disk image
+ .long 0 // LBA for emulated disk image
sp_devspec:
- .word 0 // IDE/SCSI information
+ .word 0 // IDE/SCSI information
sp_buffer:
- .word 0 // User-provided buffer
+ .word 0 // User-provided buffer
sp_loadseg:
- .word 0 // Load segment
+ .word 0 // Load segment
sp_sectors:
- .word 0 // Sector count
+ .word 0 // Sector count
sp_chs:
- .byte 0,0,0 // Simulated CHS geometry
+ .byte 0,0,0 // Simulated CHS geometry
sp_dummy:
- .byte 0 // Scratch, safe to overwrite
-
-//
-// EBIOS drive parameter packet
-//
-.align 8
-drive_params:
- .word 30 // Buffer size
-dp_flags:
- .word 0 // Information flags
-dp_cyl:
- .long 0 // Physical cylinders
-dp_head:
- .long 0 // Physical heads
-dp_sec:
- .long 0 // Physical sectors/track
-dp_totalsec:
- .long 0,0 // Total sectors
-dp_secsize:
- .word 0 // Bytes per sector
-dp_dpte:
- .long 0 // Device Parameter Table
-dp_dpi_key:
- .word 0 // 0BEDDh if rest valid
-dp_dpi_len:
- .byte 0 // DPI len
- .byte 0
- .word 0
-dp_bus:
- .byte 0,0,0,0 // Host bus type
-dp_interface:
- .byte 0,0,0,0,0,0,0,0 // Interface type
-db_i_path:
- .long 0,0 // Interface path
-db_d_path:
- .long 0,0 // Device path
- .byte 0
-db_dpi_csum:
- .byte 0 // Checksum for DPI info
+ .byte 0 // Scratch, safe to overwrite
//
// EBIOS disk address packet
//
.align 8
dapa:
- .word 16 // Packet size
+ .word 16 // Packet size
.count:
- .word 0 // Block count
+ .word 0 // Block count
.off:
- .word 0 // Offset of buffer
+ .word 0 // Offset of buffer
.seg:
- .word 0 // Segment of buffer
+ .word 0 // Segment of buffer
.lba:
- .long 0 // LBA (LSW)
- .long 0 // LBA (MSW)
-
-.align 4
-MaxTransfer:
- .word 2 //32 // Max sectors per transfer
-
-.org 2046 // Pad to file offset 2046
-.word HEX(0aa55) // BootSector signature
+ .long 0 // LBA (LSW)
+ .long 0 // LBA (MSW)
+
+
+// Extend the size to cover one 2K-sized sector
+.org 2047
+ .byte 0
.endcode16