Ticket #4028: haiku_gpt_mbr.S

File haiku_gpt_mbr.S, 12.7 KB (added by meianoite, 14 years ago)

Updated with fixed comments and nicer formatting (set your editor to 4 spaces per tab)

Line 
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#
120start: 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#
131reloc: 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
143main_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#
150load_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#
163load_part: movw $GPT_ADDR+GPT_PART_LBA,%si
164 movw $PART_ADDR,%bx
165 movw $1,%cx # Read 1 sector
166 call read
167scan: 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
181load_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
188start_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#
196next_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#
209try_mbr: call setup # Start afresh
210 movw $LOAD,%sp # Set up MBR stack
211main_mbr: xorw %si,%si # No active partition
212 movw $partbl,%bx # Partition table
213 movb $0x4,%cl # Number of entries
214main_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
220main_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#
230main_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#
236main_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
262main_mbr.5: popw %bx # Restore %bx (For CHS load)
263 popw %cx # Restore %cx (For CHS load)
264main_mbr.6: movw $0x201,%ax # BIOS: Read from disk
265main_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#
284setup: 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#
294validate_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
300validate_drv.1: movb $0x80,%dl # Assume drive 0x80
301validate_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#
307read: 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#
325err_pt: movw $msg_pt,%si # "Bad partition
326 jmp putstr # table"
327
328err_rd: movw $msg_rd,%si # "IO Error"
329 jmp putstr
330
331err_noboot: movw $msg_noboot,%si # "Missing System
332 jmp putstr # Bootloader"
333#
334# Output an ASCIZ string to the console via the BIOS.
335#
336putstr.0: movw $0x7,%bx # Page:attribute
337 movb $0xe,%ah # BIOS: Display
338 int $0x10 # character
339putstr: lodsb # Get character
340 testb %al,%al # End of string?
341 jnz putstr.0 # No
342putstr.1: hlt # Await reset
343 jmp putstr.1 # (but avoid melting the CPU)
344
345msg_pt: .asciz "Bad Partition Table"
346msg_rd: .asciz "IO Error"
347msg_noboot: .asciz "Missing System Bootloader"
348
349 .org DISKSIG-1-1-16-8,0xff # -flags-sectors-boot_uuid-lba
350
351flags: .byte 0x80 # Try EDD packet mode
352
353sectors: .byte 0x02 # Number of sectors to load
354 # from the target partition
355
356boot_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
368lba: .quad 1 # LBA of GPT header
369
370 .org DISKSIG,0x90 # Won't pad (code is packed tight!)
371 # but here for documentation
372
373sig: .long 0 # OS Disk Signature
374 .word 0 # "Unknown" in PMBR
375
376partbl: .fill 0x10,0x4,0x0 # Partition table
377 .word MAGIC # Magic number