#- # Copyright (c) 2007 Yahoo!, Inc. # All rights reserved. # Written by: John Baldwin # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # 3. Neither the name of the author nor the names of any co-contributors # may be used to endorse or promote products derived from this software # without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # # $FreeBSD$ # # Partly from: src/sys/boot/i386/mbr/mbr.s 1.7 # A 512 byte PMBR boot manager to read a boot program and run it. # The embedded MBR is set up for PMBR and default bootblock sector # is hardcoded to 256 and size 1. The actual values are supposed to be # updated by installboot. .set LOAD,0x7c00 # Load address .set EXEC,0x600 # Execution address .set MAGIC,0xaa55 # Magic: bootable .set SECSIZE,0x200 # Size of a single disk sector .set DISKSIG,440 # Disk signature offset .set STACK,EXEC+SECSIZE*4 # Stack address .set DPBUF,STACK .set NHRDRV,0x475 # Number of hard drives .globl start # Entry point .code16 .text start: jmp real_code .fill 0x3c,0x1,0x90 # fill with nop to ease disasm # # BIOS Parameter Block. Reserved space from 0xb to 0x3e, the FAT32 BPB # is 60 (3Ch) bytes. # . = start + 0x3e # # Setup the segment registers for flat addressing and setup the stack. # real_code: cld # String ops inc xorw %ax,%ax # Zero movw %ax,%es # Address movw %ax,%ds # data movw %ax,%ss # Set up movw $STACK,%sp # stack # # Relocate ourself to a lower address so that we have more room to load # other sectors. # movw $main-EXEC+LOAD,%si # Source movw $main,%di # Destination movw $SECSIZE-(main-start),%cx # Byte count rep # Relocate movsb # code # # Jump to the relocated code. # jmp main-LOAD+EXEC # To relocated code # # Validate drive number in %dl. # main: cmpb $0x80,%dl # Drive valid? jb main.1 # No movb NHRDRV,%dh # Calculate the highest addb $0x80,%dh # drive number available cmpb %dh,%dl # Within range? jb main.2 # Yes main.1: movb $0x80,%dl # Assume drive 0x80 # # Load stage2 and start it. location and size is written by installboot # and if size is 0, we can not do anything... # main.2: movw stage2_size, %ax cmpw $0, %ax je err_noboot # the stage2 size is not set pushw %dx # save drive movb $0x41, %ah # check extensions movw $0x55aa, %bx int $0x13 popw %dx # restore drive jc err_rd # need lba mode for now cmpw $0xaa55, %bx # chs support is not jne err_rd # implemented. movw $stage2_sector, %si # pointer to lba movw $LOAD/16,%bx # set buffer segment movw %bx,%es xorw %bx,%bx # and offset load_boot: push %si # Save %si call read pop %si # Restore decw stage2_size # stage2_size-- jnz next_boot boot: mov %bx,%es # Reset %es to zero jmp LOAD # Jump to boot code next_boot: incl (%si) # Next LBA adcl $0,4(%si) mov %es,%ax # Adjust segment for next addw $SECSIZE/16,%ax # sector mov %ax,%es # jmp load_boot # # Load a sector (64-bit LBA at %si) from disk %dl into %es:%bx by creating # a EDD packet on the stack and passing it to the BIOS. Trashes %ax and %si. # read: pushl 0x4(%si) # Set the LBA pushl 0x0(%si) # address pushw %es # Set the address of pushw %bx # the transfer buffer pushw $0x1 # Read 1 sector pushw $0x10 # Packet length movw %sp,%si # Packer pointer movw $0x4200,%ax # BIOS: LBA Read from disk int $0x13 # Call the BIOS add $0x10,%sp # Restore stack jc err_rd # If error ret # # Various error message entry points. # err_rd: movw $msg_rd,%si # "I/O error loading jmp putstr # boot loader" err_noboot: movw $msg_noboot,%si # "Missing boot jmp putstr # loader" # # Output an ASCIZ string to the console via the BIOS. # putstr.0: movw $0x7,%bx # Page:attribute movb $0xe,%ah # BIOS: Display int $0x10 # character putstr: lodsb # Get character testb %al,%al # End of string? jnz putstr.0 # No putstr.1: jmp putstr.1 # Await reset msg_rd: .asciz "I/O error" msg_noboot: .asciz "No boot loader" nop mbr_version: .byte 1, 1 # 1.1 .align 4 stage2_size: .word 1 # bootblock size in sectors stage2_sector: .quad 256 # lba of bootblock disk_uuid: .quad 0 # uuid .quad 0 # this is the end of the code block we can use, next is space for # signature, partition table 4 entries and signature. .org DISKSIG,0x1b8 # sig: .long 0 # OS Disk Signature .word 0 # "Unknown" in PMBR partbl: .byte 0x00 # non-bootable .byte 0x00 # head 0 .byte 0x02 # sector .byte 0x00 # cylinder .byte 0xEE # ID .byte 0xFF # ending head .byte 0xFF # ending sector .byte 0xFF # ending cylinder .long 0x00000001 # starting LBA .long 0xFFFFFFFF # size .fill 0x10,0x3,0x0 # other 3 entries .word MAGIC # Magic number