2 # Copyright (c) 2007 Yahoo!, Inc.
4 # Written by: John Baldwin <jhb@FreeBSD.org>
6 # Redistribution and use in source and binary forms, with or without
7 # modification, are permitted provided that the following conditions
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.
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
32 # Partly from: src/sys/boot/i386/mbr/mbr.s 1.7
34 # A 512 byte PMBR boot manager that looks for a FreeBSD boot GPT partition
37 .set LOAD,0x7c00 # Load address
38 .set EXEC,0x600 # Execution address
39 .set MAGIC,0xaa55 # Magic: bootable
40 .set SECSIZE,0x200 # Size of a single disk sector
41 .set DISKSIG,440 # Disk signature offset
42 .set STACK,EXEC+SECSIZE*4 # Stack address
43 .set GPT_ADDR,STACK # GPT header address
45 .set GPT_SIG_0,0x20494645 # "EFI "
46 .set GPT_SIG_1,0x54524150 # "PART"
51 .set PART_ADDR,GPT_ADDR+SECSIZE # GPT partition array address
53 .set PART_START_LBA,32
55 .set DPBUF,PART_ADDR+SECSIZE
56 .set DPBUF_SEC,0x10 # Number of sectors
58 .set NHRDRV,0x475 # Number of hard drives
60 .globl start # Entry point
64 # Setup the segment registers for flat addressing and setup the stack.
66 start: cld # String ops inc
68 movw %ax,%es # Address
71 movw $STACK,%sp # stack
73 # Relocate ourself to a lower address so that we have more room to load
76 movw $main-EXEC+LOAD,%si # Source
77 movw $main,%di # Destination
78 movw $SECSIZE-(main-start),%cx # Byte count
82 # Jump to the relocated code.
84 jmp main-LOAD+EXEC # To relocated code
86 # Validate drive number in %dl.
88 main: cmpb $0x80,%dl # Drive valid?
90 movb NHRDRV,%dh # Calculate the highest
91 addb $0x80,%dh # drive number available
92 cmpb %dh,%dl # Within range?
94 main.1: movb $0x80,%dl # Assume drive 0x80
96 # Load the GPT header and verify signature. Try LBA 1 for the primary one and
97 # the last LBA for the backup if it is broken.
99 main.2: call getdrvparams # Read drive parameters
100 movb $1,%dh # %dh := 1 (reading primary)
101 main.2a: movw $GPT_ADDR,%bx
103 call read # Read header and check GPT sig
104 cmpl $GPT_SIG_0,GPT_ADDR+GPT_SIG
106 cmpl $GPT_SIG_1,GPT_ADDR+GPT_SIG+4
109 main.2b: cmpb $1,%dh # Reading primary?
110 jne err_pt # If no - invalid table found
112 # Try alternative LBAs from the last sector for the GPT header.
114 main.3: movb $0,%dh # %dh := 0 (reading backup)
115 movw $DPBUF+DPBUF_SEC,%si # %si = last sector + 1
116 movw $lba,%di # %di = $lba
117 main.3a: decl (%si) # 0x0(%si) = last sec (0-31)
120 movsw # $lastsec--, copy it to $lba
121 jmp main.2a # Read the next sector
123 # Load a partition table sector from disk and look for a FreeBSD boot
126 load_part: movw $GPT_ADDR+GPT_PART_LBA,%si
129 scan: movw %bx,%si # Compare partition UUID
130 movw $boot_uuid,%di # with FreeBSD boot UUID
133 jnz next_part # Didn't match, next partition
135 # We found a boot partition. Load it into RAM starting at 0x7c00.
137 movw %bx,%di # Save partition pointer in %di
138 leaw PART_START_LBA(%di),%si
142 load_boot: push %si # Save %si
145 movl PART_END_LBA(%di),%eax # See if this was the last LBA
148 movl PART_END_LBA+4(%di),%eax
151 mov %bx,%es # Reset %es to zero
152 jmp LOAD # Jump to boot code
153 next_boot: incl (%si) # Next LBA
155 mov %es,%ax # Adjust segment for next
156 addw $SECSIZE/16,%ax # sector
157 cmp $0x9000,%ax # Don't load past 0x90000,
158 jae err_big # 545k should be enough for
159 mov %ax,%es # any boot code. :)
162 # Move to the next partition. If we walk off the end of the sector, load
163 # the next sector. We assume that partition entries are smaller than 64k
164 # and that they won't span a sector boundary.
166 # XXX: Should we int 0x18 instead of err_noboot if we hit the end of the table?
168 next_part: decl GPT_ADDR+GPT_NPART # Was this the last partition?
170 movw GPT_ADDR+GPT_PART_SIZE,%ax
171 addw %ax,%bx # Next partition
172 cmpw $PART_ADDR+0x200,%bx # Still in sector?
174 incl GPT_ADDR+GPT_PART_LBA # Next sector
175 adcl $0,GPT_ADDR+GPT_PART_LBA+4
178 # Load a sector (64-bit LBA at %si) from disk %dl into %es:%bx by creating
179 # a EDD packet on the stack and passing it to the BIOS. Trashes %ax and %si.
181 read: pushl 0x4(%si) # Set the LBA
182 pushl 0x0(%si) # address
183 pushw %es # Set the address of
184 pushw %bx # the transfer buffer
185 pushw $0x1 # Read 1 sector
186 pushw $0x10 # Packet length
187 movw %sp,%si # Packer pointer
188 movw $0x4200,%ax # BIOS: LBA Read from disk
189 int $0x13 # Call the BIOS
190 add $0x10,%sp # Restore stack
194 # Check the number of LBAs on the drive index %dx. Trashes %ax and %si.
197 movw $DPBUF,%si # Set the address of result buf
198 movw $0x001e,(%si) # len
199 movw $0x4800,%ax # BIOS: Read Drive Parameters
200 int $0x13 # Call the BIOS
201 jc err_rd # "I/O error" if error
204 # Various error message entry points.
206 err_big: movw $msg_big,%si # "Boot loader too
209 err_pt: movw $msg_pt,%si # "Invalid partition
212 err_rd: movw $msg_rd,%si # "I/O error loading
213 jmp putstr # boot loader"
215 err_noboot: movw $msg_noboot,%si # "Missing boot
218 # Output an ASCIZ string to the console via the BIOS.
220 putstr.0: movw $0x7,%bx # Page:attribute
221 movb $0xe,%ah # BIOS: Display
222 int $0x10 # character
223 putstr: lodsb # Get character
224 testb %al,%al # End of string?
226 putstr.1: jmp putstr.1 # Await reset
228 msg_big: .asciz "Boot loader too large"
229 msg_pt: .asciz "Invalid partition table"
230 msg_rd: .asciz "I/O error loading boot loader"
231 msg_noboot: .asciz "Missing boot loader"
233 lba: .quad 1 # LBA of GPT header
235 boot_uuid: .long 0x83bd6b9d
248 sig: .long 0 # OS Disk Signature
249 .word 0 # "Unknown" in PMBR
251 partbl: .fill 0x10,0x4,0x0 # Partition table
252 .word MAGIC # Magic number