pmbr.s revision 172940
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# $FreeBSD: head/sys/boot/i386/pmbr/pmbr.s 172940 2007-10-24 21:33:00Z jhb $ 31 32# A 512 byte PMBR boot manager that looks for a FreeBSD boot GPT partition 33# and boots it. 34 35 .set LOAD,0x7c00 # Load address 36 .set EXEC,0x600 # Execution address 37 .set MAGIC,0xaa55 # Magic: bootable 38 .set SECSIZE,0x200 # Size of a single disk sector 39 .set DISKSIG,440 # Disk signature offset 40 .set STACK,EXEC+SECSIZE*4 # Stack address 41 .set GPT_ADDR,STACK # GPT header address 42 .set GPT_SIG,0 43 .set GPT_SIG_0,0x20494645 44 .set GPT_SIG_1,0x54524150 45 .set GPT_MYLBA,24 46 .set GPT_PART_LBA,72 47 .set GPT_NPART,80 48 .set GPT_PART_SIZE,84 49 .set PART_ADDR,GPT_ADDR+SECSIZE # GPT partition array address 50 .set PART_TYPE,0 51 .set PART_START_LBA,32 52 .set PART_END_LBA,40 53 54 .set NHRDRV,0x475 # Number of hard drives 55 56 .globl start # Entry point 57 .code16 58 59# 60# Setup the segment registers for flat addressing and setup the stack. 61# 62start: cld # String ops inc 63 xorw %ax,%ax # Zero 64 movw %ax,%es # Address 65 movw %ax,%ds # data 66 movw %ax,%ss # Set up 67 movw $STACK,%sp # stack 68# 69# Relocate ourself to a lower address so that we have more room to load 70# other sectors. 71# 72 movw $main-EXEC+LOAD,%si # Source 73 movw $main,%di # Destination 74 movw $SECSIZE-(main-start),%cx # Byte count 75 rep # Relocate 76 movsb # code 77# 78# Jump to the relocated code. 79# 80 jmp main-LOAD+EXEC # To relocated code 81# 82# Validate drive number in %dl. 83# 84main: cmpb $0x80,%dl # Drive valid? 85 jb main.1 # No 86 movb NHRDRV,%dh # Calculate the highest 87 addb $0x80,%dh # drive number available 88 cmpb %dh,%dl # Within range? 89 jb main.2 # Yes 90main.1: movb $0x80,%dl # Assume drive 0x80 91# 92# Load the primary GPT header from LBA 1 and verify signature. 93# 94main.2: movw $GPT_ADDR,%bx 95 movw $lba,%si 96 call read 97 cmpl $GPT_SIG_0,GPT_ADDR+GPT_SIG 98 jnz err_pt 99 cmpl $GPT_SIG_1,GPT_ADDR+GPT_SIG+4 100 jnz err_pt 101# 102# Load a partition table sector from disk and look for a FreeBSD boot 103# partition. 104# 105load_part: movw $GPT_ADDR+GPT_PART_LBA,%si 106 movw $PART_ADDR,%bx 107 call read 108scan: movw %bx,%si # Compare partition UUID 109 movw $boot_uuid,%di # with FreeBSD boot UUID 110 movb $0x10,%cl 111 repe cmpsb 112 jnz next_part # Didn't match, next partition 113# 114# We found a boot partition. Load it into RAM starting at 0x7c00. 115# 116 movw %bx,%di # Save partition pointer in %di 117 leaw PART_START_LBA(%di),%si 118 movw $LOAD/16,%bx 119 movw %bx,%es 120 xorw %bx,%bx 121load_boot: push %si # Save %si 122 call read 123 pop %si # Restore 124 movl PART_END_LBA(%di),%eax # See if this was the last LBA 125 cmpl (%si),%eax 126 jnz next_boot 127 movl PART_END_LBA+4(%di),%eax 128 cmpl 4(%si),%eax 129 jnz next_boot 130 mov %bx,%es # Reset %es to zero 131 jmp LOAD # Jump to boot code 132next_boot: incl (%si) # Next LBA 133 adcl $0,4(%si) 134 mov %es,%ax # Adjust segment for next 135 addw $SECSIZE/16,%ax # sector 136 cmp $0x9000,%ax # Don't load past 0x90000, 137 jae err_big # 545k should be enough for 138 mov %ax,%es # any boot code. :) 139 jmp load_boot 140# 141# Move to the next partition. If we walk off the end of the sector, load 142# the next sector. We assume that partition entries are smaller than 64k 143# and that they won't span a sector boundary. 144# 145# XXX: Should we int 0x18 instead of err_noboot if we hit the end of the table? 146# 147next_part: decl GPT_ADDR+GPT_NPART # Was this the last partition? 148 jz err_noboot 149 movw GPT_ADDR+GPT_PART_SIZE,%ax 150 addw %ax,%bx # Next partition 151 cmpw $PART_ADDR+0x200,%bx # Still in sector? 152 jb scan 153 incl GPT_ADDR+GPT_PART_LBA # Next sector 154 adcl $0,GPT_ADDR+GPT_PART_LBA+4 155 jmp load_part 156# 157# Load a sector (64-bit LBA at %si) from disk %dl into %es:%bx by creating 158# a EDD packet on the stack and passing it to the BIOS. Trashes %ax and %si. 159# 160read: pushl 0x4(%si) # Set the LBA 161 pushl 0x0(%si) # address 162 pushw %es # Set the address of 163 pushw %bx # the transfer buffer 164 pushw $0x1 # Read 1 sector 165 pushw $0x10 # Packet length 166 movw %sp,%si # Packer pointer 167 movw $0x4200,%ax # BIOS: LBA Read from disk 168 int $0x13 # Call the BIOS 169 add $0x10,%sp # Restore stack 170 jc err_rd # If error 171 ret 172# 173# Various error message entry points. 174# 175err_big: movw $msg_big,%si # "Boot loader too 176 jmp putstr # large" 177 178err_pt: movw $msg_pt,%si # "Invalid partition 179 jmp putstr # table" 180 181err_rd: movw $msg_rd,%si # "I/O error loading 182 jmp putstr # boot loader" 183 184err_noboot: movw $msg_noboot,%si # "Missing boot 185 jmp putstr # loader" 186# 187# Output an ASCIZ string to the console via the BIOS. 188# 189putstr.0: movw $0x7,%bx # Page:attribute 190 movb $0xe,%ah # BIOS: Display 191 int $0x10 # character 192putstr: lodsb # Get character 193 testb %al,%al # End of string? 194 jnz putstr.0 # No 195putstr.1: jmp putstr.1 # Await reset 196 197msg_big: .asciz "Boot loader too large" 198msg_pt: .asciz "Invalid partition table" 199msg_rd: .asciz "I/O error loading boot loader" 200msg_noboot: .asciz "Missing boot loader" 201 202lba: .quad 1 # LBA of GPT header 203 204boot_uuid: .long 0x83bd6b9d 205 .word 0x7f41 206 .word 0x11dc 207 .byte 0xbe 208 .byte 0x0b 209 .byte 0x00 210 .byte 0x15 211 .byte 0x60 212 .byte 0xb8 213 .byte 0x4f 214 .byte 0x0f 215 216 .org DISKSIG,0x90 217sig: .long 0 # OS Disk Signature 218 .word 0 # "Unknown" in PMBR 219 220partbl: .fill 0x10,0x4,0x0 # Partition table 221 .word MAGIC # Magic number 222