/* * BootDuet - Replacement boot program for DUET. * Copyright 2011 Miguel Lopes Santos Ramos . * * 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, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * See: * - README for a description of this project * - INSTALL for installation instructions */ /* * The Master Boot Record (MBR) will have loaded this program into physical * address 0x7c00 and jumped into 0000:7c00 just as the BIOS would. * The environment that EFILDR expects us to have prepared is as follows: * * 0x015000 - 0x019000 EFIVAR.BIN loaded here, if the file exists * 0x019000 - 0x019004 The serial number of the FAT boot volume * 0x019004 - 0x019005 One byte indicating the following conditions: * - 0 - EFIVAR.BIN was loaded * - 1 - EFIVAR.BIN does not exist * - 2 - EFIVAR.BIN exists but is not exactly 16k * 0x020000 - 0x0a0000 EFILDR loaded here * * Given those constraints, we define our memory map as follows. Note that we * work mostly in the lower 64k of physical memory with segment registers set * to zero. * * 0x006000 - 0x007000 Room for several FAT sectors (4k) (FAT12) * 0x007000 - 0x007c00 We have 3k here for stack and local variables * 0x007c00 - 0x007e00 Where BootDuet is loaded (512b) * 0x007e00 - 0x008000 Room for one FAT sector (FAT32 and FAT16) * 0x008000 - 0x010000 Room for root directory entries (32k at most) * 0x010000 - 0x015000 Unused space (20k) * 0x015000 - 0x019000 Room for EFIVAR.BIN (16k at most) * 0x019000 - 0x019005 Parameters for EFILDR (5 bytes) * 0x019005 - 0x020000 Unused space (almost 4k) * 0x020000 - 0x0a0000 Room for EFILDR (512k at most) */ .equ BaseAddress, 0x7c00 # Offset address for our own code and data #if FAT == 32 || FAT == 16 .equ FatOffset, 0x7e00 # Offset address for the FAT buffer #else .equ FatOffset, 0x6000 # Offset address for the FAT buffer #endif .equ RootOffset, 0x8000 # Offset address for the root dir buffer /* * Constants everyone knows about. */ .equ DirEntrySize, 32 # Size of directory entry for all types of FAT .equ DirEntryShift, 5 # Shift factor for directory entry #if defined(WITH_LBA_64BIT) .equ SizeOfLBA, 8 # Bytes in a 64-bit LBA variable #else .equ SizeOfLBA, 4 # Bytes in a 32-bit LBA variable #endif #if FAT == 32 .equ SizeOfCluster, 4 # Bytes in a cluster pointer variable #elif FAT == 16 || FAT == 12 .equ SizeOfCluster, 2 # Bytes in a cluster pointer variable #endif /* * This is a 16-bit code segment and we're in real mode. */ .code16 /* * This jump is canonical, don't change the target. */ .global _start _start: jmp main nop /* * BIOS Parameter Block (BPB) * * The BPB is the same for all types of FAT filesystems. * The following labels are placeholders that make writing the code that * accesses this data easier. * The real data is what is filled in by the format program. * The intention is that you only overwrite the part of your volume boot * sector that contains the code and leave this part unchanged. */ .space 8, 0x20 # OEM ID waste (OS or format program) .word 512 # Bytes per sector (will anything other than 512 work?) .byte 0 # Sectors per cluster .word 0 # Reserved sectors before first FAT including boot .byte 0 # Number of FATs (usually 1 or 2) .word 0 # Root directory entries (only FAT12 or FAT16) .word 0 # Number of sectors or 0 (not used) .byte 0 # Media descriptor (irrelevant) .word 0 # Sectors per FAT (for FAT12 or FAT16) .word 0 # Sectors per track (irrelevant for LBA) .word 0 # Number of heads (irrelevant for LBA) .long 0 # Hidden sectors before partition .long 0 # Number of sectors (if wSectors = 0) /* * The next symbols allow us to reference exactly that same data in the BPB, * but relatively to our main stack frame. * Addressing relative to the frame pointer saves us a byte on each memory * reference, however, GNU as makes it hard for us to do it. */ .equ main_wBps, 0x0b .equ main_bSpc, 0x0d .equ main_wReserved, 0x0e .equ main_bFats, 0x10 .equ main_wRootEntries, 0x11 .equ main_wSectsPerFat, 0x16 .equ main_lHidden, 0x1c #if FAT == 32 /* * Extended BIOS Parameter Block (EBPB) for FAT32. */ .long 0 # Sectors per FAT (for FAT32) .word 0 # FAT flags (irrelevant) .word 0 # FAT32 version (only known is 0) .long 0 # First cluster of the root directory .word 0 # Sector number of FSINFO (irrelevant) .word 0 # Backup boot sector number or 0 for no backup .space 12, 0 # another 12 bytes gone to waste bDrive: .byte 0 # BIOS drive number (we use what comes in DL) .byte 0 # another byte gone to waste .byte 0 # EBPB signature (should be 0x29) .long 0 # Volume ID (serial number) .space 11, 0x20# Volume label (8.3) (irrelevant) .space 8, 0x20 # another 8 bytes gone to waste ("FAT32 ") /* * As before, symbols for memory references relative to the main stack frame. */ .equ main_lSectsPerFat, 0x24 .equ main_lRootCluster, 0x2c .equ main_bDrive, 0x40 .equ main_bSignature, 0x42 .equ main_lVolId, 0x43 .equ main_FsType, 0x52 #elif FAT == 16 || FAT == 12 /* * Extended BIOS Parameter Block (EBPB) for recent versions of FAT12 and FAT16. */ bDrive: .byte 0 # BIOS drive number (we use what comes in DL) .byte 0 # another byte gone to waste .byte 0 # EBPB signature (should be 0x29) .long 0 # Volume ID (serial number) .space 11, 0x20# Volume label (8.3) (irrelevant) .space 8, 0x20 # File system type ("FAT12 " or "FAT16 ") /* * As before, symbols for memory references relative to the main stack frame. */ .equ main_bDrive, 0x24 .equ main_bSignature, 0x26 .equ main_lVolId, 0x27 .equ main_FsType, 0x36 #endif /* * And we finally start our main function. * We have 420 bytes left for the boot code, those wasted bytes would have * come in handy. * We'll probably have DL set with the BIOS boot disk number. If this is an MBR * disk, we may even have SI pointing to the right partition entry, if it is GPT * maybe a boot loader faked a partition entry. Anyway, we don't trust that. */ main: /* * Initialize our memory model with all segment registers at 0000. */ cli # no stack, no interrupts pushw %cs popw %ss # SS = CS = 0000 movw $BaseAddress,%sp # stack goes down from 7c00 sti # got stack, got interrupts cld # we work upward pushw %cs popw %ds # DS = CS = 0000 movw %sp,%bp # yes, we use a frame pointer #if !defined(WITH_HARDCODED_DRIVE) movb %dl,main_bDrive(%bp) # store drive number, which the # MBR should have passed us on # DL, to the EBPB. #endif #if defined(WITH_VALIDATION) && !defined(DEBUG) /* * fsck - boot sector validation. This validation is only to help troubleshoot. * On tighter versions, such as FAT12 with LBA 64 bit, we skip this, there's no * space. */ fsck: /* * - check that file system signature is 0x29 * - check that hidden sectors isn't zero */ cmpb $0x29,main_bSignature(%bp) jne fsck.1 cmpl $0,main_lHidden(%bp) jne fsck.2 /* * Something went wrong with the installation, tell the user and halt. */ fsck.1: movw $Invalid,%si # SI = error message movb $InvalidLen,%cl # CL = length call print fsck.h: jmp fsck.h # Hot halt fsck.2: /* * Fall through to fsinit. */ #endif /* * init - initializes variables on the main stack frame. * * returns: * sFat, sRoot, wRootSects and sData variables are set, * wRootEnd, bEfiLdr, bEfiVar and cFatCache are set to harmless defaults. * * registers trashed: EAX, EBX, ECX, EDX */ init: /* * The following assembler symbol is a neat trick that helps us not * getting lost when computing frame offsets of local variables. */ main_frame = 0 /* * Compute the LBA of the first sector of the first FAT. */ main_frame = main_frame - SizeOfLBA main_sFat = main_frame # LBA at which FAT starts #if !defined(WITH_LBA_64BIT) movzwl main_wReserved(%bp),%eax addl main_lHidden(%bp),%eax # EAX = hidden + reserved pushl %eax # store to sFat #else movzwl main_wReserved(%bp),%eax xorl %edx,%edx addl main_lHidden(%bp),%eax adcl lHiddenHigh,%edx # EDX:EAX = hidden + reserved pushl %edx # store to sFat pushl %eax #endif /* * Compute the LBA of the first sector after all copies of FAT. This * will be, on FAT12 and FAT16, the first sector of the root directory * and on FAT32 the first sector of the first cluster (the data region). */ #if FAT == 32 main_frame = main_frame - SizeOfLBA main_sData = main_frame # LBA at which data starts movl main_lSectsPerFat(%bp),%ecx #elif FAT == 16 || FAT == 12 main_frame = main_frame - SizeOfLBA main_sRoot = main_frame # LBA at which root starts movzwl main_wSectsPerFat(%bp),%ecx #endif movzbl main_bFats(%bp),%eax # EAX = number of FATs mull %ecx # EDX:EAX = total FAT sectors #if !defined(WITH_LBA_64BIT) addl main_sFat(%bp),%eax # EAX = sFat + total FAT pushl %eax # store to sData/sRoot #else addl main_sFat(%bp),%eax adcl main_sFat+4(%bp),%edx # EDX:EAX = sFat + total FAT pushl %edx # store to sData/sRoot pushl %eax #endif #if FAT == 12 || FAT == 16 /* * Compute the LBA of the first sector of the root directory, which * comes immediately after all copies of the FAT. */ main_frame = main_frame - 2 main_wRootSects = main_frame # number of sectors in root main_frame = main_frame - SizeOfLBA main_sData = main_frame # LBA at which data starts movzwl main_wRootEntries(%bp),%eax bsrw main_wBps(%bp),%cx subw $DirEntryShift,%cx shrw %cl,%ax pushw %ax # store to wRootSects #if !defined(WITH_LBA_64BIT) addl main_sRoot(%bp),%eax # EAX = sRoot + wRootSects pushl %eax # store to sData #else xorl %edx,%edx addl main_sRoot(%bp),%eax adcl main_sRoot+4(%bp),%edx # EDX:EAX = sRoot + wRootSects pushl %edx # store to sData pushl %eax #endif #endif /* * Other variables that must be initialized. * cEfiVar must come lower in memory than cEfiLdr. Together, they form * a sorted array of two elements. */ main_frame = main_frame - 2 main_wRootEnd = main_frame # ptr to end off root buffer main_frame = main_frame - 1 main_bEfiLdr = main_frame # EFILDR present? main_frame = main_frame - 1 main_bEfiVar = main_frame # EFIVAR.BIN present? main_frame = main_frame - SizeOfCluster main_cFatCache = main_frame # loaded/cached FAT sector pushw %cs # zero wRootEnd pushw $1 # bEfiLdr = 0, bEfiVar = 1 #if FAT == 32 pushw %cs # set cFatCache to funny value pushw $0xffff #elif FAT == 16 || FAT == 12 pushw $0xffff # set cFatCache to funny value #endif /* * Fall through to readroot. */ /* * readroot - reads the root directory into the predetermined buffer. * * returns: * wRootEnd variable is set * * registers trashed: EAX, EBX, ECX, EDX, SI */ readroot: /* * We read the root directory to a predifined buffer and hope that it * won't cross the boundary of the first 64k. */ pushw %cs popw %es # ES = CS = 0000 movw $RootOffset,%di # ES:DI = root buffer #if FAT == 32 /* * On FAT32, root is a normal file with the start cluster registered on * the EBPB. */ movl main_lRootCluster(%bp),%eax call fread # read the root directory movw %di,main_wRootEnd(%bp) # store DI to wRootEnd #elif FAT == 16 || FAT == 12 /* * On FAT16 and FAT12, we must compute the number of sectors taken by * the root directory and read them from the disk. */ movw main_wRootSects(%bp),%cx movl main_sRoot(%bp),%eax # EDX:EAX = start LBA of root #if !defined(WITH_LBA_64BIT) xorl %edx,%edx #else movl main_sRoot+4(%bp),%edx # EDX:EAX = start LBA of root #endif /* * Read all sectors on the root directory. */ call read /* * After reading, advance DI by the number of bytes read and return. * We don't advance ES. Even if we did, the next routine would have * a problem if the root directory was superimposed by the files * that it reads. */ movw main_wBps(%bp),%ax mulw %cx # DX:AX = bytes read addw %ax,%di # advance DI by AX bytes movw %di,main_wRootEnd(%bp) # store DI to wRootEnd #endif /* * Fall through to scanroot. */ /* * scanroot - scans the root directory for EFILDR and EFIVAR.BIN, if any of * these files is found, it is read and bEfiLdr or bEfiVar variables are * set appropriately * * returns: * bEfiLdr and bEfiVar variables are set * * registers trashed: EAX, EBX, ECX, EDX, SI, DI, ES */ scanroot: movw $RootOffset,%si # DS:SI = root buffer scanroot.1: /* * Check if this directory entry is EFILDR */ pushw %cs popw %es # ES = CS movw $EfiLdr,%di # ES:DI = &EfiLdr call fncmp jne scanroot.2 # jump if this isn't EFILDR movb $1,main_bEfiLdr(%bp) # bEfiLdr = 1, we have it pushw $0x2000 # read EFILDR to 2000:0000 jmp scanroot.r scanroot.2: /* * Check if this directory entry is EFIVAR.BIN and, if so, check its * size to see if it is 16k and then set the bHaveVar variable * accordingly. * If the size is right, then proceed to reading it. */ movw $EfiVar,%di # ES:DI = &EfiVar (assume ES=CS) call fncmp jne scanroot.n # jump if this isn't EFIVAR.BIN movb $2,main_bEfiVar(%bp) # bEfiVar = 2, maybe size is bad #if FAT == 12 cmpl $0,0x1c(%si) # is zero size? je scanroot.n # it is, skip it #else cmpl $0x4000,0x1c(%si) # compare size to 16k jne scanroot.n # size is not exactly 16k... #endif movb $0,main_bEfiVar(%bp) # bEfiVar = 0, we have it pushw $0x1500 # read EFIVAR.BIN to 1500:0000 scanroot.r: /* * Found interesting file, print its name, so the user knows something * if we halt for some reason, and read it to ES:0000, where ES is the * word on top of the stack. */ movb $FilenameLen,%cl # CL = number of chars call print # print the file name popw %es # restore ES from the stack xorw %di,%di # ES:DI = xxxx:0000 #if FAT == 32 pushw 0x14(%si) # push high 16 bits of cluster pushw 0x1a(%si) # push low 16 bits of cluster popl %eax # EAX = 32-bit cluster number #elif FAT == 16 || FAT == 12 movw 0x1a(%si),%ax # AX = 16-bit cluster number #endif call fread # read file EAX into ES:DI scanroot.n: /* * Proceed to the next directory entry. */ addw $DirEntrySize,%si # advance SI cmpw main_wRootEnd(%bp),%si # have we reached the end? jb scanroot.1 # if not, loop /* * Fall through to setup. */ /* * setup - sets up environment to what EFILDR expects to find */ setup: /* * Check that EFILDR was found and that we have something to jump into. */ movw main_bEfiVar(%bp),%ax # AL = bEfiVar, AH = bEfiLdr or %ah,%ah # is bEfiLdr set? jnz setup.1 /* * Print error message and halt. */ movw $Missing,%si # SI = Missing movb $MissingLen,%cl # CL = length call print setup.h: jmp setup.h # Hot halt setup.1: #if !defined(DEBUG) /* * Copy the volume id (serial number) of the FAT file system to the * physical address 19000 and the value of bEfiVar to 19004. */ pushw $0x1900 popw %es # ES = 1900 movb %al,%es:(4) # store AL to 1900:0004 movl main_lVolId(%bp),%eax # EAX = volume serial number movl %eax,%es:(0) # store EAX to 1900:0000 /* * Jump into EFILDR at 2000:0200, the second sector of start.com. */ ljmp $0x2000,$0x0200 #endif #if defined(DEBUG) /* * printn - print a 32-bit number on the screen in decimal and halt * * parameters: * EAX number to print */ printn: leaw main_FsType(%bp),%si # Overwrite volume label and id xorl %ebx,%ebx movb $10,%bl # EBX = decimal base xorw %cx,%cx # CX will count digits printn.1: xorl %edx,%edx # satisfy the DIV instruction divl %ebx # EAX = EAX / 10, EDX = EAX % 10 decw %si # --SI incw %cx # ++CX addb $'0',%dl # DL = decimal digit to print movb %dl,(%si) # *SI == DL testl %eax,%eax # did we reach zero? jnz printn.1 call print printn.h: jmp printn.h # halt #endif /* * print - print a message on the screen * * parameters: * DS:SI pointer to the message being written * CL number of characters to write * * registers trashed: AL, CX, DI, ES */ print: pushw %si pushw $0xb800 popw %es xorb %ch,%ch # high 16 bits of counter = 0 xorw %di,%di # ES:DI = b800:0000 movb $0x07,%al # AL = 0x07 (white, non-blink) print.1: movsb # move one byte of text stosb # store one byte of attributes loop print.1 popw %si ret /* * fncmp - compares two 8.3 style filenames * * parameters: * DS:SI pointer to one filename * ES:DI pointer the other filename * * returns: * zero flag set if filenames are equal * * registers trashed: CX, DI */ fncmp: pushw %si movw $FilenameLen,%cx # compare all 11 characters repe cmpsb popw %si # pop won't affect flags ret /* * fread - reads a file given its first cluster * * parameters: * EAX first cluster to read (AX on FAT12/FAT16) * ES:DI destination buffer * * returns: * ES:DI pointer past the used portion of the destination buffer * * registers trashed: EAX, EBX, ECX, EDX */ fread: /* * First we establish a stack frame here. We will assume, for * size optimization, that the stack frame above is the main stack * frame. That means this function won't work if it's not called in that * context. * The margin between frames contains IP and BP only (4 bytes). */ pushw %bp movw %sp,%bp fread_frame = 0 fread_wBps = main_wBps - main_frame + 4 fread_bSpc = main_bSpc - main_frame + 4 fread_sFat = main_sFat - main_frame + 4 fread_sData = main_sData - main_frame + 4 fread_cFatCache = main_cFatCache - main_frame + 4 fread.1: /* * Check if the cluster is something crazy, such as the last cluster in * file or a bad sector or anything strange. */ #if FAT == 32 cmpl $2,%eax jb fread.2 cmpl $0x0ffffff0,%eax jb fread.3 #elif FAT == 16 cmpw $2,%ax jb fread.2 cmpw $0xfff0,%ax jb fread.3 #elif FAT == 12 cmpw $2,%ax jb fread.2 cmpw $0x0ff0,%ax jb fread.3 #endif fread.2: /* * If the cluster number is crazy, then we return and that's it. */ leave ret fread.3: /* * Clean the cluster number, on FAT12 and FAT16, we may have trash * on the upper 16 bits of EAX. * Then save the cluster number on a local variable. */ fread_frame = fread_frame - 4 # 4 bytes even for FAT12/16 fread_cluster = fread_frame # new local var cluster #if FAT == 16 || FAT == 12 movzwl %ax,%eax # zero extend AX #endif pushl %eax # store to var cluster /* * Compute the start LBA for this cluster, first the offset from the * data region, then the LBA. * ECX is kept with the number of sectors per cluster. */ #if FAT == 32 subl $2,%eax #elif FAT == 16 || FAT == 12 decw %ax decw %ax #endif movzbl fread_bSpc(%bp),%ecx # ECX = sectors per cluster mull %ecx # EDX:EAX = (cluster - 2) * ECX addl fread_sData(%bp),%eax # EDX:EAX = start LBA #if defined(WITH_LBA_64BIT) adcl fread_sData+4(%bp),%edx #endif /* * Read the cluster, the number of sectors to read is bSpc (in CX). */ call read /* * After reading, advance DI by the number of bytes read and on overflow * advance ES too. */ movw fread_wBps(%bp),%ax mulw %cx # AX = bytes per cluster (bSpc * wBps) addw %ax,%di # advance DI by AX bytes jnc fread.4 # check for carry pushw %es # advance ES by 64k addw $0x1000,fread_frame-2(%bp) popw %es fread.4: /* * Now we must locate the next cluster in the file, and for that, first * locate the FAT sector that we must read by obtaining the quotient and * remainder of the division of the cluster number by the number of * cluster pointers per FAT sector. */ popl %eax # restore from fread_cluster fread_frame = fread_frame + 4 # fread_cluster goes away fread_frame = fread_frame - 2 fread_index = fread_frame # new local var index #if FAT == 32 movzwl fread_wBps(%bp),%ebx # EBX = bytes per sector shrw $2,%bx # EBX = ptrs per sector xorl %edx,%edx divl %ebx # EAX = FAT sector, EDX = ptr pushw %dx # save cluster pointer index #elif FAT == 16 movw fread_wBps(%bp),%bx # BX = bytes per sector shrw $1,%bx # BX = ptrs per sector xorw %dx,%dx divw %bx # AX = FAT sector, DX = ptr pushw %dx # save cluster pointer index #elif FAT == 12 movw fread_wBps(%bp),%bx # BX = bytes per sector shlw $1,%bx # BX = ptrs per trio xorw %dx,%dx divw %bx # AX = FAT trio, DX = ptr pushw %dx # save cluster pointer index movw $3,%bx mulw %bx # AX = first sector of trio #endif /* * Check if this FAT sector was already loaded and, if so, skip to the * next section. */ #if FAT == 32 cmpl fread_cFatCache(%bp),%eax #elif FAT == 16 || FAT == 12 cmpw fread_cFatCache(%bp),%ax #endif je fread.5 /* * We have to load the relevant sector of FAT. We keep the sector that * we will load in cFatCache (if the read fails we will abort anyway). */ #if FAT == 32 movl %eax,fread_cFatCache(%bp) #elif FAT == 16 || FAT == 12 movw %ax,fread_cFatCache(%bp) #endif xorl %edx,%edx #if !defined(WITH_LBA_64BIT) addl fread_sFat(%bp),%eax # EDX:EAX = FAT LBA #else addl fread_sFat(%bp),%eax adcl fread_sFat+4(%bp),%edx # EDX:EAX = FAT LBA #endif /* * Now read that sector into the buffer for FAT sectors (0000:7e00). */ pushw %es pushw %di pushw %cs popw %es movw $FatOffset,%di # ES:DI = 0000:xxxx #if FAT == 12 movw $3,%cx # on FAT12, read 3 sectors #else movw $1,%cx #endif call read # read the FAT sector popw %di popw %es fread.5: /* * Finally we read the cluster pointer in this FAT sector and repeat the * whole thing. */ popw %bx # restore fread_index to BX fread_frame = fread_frame + 2 # fread_index goes away #if FAT == 32 shlw $2,%bx # BX = index * 4 movl FatOffset(%bx),%eax # EAX = next cluster in file jmp fread.1 #elif FAT == 16 shlw $1,%bx # BX = index * 2 movw FatOffset(%bx),%ax # AX = next cluster in file jmp fread.1 #elif FAT == 12 xorw %cx,%cx # CX = default shift factor 0 movw %bx,%ax # AX = index too testw $1,%ax # is it even or odd? jz fread.6 # if even, CL (shift factor) = 0 movb $4,%cl # if odd, CL (shift factor) = 4 fread.6: shrw $1,%ax addw %ax,%bx # BX = 3 * (index / 2) + odd? movw FatOffset(%bx),%ax # low or high 12 of AX is ptr shrw %cl,%ax # shift right by CL andw $0x0fff,%ax # trim high bits jmp fread.1 #endif /* * read - reads sectors by 64-bit Logical Block Address (LBA) * * parameters: * EDX:EAX LBA of first sector to read * CX number of sectors to read * ES:DI destination buffer * * registers trashed: AX, DL */ read: pushw %si /* * Fill in Disk Address Packet (DAP) structure. This is filled on the * stack from top to bottom. */ pushl %edx pushl %eax pushw %es pushw %di pushw %cx pushw $16 /* * Call BIOS int 13h AH=42h: Extended Read Sectors From Drive. */ movb $0x42,%ah movb bDrive,%dl movw %sp,%si # SI = SP (base of DAP) int $0x13 /* * Return on success or halt on error (an indicative message would have * already been written on the screen). */ read.h: jc read.h # Halt if carry addw $16,%sp popw %si ret /* * String constants for the whole program and their length. */ #if defined(WITH_VALIDATION) && !defined(DEBUG) .equ InvalidLen, 3 Invalid: .ascii "Bad" #endif .equ MissingLen, 19 # "Missing " + 8.3 filename Missing: .ascii "Missing " .equ FilenameLen, 11 # 8.3 filename (11) #if FAT == 32 EfiLdr: .ascii "EFILDR20 " #elif FAT == 16 EfiLdr: .ascii "EFILDR16 " #elif FAT == 12 EfiLdr: .ascii "EFILDR " #endif EfiVar: .ascii "EFIVAR BIN" /* * Since the BPB only has room for a 32-bit number of hidden sectors, if we need * 64-bit LBA, we need room for storing the high-order 32 bits of hidden * sectors. */ #if defined(WITH_LBA_64BIT) .org 0x01fa lHiddenHigh: .long 0 #endif /* * The boot sector signature at the end of the sector. */ .org 0x01fe wSignature: .word 0xaa55