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
46 .set GPT_SIG_1,0x54524150
51 .set PART_ADDR,GPT_ADDR+SECSIZE # GPT partition array address
53 .set PART_START_LBA,32
56 .set NHRDRV,0x475 # Number of hard drives
58 .globl start # Entry point
62 # Setup the segment registers for flat addressing and setup the stack.
64 start: cld # String ops inc
66 movw %ax,%es # Address
69 movw $STACK,%sp # stack
71 # Relocate ourself to a lower address so that we have more room to load
74 movw $main-EXEC+LOAD,%si # Source
75 movw $main,%di # Destination
76 movw $SECSIZE-(main-start),%cx # Byte count
80 # Jump to the relocated code.
82 jmp main-LOAD+EXEC # To relocated code
84 # Validate drive number in %dl.
86 main: cmpb $0x80,%dl # Drive valid?
88 movb NHRDRV,%dh # Calculate the highest
89 addb $0x80,%dh # drive number available
90 cmpb %dh,%dl # Within range?
92 main.1: movb $0x80,%dl # Assume drive 0x80
94 # Load the primary GPT header from LBA 1 and verify signature.
96 main.2: movw $GPT_ADDR,%bx
99 cmpl $GPT_SIG_0,GPT_ADDR+GPT_SIG
101 cmpl $GPT_SIG_1,GPT_ADDR+GPT_SIG+4
104 # Load a partition table sector from disk and look for a FreeBSD boot
107 load_part: movw $GPT_ADDR+GPT_PART_LBA,%si
110 scan: movw %bx,%si # Compare partition UUID
111 movw $boot_uuid,%di # with FreeBSD boot UUID
114 jnz next_part # Didn't match, next partition
116 # We found a boot partition. Load it into RAM starting at 0x7c00.
118 movw %bx,%di # Save partition pointer in %di
119 leaw PART_START_LBA(%di),%si
123 load_boot: push %si # Save %si
126 movl PART_END_LBA(%di),%eax # See if this was the last LBA
129 movl PART_END_LBA+4(%di),%eax
132 mov %bx,%es # Reset %es to zero
133 jmp LOAD # Jump to boot code
134 next_boot: incl (%si) # Next LBA
136 mov %es,%ax # Adjust segment for next
137 addw $SECSIZE/16,%ax # sector
138 cmp $0x9000,%ax # Don't load past 0x90000,
139 jae err_big # 545k should be enough for
140 mov %ax,%es # any boot code. :)
143 # Move to the next partition. If we walk off the end of the sector, load
144 # the next sector. We assume that partition entries are smaller than 64k
145 # and that they won't span a sector boundary.
147 # XXX: Should we int 0x18 instead of err_noboot if we hit the end of the table?
149 next_part: decl GPT_ADDR+GPT_NPART # Was this the last partition?
151 movw GPT_ADDR+GPT_PART_SIZE,%ax
152 addw %ax,%bx # Next partition
153 cmpw $PART_ADDR+0x200,%bx # Still in sector?
155 incl GPT_ADDR+GPT_PART_LBA # Next sector
156 adcl $0,GPT_ADDR+GPT_PART_LBA+4
159 # Load a sector (64-bit LBA at %si) from disk %dl into %es:%bx by creating
160 # a EDD packet on the stack and passing it to the BIOS. Trashes %ax and %si.
162 read: pushl 0x4(%si) # Set the LBA
163 pushl 0x0(%si) # address
164 pushw %es # Set the address of
165 pushw %bx # the transfer buffer
166 pushw $0x1 # Read 1 sector
167 pushw $0x10 # Packet length
168 movw %sp,%si # Packer pointer
169 movw $0x4200,%ax # BIOS: LBA Read from disk
170 int $0x13 # Call the BIOS
171 add $0x10,%sp # Restore stack
175 # Various error message entry points.
177 err_big: movw $msg_big,%si # "Boot loader too
180 err_pt: movw $msg_pt,%si # "Invalid partition
183 err_rd: movw $msg_rd,%si # "I/O error loading
184 jmp putstr # boot loader"
186 err_noboot: movw $msg_noboot,%si # "Missing boot
189 # Output an ASCIZ string to the console via the BIOS.
191 putstr.0: movw $0x7,%bx # Page:attribute
192 movb $0xe,%ah # BIOS: Display
193 int $0x10 # character
194 putstr: lodsb # Get character
195 testb %al,%al # End of string?
197 putstr.1: jmp putstr.1 # Await reset
199 msg_big: .asciz "Boot loader too large"
200 msg_pt: .asciz "Invalid partition table"
201 msg_rd: .asciz "I/O error loading boot loader"
202 msg_noboot: .asciz "Missing boot loader"
204 lba: .quad 1 # LBA of GPT header
206 boot_uuid: .long 0x83bd6b9d
219 sig: .long 0 # OS Disk Signature
220 .word 0 # "Unknown" in PMBR
222 partbl: .fill 0x10,0x4,0x0 # Partition table
223 .word MAGIC # Magic number