1#- 2# Copyright (c) 2007 Yahoo!, Inc. 3# All rights reserved. 4# Written by: John Baldwin <jhb@FreeBSD.org> 5# 6# Redistribution and use in source and binary forms, with or without 7# modification, are permitted provided that the following conditions 8# are met: 9# 1. Redistributions of source code must retain the above copyright 10# notice, this list of conditions and the following disclaimer. 11# 2. Redistributions in binary form must reproduce the above copyright 12# notice, this list of conditions and the following disclaimer in the 13# documentation and/or other materials provided with the distribution. 14# 3. Neither the name of the author nor the names of any co-contributors 15# may be used to endorse or promote products derived from this software 16# without specific prior written permission. 17# 18# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28# SUCH DAMAGE. 29# 30# 31# Partly from: src/sys/boot/i386/mbr/mbr.s 1.7 32 33# A 512 byte PMBR boot manager that looks for a FreeBSD boot GPT partition 34# and boots it. 35 36 .set LOAD,0x7c00 # Load address 37 .set EXEC,0x600 # Execution address 38 .set MAGIC,0xaa55 # Magic: bootable 39 .set SECSIZE,0x200 # Size of a single disk sector 40 .set DISKSIG,440 # Disk signature offset 41 .set STACK,EXEC+SECSIZE*4 # Stack address 42 .set GPT_ADDR,STACK # GPT header address 43 .set GPT_SIG,0 44 .set GPT_SIG_0,0x20494645 # "EFI " 45 .set GPT_SIG_1,0x54524150 # "PART" 46 .set GPT_MYLBA,24 47 .set GPT_PART_LBA,72 48 .set GPT_NPART,80 49 .set GPT_PART_SIZE,84 50 .set PART_ADDR,GPT_ADDR+SECSIZE # GPT partition array address 51 .set PART_TYPE,0 52 .set PART_START_LBA,32 53 .set PART_END_LBA,40 54 .set DPBUF,PART_ADDR+SECSIZE 55 .set DPBUF_SEC,0x10 # Number of sectors 56 57 .set NHRDRV,0x475 # Number of hard drives 58 59 .globl start # Entry point 60 .code16 61 62# 63# Setup the segment registers for flat addressing and setup the stack. 64# 65start: cld # String ops inc 66 xorw %ax,%ax # Zero 67 movw %ax,%es # Address 68 movw %ax,%ds # data 69 movw %ax,%ss # Set up 70 movw $STACK,%sp # stack 71# 72# Relocate ourself to a lower address so that we have more room to load 73# other sectors. 74# 75 movw $main-EXEC+LOAD,%si # Source 76 movw $main,%di # Destination 77 movw $SECSIZE-(main-start),%cx # Byte count 78 rep # Relocate 79 movsb # code 80# 81# Jump to the relocated code. 82# 83 jmp main-LOAD+EXEC # To relocated code 84# 85# Validate drive number in %dl. 86# 87main: cmpb $0x80,%dl # Drive valid? 88 jb main.1 # No 89 movb NHRDRV,%dh # Calculate the highest 90 addb $0x80,%dh # drive number available 91 cmpb %dh,%dl # Within range? 92 jb main.2 # Yes 93main.1: movb $0x80,%dl # Assume drive 0x80 94# 95# Load the GPT header and verify signature. Try LBA 1 for the primary one and 96# the last LBA for the backup if it is broken. 97# 98main.2: call getdrvparams # Read drive parameters 99 movb $1,%dh # %dh := 1 (reading primary) 100main.2a: movw $GPT_ADDR,%bx 101 movw $lba,%si 102 call read # Read header and check GPT sig 103 cmpl $GPT_SIG_0,GPT_ADDR+GPT_SIG 104 jnz main.2b 105 cmpl $GPT_SIG_1,GPT_ADDR+GPT_SIG+4 106 jnz main.2b 107 jmp load_part 108main.2b: cmpb $1,%dh # Reading primary? 109 jne err_pt # If no - invalid table found 110# 111# Try alternative LBAs from the last sector for the GPT header. 112# 113main.3: movb $0,%dh # %dh := 0 (reading backup) 114 movw $DPBUF+DPBUF_SEC,%si # %si = last sector + 1 115 movw $lba,%di # %di = $lba 116main.3a: subl $1, (%si) # 0x0(%si) = last sec (0-31) 117 sbbl $0, 4(%si) 118 movw $4,%cx 119 rep 120 movsw # $lastsec--, copy it to $lba 121 jmp main.2a # Read the next sector 122# 123# Load a partition table sector from disk and look for a FreeBSD boot 124# partition. 125# 126load_part: movw $GPT_ADDR+GPT_PART_LBA,%si 127 movw $PART_ADDR,%bx 128 call read 129scan: movw %bx,%si # Compare partition UUID 130 movw $boot_uuid,%di # with FreeBSD boot UUID 131 movw $0x10,%cx 132 repe cmpsb 133 jnz next_part # Didn't match, next partition 134# 135# We found a boot partition. Load it into RAM starting at 0x7c00. 136# 137 movw %bx,%di # Save partition pointer in %di 138 leaw PART_START_LBA(%di),%si 139 movw $LOAD/16,%bx 140 movw %bx,%es 141 xorw %bx,%bx 142load_boot: push %si # Save %si 143 call read 144 pop %si # Restore 145 movl PART_END_LBA(%di),%eax # See if this was the last LBA 146 cmpl (%si),%eax 147 jnz next_boot 148 movl PART_END_LBA+4(%di),%eax 149 cmpl 4(%si),%eax 150 jnz next_boot 151 mov %bx,%es # Reset %es to zero 152 jmp LOAD # Jump to boot code 153next_boot: addl $1,(%si) # Next LBA 154 adcl $0,4(%si) 155 mov %es,%ax # Adjust segment for next 156 addw $SECSIZE/16,%ax # sector 157 cmp $0x9000,%ax # Don't load past 0x90000, 158 jb sz_ok # 545k should be enough for 159 call err_big # any boot code, but warn 160 mov $0x9000-SECSIZE/16,%ax # and truncate 161sz_ok: mov %ax,%es 162 jmp load_boot 163# 164# Move to the next partition. If we walk off the end of the sector, load 165# the next sector. We assume that partition entries are smaller than 64k 166# and that they won't span a sector boundary. 167# 168# XXX: Should we int 0x18 instead of err_noboot if we hit the end of the table? 169# 170next_part: decl GPT_ADDR+GPT_NPART # Was this the last partition? 171 jz err_noboot 172 movw GPT_ADDR+GPT_PART_SIZE,%ax 173 addw %ax,%bx # Next partition 174 cmpw $PART_ADDR+0x200,%bx # Still in sector? 175 jb scan 176 addl $1, GPT_ADDR+GPT_PART_LBA # Next sector 177 adcl $0,GPT_ADDR+GPT_PART_LBA+4 178 jmp load_part 179# 180# Load a sector (64-bit LBA at %si) from disk %dl into %es:%bx by creating 181# a EDD packet on the stack and passing it to the BIOS. Trashes %ax and %si. 182# 183read: pushl 0x4(%si) # Set the LBA 184 pushl 0x0(%si) # address 185 pushw %es # Set the address of 186 pushw %bx # the transfer buffer 187 pushw $0x1 # Read 1 sector 188 pushw $0x10 # Packet length 189 movw %sp,%si # Packer pointer 190 movw $0x4200,%ax # BIOS: LBA Read from disk 191 int $0x13 # Call the BIOS 192 add $0x10,%sp # Restore stack 193 jc err_rd # If error 194 ret 195# 196# Check the number of LBAs on the drive index %dx. Trashes %ax and %si. 197# 198getdrvparams: 199 movw $DPBUF,%si # Set the address of result buf 200 movw $0x001e,(%si) # len 201 movw $0x4800,%ax # BIOS: Read Drive Parameters 202 int $0x13 # Call the BIOS 203 jc err_rd # "I/O error" if error 204 ret 205# 206# Various error message entry points. 207# 208err_big: movw $msg_big,%si # "Truncated 209 call putstr # to 545k" 210 ret 211 212err_pt: movw $msg_pt,%si # "Invalid partition 213 call putstr # table" 214err_pt.1: jmp err_pt.1 # Await reset 215 216err_rd: movw $msg_rd,%si # "I/O error loading 217 call putstr # boot loader" 218 jmp err_pt.1 219 220err_noboot: movw $msg_noboot,%si # "Missing boot 221 call putstr # loader" 222 jmp err_pt.1 223# 224# Output an ASCIZ string to the console via the BIOS. 225# 226putstr.0: movw $0x7,%bx # Page:attribute 227 movb $0xe,%ah # BIOS: Display 228 int $0x10 # character 229putstr: lodsb # Get character 230 testb %al,%al # End of string? 231 jnz putstr.0 # No 232 ret 233 234msg_big: .asciz "Loaded only 545k" 235msg_pt: .asciz "Invalid partition table" 236msg_rd: .asciz "I/O error loading boot loader" 237msg_noboot: .asciz "Missing boot loader" 238 239lba: .quad 1 # LBA of GPT header 240 241boot_uuid: .long 0x83bd6b9d 242 .word 0x7f41 243 .word 0x11dc 244 .byte 0xbe 245 .byte 0x0b 246 .byte 0x00 247 .byte 0x15 248 .byte 0x60 249 .byte 0xb8 250 .byte 0x4f 251 .byte 0x0f 252 253 .org DISKSIG,0x90 254sig: .long 0 # OS Disk Signature 255 .word 0 # "Unknown" in PMBR 256 257partbl: .fill 0x10,0x4,0x0 # Partition table 258 .word MAGIC # Magic number 259