1 | #
|
---|
2 | # Partly from:
|
---|
3 | # $FreeBSD: src/sys/boot/i386/pmbr/pmbr.s,v 1.2 2007/11/26 21:29:59 jhb Exp $
|
---|
4 | #-
|
---|
5 | # Copyright (c) 2007 Yahoo!, Inc.
|
---|
6 | # All rights reserved.
|
---|
7 | # Written by: John Baldwin <jhb@FreeBSD.org>
|
---|
8 | #
|
---|
9 | # Redistribution and use in source and binary forms, with or without
|
---|
10 | # modification, are permitted provided that the following conditions
|
---|
11 | # are met:
|
---|
12 | # 1. Redistributions of source code must retain the above copyright
|
---|
13 | # notice, this list of conditions and the following disclaimer.
|
---|
14 | # 2. Redistributions in binary form must reproduce the above copyright
|
---|
15 | # notice, this list of conditions and the following disclaimer in the
|
---|
16 | # documentation and/or other materials provided with the distribution.
|
---|
17 | # 3. Neither the name of the author nor the names of any co-contributors
|
---|
18 | # may be used to endorse or promote products derived from this software
|
---|
19 | # without specific prior written permission.
|
---|
20 | #
|
---|
21 | # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
---|
22 | # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
---|
23 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
---|
24 | # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
---|
25 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
---|
26 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
---|
27 | # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
---|
28 | # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
---|
29 | # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
---|
30 | # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
---|
31 | # SUCH DAMAGE.
|
---|
32 | #
|
---|
33 |
|
---|
34 | #
|
---|
35 | # Partly from:
|
---|
36 | # $FreeBSD: src/sys/boot/i386/mbr/mbr.s,v 1.7 2004/08/28 08:39:35 yar Exp $
|
---|
37 | #
|
---|
38 | # Copyright (c) 1999 Robert Nordier
|
---|
39 | # All rights reserved.
|
---|
40 | #
|
---|
41 | # Redistribution and use in source and binary forms are freely
|
---|
42 | # permitted provided that the above copyright notice and this
|
---|
43 | # paragraph and the following disclaimer are duplicated in all
|
---|
44 | # such forms.
|
---|
45 | #
|
---|
46 | # This software is provided "AS IS" and without any express or
|
---|
47 | # implied warranties, including, without limitation, the implied
|
---|
48 | # warranties of merchantability and fitness for a particular
|
---|
49 | # purpose.
|
---|
50 | #
|
---|
51 |
|
---|
52 | #
|
---|
53 | # "Hybridisation" and modifications for booting Haiku by Andre' Braga
|
---|
54 | # (andrebraga@gmail.com) The modifications herein contained are released into
|
---|
55 | # the Public Domain.
|
---|
56 | #
|
---|
57 |
|
---|
58 | #
|
---|
59 | # A 512 byte PMBR boot loader that looks for the UUID of a Haiku GPT partition
|
---|
60 | # and boots it, falling back to MBR partitions if said UUID isn't found or if
|
---|
61 | # the (primary) GPT is corrupted or non-existent.
|
---|
62 | # Its usefulness is in being a generalised IPL that supports both
|
---|
63 | # partitioning styles, allowing it to be used transparently and even allowing
|
---|
64 | # disks to be converted from one partitioning style to the other with ease,
|
---|
65 | # should the need for more partitions or volumes over 2TiB arise (for instance
|
---|
66 | # when cloning an older disk to a newer, more capacious one).
|
---|
67 | # It also paves the way for Haiku to create and support booting from
|
---|
68 | # multiple volumes larger than 2TiB, which we're in the very privileged position
|
---|
69 | # of enjoying efficiently in the near future due to BFS. Another use case is
|
---|
70 | # taking a disk from a Intel EFI machine, plugging it on a BIOS machine and boot
|
---|
71 | # just fine; and vice-versa.
|
---|
72 | # As mentioned, if there are valid partitions defined in the MBR, and the
|
---|
73 | # primary GPT becomes corrupt, it can fall back to loading the MBR partition
|
---|
74 | # with the active flag set, if one is defined.
|
---|
75 | # Currently there's no provision for falling back to the GPT copy that
|
---|
76 | # lives in the end of the disk, due to the 512 bytes constraint; supporting this
|
---|
77 | # would require either some major refactoring of the code or disabling the
|
---|
78 | # support for booting from MBR using calls to int13h other than function 4200h,
|
---|
79 | # "LBA Read from Disk".
|
---|
80 | # For the GPT boot, the number of sectors to load from the partition is
|
---|
81 | # adjustable (needed by FreeBSD's "gptloader" on a freebsd-boot UUID
|
---|
82 | # partition), probably needed by Haiku as well since stage1 is 2 sectors
|
---|
83 | # big), but beware that int13h 4200h only supports up to 127 (0x7f) sectors,
|
---|
84 | # or a loader of almost 64KiB; so don't specify a larger number. This is not
|
---|
85 | # checked by the code, again because of space constraints.
|
---|
86 | #
|
---|
87 |
|
---|
88 | .set LOAD,0x7c00 # Load address
|
---|
89 | .set EXEC,0x600 # Execution address
|
---|
90 | .set MAGIC,0xaa55 # Magic: bootable
|
---|
91 | .set SECSIZE,0x200 # Size of a single disk sector
|
---|
92 | .set DISKSIG,440 # Disk signature offset
|
---|
93 | .set PT_OFF,0x1be # Partition table
|
---|
94 |
|
---|
95 | .set STACK,EXEC+SECSIZE*4 # Stack address
|
---|
96 |
|
---|
97 | .set FL_PACKET,0x80 # Flag: try EDD
|
---|
98 |
|
---|
99 | .set GPT_ADDR,STACK # GPT header address
|
---|
100 | .set GPT_SIG,0
|
---|
101 | .set GPT_SIG_0,0x20494645
|
---|
102 | .set GPT_SIG_1,0x54524150
|
---|
103 | .set GPT_MYLBA,24
|
---|
104 | .set GPT_PART_LBA,72
|
---|
105 | .set GPT_NPART,80
|
---|
106 | .set GPT_PART_SIZE,84
|
---|
107 | .set PART_ADDR,GPT_ADDR+SECSIZE # GPT partition array addr.
|
---|
108 | .set PART_TYPE,0
|
---|
109 | .set PART_START_LBA,32
|
---|
110 | .set PART_END_LBA,40
|
---|
111 |
|
---|
112 | .set NHRDRV,0x475 # Number of hard drives
|
---|
113 |
|
---|
114 | .globl start # Entry point
|
---|
115 | .code16
|
---|
116 |
|
---|
117 | #
|
---|
118 | # Setup the segment registers for flat addressing and setup the stack.
|
---|
119 | #
|
---|
120 | start: cld # String ops inc
|
---|
121 | call setup # Used by the two loader types,
|
---|
122 | # GPT and MBR; must come
|
---|
123 | # after relocation
|
---|
124 |
|
---|
125 | movw $STACK,%sp # Set up GPT stack
|
---|
126 |
|
---|
127 | #
|
---|
128 | # Relocate ourself to a lower address so that we have more room to load
|
---|
129 | # other sectors.
|
---|
130 | #
|
---|
131 | reloc: movw $main_gpt-EXEC+LOAD,%si # Source
|
---|
132 | movw $main_gpt,%di # Destination
|
---|
133 | movw $SECSIZE-(main_gpt-start),%cx # Byte count
|
---|
134 | rep # Relocate
|
---|
135 | movsb # code
|
---|
136 |
|
---|
137 | #
|
---|
138 | # Jump to the relocated code.
|
---|
139 | #
|
---|
140 | jmp main_gpt-LOAD+EXEC # To relocated code
|
---|
141 |
|
---|
142 |
|
---|
143 | main_gpt: call validate_drv # validate_drv is also
|
---|
144 | # shared between GPT
|
---|
145 | # and MBR loaders
|
---|
146 |
|
---|
147 | #
|
---|
148 | # Load the primary GPT header from LBA 1 and verify signature.
|
---|
149 | #
|
---|
150 | load_gpt_hdr: movw $GPT_ADDR,%bx
|
---|
151 | movw $lba,%si
|
---|
152 | movw $1,%cx # Read 1 sector
|
---|
153 | call read
|
---|
154 | cmpl $GPT_SIG_0,GPT_ADDR+GPT_SIG
|
---|
155 | jnz try_mbr # If invalid GPT header
|
---|
156 | cmpl $GPT_SIG_1,GPT_ADDR+GPT_SIG+4
|
---|
157 | jnz try_mbr # Fluke :( Try MBR now
|
---|
158 |
|
---|
159 | #
|
---|
160 | # GPT is valid. Load a partition table sector from disk and look for a
|
---|
161 | # partition matching the UUID found in boot_uuid.
|
---|
162 | #
|
---|
163 | load_part: movw $GPT_ADDR+GPT_PART_LBA,%si
|
---|
164 | movw $PART_ADDR,%bx
|
---|
165 | movw $1,%cx # Read 1 sector
|
---|
166 | call read
|
---|
167 | scan: movw %bx,%si # Compare partition UUID
|
---|
168 | movw $boot_uuid,%di # with Haiku boot UUID
|
---|
169 | movb $0x10,%cl
|
---|
170 | repe cmpsb
|
---|
171 | jnz next_part # Didn't match, next partition
|
---|
172 | #
|
---|
173 | # We found a partition. Load it into RAM starting at 0x7c00.
|
---|
174 | #
|
---|
175 | movw %bx,%di # Save partition pointer in %di
|
---|
176 | leaw PART_START_LBA(%di),%si
|
---|
177 | movw $LOAD/16,%bx
|
---|
178 | movw %bx,%es
|
---|
179 | xorw %bx,%bx
|
---|
180 |
|
---|
181 | load_bootcode: push %si # Save %si
|
---|
182 |
|
---|
183 | # Load up to 127 sectors into
|
---|
184 | movb sectors,%cl # physical address 0x7c00
|
---|
185 | call read # (Notice that %cx is zero due
|
---|
186 | # to "repe cmpsb" above)
|
---|
187 |
|
---|
188 | start_loader: xorw %ax,%ax
|
---|
189 | movw %ax,%es # Reset %es to zero
|
---|
190 | jmp LOAD # Jump to boot code
|
---|
191 |
|
---|
192 | #
|
---|
193 | # Move to the next partition. If we walk off the end of the sector, load
|
---|
194 | # the next sector.
|
---|
195 | #
|
---|
196 | next_part: decl GPT_ADDR+GPT_NPART # Was this the last partition?
|
---|
197 | jz try_mbr # UUID boot signature not found
|
---|
198 | movw GPT_ADDR+GPT_PART_SIZE,%ax
|
---|
199 | addw %ax,%bx # Next partition
|
---|
200 | cmpw $PART_ADDR+0x200,%bx # Still in sector?
|
---|
201 | jb scan
|
---|
202 | incl GPT_ADDR+GPT_PART_LBA # Next sector
|
---|
203 | adcl $0,GPT_ADDR+GPT_PART_LBA+4
|
---|
204 | jmp load_part
|
---|
205 |
|
---|
206 | #
|
---|
207 | # If loading a Haiku partition from a GPT fails, try booting a MBR partition.
|
---|
208 | #
|
---|
209 | try_mbr: call setup # Start afresh
|
---|
210 | movw $LOAD,%sp # Set up MBR stack
|
---|
211 | main_mbr: xorw %si,%si # No active partition
|
---|
212 | movw $partbl,%bx # Partition table
|
---|
213 | movb $0x4,%cl # Number of entries
|
---|
214 | main_mbr.1: cmpb %ch,(%bx) # Null entry?
|
---|
215 | je main_mbr.2 # Yes
|
---|
216 | jg err_pt # If 0x1..0x7f
|
---|
217 | testw %si,%si # Active already found?
|
---|
218 | jnz err_pt # Yes
|
---|
219 | movw %bx,%si # Point to active
|
---|
220 | main_mbr.2: addb $0x10,%bl # Till
|
---|
221 | loop main_mbr.1 # done
|
---|
222 | testw %si,%si # Active found?
|
---|
223 | jnz main_mbr.3 # Yes
|
---|
224 | int $0x18 # BIOS: Diskless boot
|
---|
225 |
|
---|
226 | #
|
---|
227 | # Ok, we've found a possible active partition. Check to see that the drive
|
---|
228 | # is a valid hard drive number.
|
---|
229 | #
|
---|
230 | main_mbr.3: call validate_drv
|
---|
231 |
|
---|
232 | #
|
---|
233 | # Ok, now that we have a valid drive and partition entry, load the CHS from
|
---|
234 | # the partition entry and read the sector from the disk.
|
---|
235 | #
|
---|
236 | main_mbr.4: movw %sp,%di # Save stack pointer
|
---|
237 | movb 0x1(%si),%dh # Load head
|
---|
238 | movw 0x2(%si),%cx # Load cylinder:sector
|
---|
239 | movw $LOAD,%bx # Transfer buffer
|
---|
240 | testb $FL_PACKET,flags # Try EDD?
|
---|
241 | jz main_mbr.6 # No.
|
---|
242 | pushw %cx # Save %cx (For CHS load)
|
---|
243 | pushw %bx # Save %bx (Ditto)
|
---|
244 | movw $0x55aa,%bx # Magic
|
---|
245 | movb $0x41,%ah # BIOS: EDD extensions
|
---|
246 | int $0x13 # present?
|
---|
247 | jc main_mbr.5 # No.
|
---|
248 | cmpw $0xaa55,%bx # Magic ok?
|
---|
249 | jne main_mbr.5 # No.
|
---|
250 | testb $0x1,%cl # Packet mode present?
|
---|
251 | jz main_mbr.5 # No.
|
---|
252 | popw %bx # Restore %bx
|
---|
253 | pushl $0x0 # Set the LBA
|
---|
254 | pushl 0x8(%si) # address
|
---|
255 | pushw %es # Set the address of
|
---|
256 | pushw %bx # the transfer buffer
|
---|
257 | pushw $0x1 # Read 1 sector
|
---|
258 | pushw $0x10 # Packet length
|
---|
259 | movw %sp,%si # Packet pointer
|
---|
260 | movw $0x4200,%ax # BIOS: LBA Read from disk
|
---|
261 | jmp main_mbr.7 # Skip the CHS setup
|
---|
262 | main_mbr.5: popw %bx # Restore %bx (For CHS load)
|
---|
263 | popw %cx # Restore %cx (For CHS load)
|
---|
264 | main_mbr.6: movw $0x201,%ax # BIOS: Read from disk
|
---|
265 | main_mbr.7: int $0x13 # Call the BIOS
|
---|
266 | movw %di,%sp # Restore stack
|
---|
267 | jc err_rd # If error
|
---|
268 |
|
---|
269 | #
|
---|
270 | # Now that we've loaded the bootstrap, check for the 0xaa55 signature. If it
|
---|
271 | # is present, execute the bootstrap we just loaded.
|
---|
272 | #
|
---|
273 | cmpw $MAGIC,0x1fe(%bx) # Bootable?
|
---|
274 | jne err_noboot # No
|
---|
275 | jmp start_loader # Invoke bootstrap
|
---|
276 |
|
---|
277 |
|
---|
278 | ################################################################################
|
---|
279 |
|
---|
280 | #
|
---|
281 | # Clear registers and set up stack/segments. Called at the start of both GPT and
|
---|
282 | # MBR loaders.
|
---|
283 | #
|
---|
284 | setup: xorw %cx,%cx
|
---|
285 | xorw %ax,%ax # Zero
|
---|
286 | movw %ax,%es # Address
|
---|
287 | movw %ax,%ds # data
|
---|
288 | movw %ax,%ss
|
---|
289 | ret
|
---|
290 |
|
---|
291 | #
|
---|
292 | # Validate drive number in %dl.
|
---|
293 | #
|
---|
294 | validate_drv: cmpb $0x80,%dl # Drive valid?
|
---|
295 | jb validate_drv.1 # No
|
---|
296 | movb NHRDRV,%dh # Calculate the highest
|
---|
297 | addb $0x80,%dh # drive number available
|
---|
298 | cmpb %dh,%dl # Within range?
|
---|
299 | jb validate_drv.2 # Yes
|
---|
300 | validate_drv.1: movb $0x80,%dl # Assume drive 0x80
|
---|
301 | validate_drv.2: ret
|
---|
302 |
|
---|
303 | #
|
---|
304 | # Load a sector (64-bit LBA at %si) from disk %dl into %es:%bx by creating
|
---|
305 | # a EDD packet on the stack and passing it to the BIOS. Trashes %ax and %si.
|
---|
306 | #
|
---|
307 | read: pushl 0x4(%si) # Set the LBA
|
---|
308 | pushl 0x0(%si) # address
|
---|
309 | pushw %es # Set the address of
|
---|
310 | pushw %bx # the transfer buffer
|
---|
311 | pushw %cx # Read up to 127 sectors
|
---|
312 | pushw $0x10 # Packet length
|
---|
313 | movw %sp,%si # Packet pointer
|
---|
314 | movw $0x4200,%ax # BIOS: LBA Read from disk
|
---|
315 | int $0x13 # Call the BIOS
|
---|
316 | add $0x10,%sp # Restore stack
|
---|
317 | jc try_mbr # In case of error, try the
|
---|
318 | # MBR code which supports
|
---|
319 | # other int13h calls
|
---|
320 | ret
|
---|
321 |
|
---|
322 | #
|
---|
323 | # Various error message entry points.
|
---|
324 | #
|
---|
325 | err_pt: movw $msg_pt,%si # "Bad partition
|
---|
326 | jmp putstr # table"
|
---|
327 |
|
---|
328 | err_rd: movw $msg_rd,%si # "IO Error"
|
---|
329 | jmp putstr
|
---|
330 |
|
---|
331 | err_noboot: movw $msg_noboot,%si # "Missing System
|
---|
332 | jmp putstr # Bootloader"
|
---|
333 | #
|
---|
334 | # Output an ASCIZ string to the console via the BIOS.
|
---|
335 | #
|
---|
336 | putstr.0: movw $0x7,%bx # Page:attribute
|
---|
337 | movb $0xe,%ah # BIOS: Display
|
---|
338 | int $0x10 # character
|
---|
339 | putstr: lodsb # Get character
|
---|
340 | testb %al,%al # End of string?
|
---|
341 | jnz putstr.0 # No
|
---|
342 | putstr.1: hlt # Await reset
|
---|
343 | jmp putstr.1 # (but avoid melting the CPU)
|
---|
344 |
|
---|
345 | msg_pt: .asciz "Bad Partition Table"
|
---|
346 | msg_rd: .asciz "IO Error"
|
---|
347 | msg_noboot: .asciz "Missing System Bootloader"
|
---|
348 |
|
---|
349 | .org DISKSIG-1-1-16-8,0xff # -flags-sectors-boot_uuid-lba
|
---|
350 |
|
---|
351 | flags: .byte 0x80 # Try EDD packet mode
|
---|
352 |
|
---|
353 | sectors: .byte 0x02 # Number of sectors to load
|
---|
354 | # from the target partition
|
---|
355 |
|
---|
356 | boot_uuid: .long 0x42465331 # 'BFS1' (formally, UUID time-low)
|
---|
357 | .word 0x3ba3 # UUID time-mid
|
---|
358 | .word 0x10f1 # UUID time-high & version (v1)
|
---|
359 | .byte 0x80 # UUID DCE 1.1 variant
|
---|
360 | .byte 0x2a # '*' (formally, UUID clock-seq-low)
|
---|
361 | .byte 0x48 # 'H'
|
---|
362 | .byte 0x61 # 'a'
|
---|
363 | .byte 0x69 # 'i'
|
---|
364 | .byte 0x6b # 'k'
|
---|
365 | .byte 0x75 # 'u'
|
---|
366 | .byte 0x21 # '!'
|
---|
367 |
|
---|
368 | lba: .quad 1 # LBA of GPT header
|
---|
369 |
|
---|
370 | .org DISKSIG,0x90 # Won't pad (code is packed tight!)
|
---|
371 | # but here for documentation
|
---|
372 |
|
---|
373 | sig: .long 0 # OS Disk Signature
|
---|
374 | .word 0 # "Unknown" in PMBR
|
---|
375 |
|
---|
376 | partbl: .fill 0x10,0x4,0x0 # Partition table
|
---|
377 | .word MAGIC # Magic number
|
---|