1*11e8ecddSJessica Hamilton/* 2*11e8ecddSJessica Hamilton * Partly from: 3*11e8ecddSJessica Hamilton * $FreeBSD: src/sys/boot/i386/pmbr/pmbr.s,v 1.2 2007/11/26 21:29:59 jhb Exp $ 4*11e8ecddSJessica Hamilton * 5*11e8ecddSJessica Hamilton * Copyright (c) 2007 Yahoo!, Inc. 6*11e8ecddSJessica Hamilton * All rights reserved. 7*11e8ecddSJessica Hamilton * Written by: John Baldwin <jhb@FreeBSD.org> 8*11e8ecddSJessica Hamilton * 9*11e8ecddSJessica Hamilton * Redistribution and use in source and binary forms, with or without 10*11e8ecddSJessica Hamilton * modification, are permitted provided that the following conditions 11*11e8ecddSJessica Hamilton * are met: 12*11e8ecddSJessica Hamilton * 1. Redistributions of source code must retain the above copyright 13*11e8ecddSJessica Hamilton * notice, this list of conditions and the following disclaimer. 14*11e8ecddSJessica Hamilton * 2. Redistributions in binary form must reproduce the above copyright 15*11e8ecddSJessica Hamilton * notice, this list of conditions and the following disclaimer in the 16*11e8ecddSJessica Hamilton * documentation and/or other materials provided with the distribution. 17*11e8ecddSJessica Hamilton * 3. Neither the name of the author nor the names of any co-contributors 18*11e8ecddSJessica Hamilton * may be used to endorse or promote products derived from this software 19*11e8ecddSJessica Hamilton * without specific prior written permission. 20*11e8ecddSJessica Hamilton * 21*11e8ecddSJessica Hamilton * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 22*11e8ecddSJessica Hamilton * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23*11e8ecddSJessica Hamilton * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24*11e8ecddSJessica Hamilton * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 25*11e8ecddSJessica Hamilton * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26*11e8ecddSJessica Hamilton * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27*11e8ecddSJessica Hamilton * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28*11e8ecddSJessica Hamilton * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29*11e8ecddSJessica Hamilton * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30*11e8ecddSJessica Hamilton * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31*11e8ecddSJessica Hamilton * SUCH DAMAGE. 32*11e8ecddSJessica Hamilton * 33*11e8ecddSJessica Hamilton * 34*11e8ecddSJessica Hamilton * Partly from: 35*11e8ecddSJessica Hamilton * $FreeBSD: src/sys/boot/i386/mbr/mbr.s,v 1.7 2004/08/28 08:39:35 yar Exp $ 36*11e8ecddSJessica Hamilton * 37*11e8ecddSJessica Hamilton * Copyright (c) 1999 Robert Nordier 38*11e8ecddSJessica Hamilton * All rights reserved. 39*11e8ecddSJessica Hamilton * 40*11e8ecddSJessica Hamilton * Redistribution and use in source and binary forms are freely 41*11e8ecddSJessica Hamilton * permitted provided that the above copyright notice and this 42*11e8ecddSJessica Hamilton * paragraph and the following disclaimer are duplicated in all 43*11e8ecddSJessica Hamilton * such forms. 44*11e8ecddSJessica Hamilton * 45*11e8ecddSJessica Hamilton * This software is provided "AS IS" and without any express or 46*11e8ecddSJessica Hamilton * implied warranties, including, without limitation, the implied 47*11e8ecddSJessica Hamilton * warranties of merchantability and fitness for a particular 48*11e8ecddSJessica Hamilton * purpose. 49*11e8ecddSJessica Hamilton * 50*11e8ecddSJessica Hamilton * 51*11e8ecddSJessica Hamilton * "Hybridisation" and modifications for booting Haiku by Andre' Braga 52*11e8ecddSJessica Hamilton * (me@andrebraga.com), with valuable input from Jean-Loïc Charroud 53*11e8ecddSJessica Hamilton * (jcharroud@free.fr). The modifications contained herein are released into 54*11e8ecddSJessica Hamilton * the Public Domain. 55*11e8ecddSJessica Hamilton * 56*11e8ecddSJessica Hamilton * 57*11e8ecddSJessica Hamilton * A 432 bytes MBR IPL (Initial Program Loader) that looks for the UUID of 58*11e8ecddSJessica Hamilton * a Haiku Boot GUID partition and boots it, falling back to MBR partitions if 59*11e8ecddSJessica Hamilton * said UUID isn't found or if the (primary) GPT is corrupted or non-existent. 60*11e8ecddSJessica Hamilton * Its usefulness is in being a versatile, "universal" IPL that supports 61*11e8ecddSJessica Hamilton * both partitioning styles, allowing it to be used transparently and even 62*11e8ecddSJessica Hamilton * facilitating the conversion between partitioning styles, should the need 63*11e8ecddSJessica Hamilton * for more partitions or volumes over 2TiB arise (for instance when cloning 64*11e8ecddSJessica Hamilton * an older disk to a newer, more capacious one). 65*11e8ecddSJessica Hamilton * It also paves the way for Haiku to create and support booting from 66*11e8ecddSJessica Hamilton * multiple volumes larger than 2TiB, which we're in the very privileged 67*11e8ecddSJessica Hamilton * position of enjoying efficiently in the near future due to BFS. Another use 68*11e8ecddSJessica Hamilton * case is taking a disk from a Intel EFI machine, plugging it on a BIOS 69*11e8ecddSJessica Hamilton * machine and boot just fine; and vice-versa. 70*11e8ecddSJessica Hamilton * As mentioned, if there are valid partitions defined in the MBR, and the 71*11e8ecddSJessica Hamilton * primary GPT becomes corrupt, it can fall back to loading the MBR partition 72*11e8ecddSJessica Hamilton * with the active flag set, if one is defined. 73*11e8ecddSJessica Hamilton * Currently there's no provision for falling back to the GPT copy that 74*11e8ecddSJessica Hamilton * lives in the end of the disk, due to the 512 bytes constraint; supporting 75*11e8ecddSJessica Hamilton * this is unlikely given that the code is packed tight. An alternative would be 76*11e8ecddSJessica Hamilton * disabling support for booting from MBR using BIOS calls other than Int13h 77*11e8ecddSJessica Hamilton * function 42h, "Extended Read From Disk" (i.e., LBA mode). It's unlikely that 78*11e8ecddSJessica Hamilton * any machine that Haiku supports won't have this BIOS function, but having an 79*11e8ecddSJessica Hamilton * "universal" IPL should be quite useful to, say, people using Haiku to 80*11e8ecddSJessica Hamilton * rewrite a corrupt MBR on another disk using the excellent DiskProbe. 81*11e8ecddSJessica Hamilton * The number of sectors loaded depends on the boot style. Booting from a 82*11e8ecddSJessica Hamilton * MBR partition assumes that the Partition Boot Record is one sector long, 83*11e8ecddSJessica Hamilton * whereas booting from a GPT partition assumes a partition exclusive for a 84*11e8ecddSJessica Hamilton * system loader and will either copy its entirety into memory starting from 85*11e8ecddSJessica Hamilton * address 0x7c00, or will copy up to circa 545KiB, whichever is smaller. Thus, 86*11e8ecddSJessica Hamilton * it remains compatible with the FreeBSD gptloader and should work for loading 87*11e8ecddSJessica Hamilton * Bootman from an exclusive Haiku boot manager partition as well. 88*11e8ecddSJessica Hamilton * It should be easy to adjust the UUID signature as needed. It lives at 89*11e8ecddSJessica Hamilton * offset 0x1a0 (416), leaving plenty of space before the 32-bit disk signature 90*11e8ecddSJessica Hamilton * at offset 0x1b8 (440), so compatibility with Microsoft Windows and other OSs 91*11e8ecddSJessica Hamilton * is maintained. 92*11e8ecddSJessica Hamilton */ 93*11e8ecddSJessica Hamilton 94*11e8ecddSJessica Hamilton .set LOAD,0x7c00 95*11e8ecddSJessica Hamilton .set EXEC,0x600 96*11e8ecddSJessica Hamilton .set MAGIC,0xaa55 97*11e8ecddSJessica Hamilton .set HANDSHAKE,0x55aa 98*11e8ecddSJessica Hamilton .set SECSIZE,0x200 99*11e8ecddSJessica Hamilton 100*11e8ecddSJessica Hamilton /* data offsets */ 101*11e8ecddSJessica Hamilton .set UUID,0x1a0 102*11e8ecddSJessica Hamilton .set DISKSIG,0x1b8 103*11e8ecddSJessica Hamilton .set PT_OFF,0x1be 104*11e8ecddSJessica Hamilton 105*11e8ecddSJessica Hamilton .set GPTSTACK,EXEC+SECSIZE*4-8 /* Stack address */ 106*11e8ecddSJessica Hamilton .set LBABUF,GPTSTACK /* LBA address pointer buffer, */ 107*11e8ecddSJessica Hamilton /* 8 bytes long, after stack */ 108*11e8ecddSJessica Hamilton 109*11e8ecddSJessica Hamilton .set GPT_ADDR,LBABUF+8 /* GPT header address */ 110*11e8ecddSJessica Hamilton .set GPT_SIG,0 /* Signature offset from LBA 1 */ 111*11e8ecddSJessica Hamilton .set GPT_SIG_0,0x20494645 /* "EFI ", bswapped */ 112*11e8ecddSJessica Hamilton .set GPT_SIG_1,0x54524150 /* "PART", bswapped */ 113*11e8ecddSJessica Hamilton .set GPT_MYLBA,24 /* Offs of curr header copy addr */ 114*11e8ecddSJessica Hamilton .set GPT_PART_LBA,72 /* Offs of partitions start LBA */ 115*11e8ecddSJessica Hamilton .set GPT_NPART,80 /* Offs to number of partitions */ 116*11e8ecddSJessica Hamilton .set GPT_PART_SIZE,84 /* Offs to size of partition */ 117*11e8ecddSJessica Hamilton .set PART_ADDR,GPT_ADDR+SECSIZE /* GPT partition array addr. */ 118*11e8ecddSJessica Hamilton .set PART_TYPE,0 119*11e8ecddSJessica Hamilton .set PART_START_LBA,32 /* Offs to 1st LBA on part entry */ 120*11e8ecddSJessica Hamilton .set PART_END_LBA,40 /* Offs to last LBA */ 121*11e8ecddSJessica Hamilton 122*11e8ecddSJessica Hamilton .set NHRDRV,0x475 /* Number of hard drives */ 123*11e8ecddSJessica Hamilton 124*11e8ecddSJessica Hamilton .globl start /* Entry point */ 125*11e8ecddSJessica Hamilton .code16 126*11e8ecddSJessica Hamilton 127*11e8ecddSJessica Hamilton/* 128*11e8ecddSJessica Hamilton * Setup the segment registers for flat addressing and setup the stack. 129*11e8ecddSJessica Hamilton */ 130*11e8ecddSJessica Hamiltonstart: cli /* Clear interrupts before relocation */ 131*11e8ecddSJessica Hamilton 132*11e8ecddSJessica Hamilton xorw %ax,%ax /* Zero */ 133*11e8ecddSJessica Hamilton movw %ax,%es /* Address */ 134*11e8ecddSJessica Hamilton movw %ax,%ds /* data */ 135*11e8ecddSJessica Hamilton 136*11e8ecddSJessica Hamilton movw %ax,%ss /* Set up */ 137*11e8ecddSJessica Hamilton movw $GPTSTACK,%sp /* stack */ 138*11e8ecddSJessica Hamilton 139*11e8ecddSJessica Hamilton std /* String ops set to decrement */ 140*11e8ecddSJessica Hamilton movw $LOAD,%si /* We'll clear working memory starting */ 141*11e8ecddSJessica Hamilton leaw -1(%si),%di /* from $LOAD-1 and stopping at EXEC. */ 142*11e8ecddSJessica Hamilton movw $(LOAD-EXEC-1),%cx /* In the end we have %si pointing */ 143*11e8ecddSJessica Hamilton rep stosb /* at LOAD and %di at EXEC. */ 144*11e8ecddSJessica Hamilton 145*11e8ecddSJessica Hamilton 146*11e8ecddSJessica Hamilton/* 147*11e8ecddSJessica Hamilton * Relocate ourself to a lower address so that we have more room to load 148*11e8ecddSJessica Hamilton * other sectors. 149*11e8ecddSJessica Hamilton */ 150*11e8ecddSJessica Hamiltonreloc: cld /* String ops set to increment */ 151*11e8ecddSJessica Hamilton movw $SECSIZE,%cx /* Now we walk forward and relocate. */ 152*11e8ecddSJessica Hamilton rep movsb /* Tricky, but works great! */ 153*11e8ecddSJessica Hamilton 154*11e8ecddSJessica Hamilton/* 155*11e8ecddSJessica Hamilton * Jump to the relocated code. 156*11e8ecddSJessica Hamilton */ 157*11e8ecddSJessica Hamilton jmp $0,$main /* Absolute address (far) jump */ 158*11e8ecddSJessica Hamilton 159*11e8ecddSJessica Hamilton/* 160*11e8ecddSJessica Hamilton * Will land here; we're now at %cs = 0x0000 and %ip a little above 0x0600 161*11e8ecddSJessica Hamilton */ 162*11e8ecddSJessica Hamiltonmain: sti /* Re-enable interrupts */ 163*11e8ecddSJessica Hamilton 164*11e8ecddSJessica Hamilton#ifdef VALIDATE_DRV 165*11e8ecddSJessica Hamilton/* 166*11e8ecddSJessica Hamilton * Validate drive number in %dl. Certain BIOSes might not like it. 167*11e8ecddSJessica Hamilton */ 168*11e8ecddSJessica Hamiltonvalidate_drv: 169*11e8ecddSJessica Hamilton cmpb $0x80,%dl /* Drive valid? (>= 0x80) */ 170*11e8ecddSJessica Hamilton jb validate_drv.1 /* No */ 171*11e8ecddSJessica Hamilton movb NHRDRV,%dh /* Calculate the highest */ 172*11e8ecddSJessica Hamilton addb $0x80,%dh /* drive number available */ 173*11e8ecddSJessica Hamilton cmpb %dh,%dl /* Within range? */ 174*11e8ecddSJessica Hamilton jb test_extensions /* Yes, proceed */ 175*11e8ecddSJessica Hamiltonvalidate_drv.1: 176*11e8ecddSJessica Hamilton movb $0x80,%dl /* Else, assume drive 0x80 */ 177*11e8ecddSJessica Hamilton#endif 178*11e8ecddSJessica Hamilton 179*11e8ecddSJessica Hamilton/* 180*11e8ecddSJessica Hamilton * Test if BIOS supports Int13h extensions. If so, will try GPT scheme first. 181*11e8ecddSJessica Hamilton * Else, sets flag (%dh = 1) and goes straight to MBR code. 182*11e8ecddSJessica Hamilton * (%dl still contains the drive number from BIOS bootstrap) 183*11e8ecddSJessica Hamilton */ 184*11e8ecddSJessica Hamiltontest_extensions: 185*11e8ecddSJessica Hamilton movb $0,%dh /* We'll test for EDD extensions. */ 186*11e8ecddSJessica Hamilton /* LBA read (Int13,42) uses only */ 187*11e8ecddSJessica Hamilton /* %dl to get drive number and if */ 188*11e8ecddSJessica Hamilton /* we must fall back to CHS read */ 189*11e8ecddSJessica Hamilton /* (Int13,02), %dh receives head */ 190*11e8ecddSJessica Hamilton /* number, so it's clear to use */ 191*11e8ecddSJessica Hamilton /* %dh to hold a "use CHS" flag */ 192*11e8ecddSJessica Hamilton 193*11e8ecddSJessica Hamilton movw $HANDSHAKE,%bx /* EDD extensions magic number */ 194*11e8ecddSJessica Hamilton movb $0x41,%ah /* BIOS: EDD extensions */ 195*11e8ecddSJessica Hamilton int $0x13 /* present? */ 196*11e8ecddSJessica Hamilton jc set_chs /* No, fall back to CHS read */ 197*11e8ecddSJessica Hamiltontest_magic: 198*11e8ecddSJessica Hamilton cmpw $MAGIC,%bx /* Magic ok? */ 199*11e8ecddSJessica Hamilton jne set_chs /* No, fall back to CHS read */ 200*11e8ecddSJessica Hamiltontest_packet: 201*11e8ecddSJessica Hamilton testb $0x1,%cl /* Packet mode present? */ 202*11e8ecddSJessica Hamilton jnz load_gpt_hdr /* Yes! */ 203*11e8ecddSJessica Hamiltonset_chs: 204*11e8ecddSJessica Hamilton movb $1,%dh /* read_chs overwrites this, and */ 205*11e8ecddSJessica Hamilton /* Int13,42 only uses %dl, so */ 206*11e8ecddSJessica Hamilton /* it's clear to use %dh as flag */ 207*11e8ecddSJessica Hamilton jmp try_mbr 208*11e8ecddSJessica Hamilton 209*11e8ecddSJessica Hamilton 210*11e8ecddSJessica Hamilton/* 211*11e8ecddSJessica Hamilton * If we reached here, drive is valid, LBA reads are available, will try GPT. 212*11e8ecddSJessica Hamilton * Load the primary GPT header from LBA 1 and verify signature. 213*11e8ecddSJessica Hamilton */ 214*11e8ecddSJessica Hamiltonload_gpt_hdr: 215*11e8ecddSJessica Hamilton movw $GPT_ADDR,%bx 216*11e8ecddSJessica Hamilton movw $LBABUF,%si /* Will load LBA sector 1 from disk */ 217*11e8ecddSJessica Hamilton movb $1,(%si) /* (64-bit value! Memory was zeroed so */ 218*11e8ecddSJessica Hamilton /* it's OK to write only the LSB) */ 219*11e8ecddSJessica Hamilton call read 220*11e8ecddSJessica Hamilton cmpl $GPT_SIG_0,GPT_ADDR+GPT_SIG 221*11e8ecddSJessica Hamilton jnz try_mbr /* If invalid GPT header */ 222*11e8ecddSJessica Hamilton cmpl $GPT_SIG_1,GPT_ADDR+GPT_SIG+4 223*11e8ecddSJessica Hamilton jnz try_mbr /* Fluke :( Try MBR now */ 224*11e8ecddSJessica Hamilton 225*11e8ecddSJessica Hamilton/* 226*11e8ecddSJessica Hamilton * GPT is valid. Load a partition table sector from disk and look for a 227*11e8ecddSJessica Hamilton * partition matching the UUID found in boot_uuid. 228*11e8ecddSJessica Hamilton */ 229*11e8ecddSJessica Hamiltonload_part: 230*11e8ecddSJessica Hamilton movw $GPT_ADDR+GPT_PART_LBA,%si 231*11e8ecddSJessica Hamilton movw $PART_ADDR,%bx 232*11e8ecddSJessica Hamilton call read 233*11e8ecddSJessica Hamiltonscan: 234*11e8ecddSJessica Hamilton movw %bx,%si /* Compare partition UUID */ 235*11e8ecddSJessica Hamilton movw $boot_uuid,%di /* with Haiku boot UUID */ 236*11e8ecddSJessica Hamilton movb $0x10,%cl /* (16 bytes) */ 237*11e8ecddSJessica Hamilton repe cmpsb 238*11e8ecddSJessica Hamilton jnz next_part /* Didn't match, next partition */ 239*11e8ecddSJessica Hamilton 240*11e8ecddSJessica Hamilton/* 241*11e8ecddSJessica Hamilton * We found a partition. Load it into RAM starting at 0x7c00. 242*11e8ecddSJessica Hamilton */ 243*11e8ecddSJessica Hamilton movw %bx,%di /* Save partition pointer in %di */ 244*11e8ecddSJessica Hamilton leaw PART_START_LBA(%di),%si 245*11e8ecddSJessica Hamilton movw $LOAD/16,%bx 246*11e8ecddSJessica Hamilton movw %bx,%es 247*11e8ecddSJessica Hamilton xorw %bx,%bx 248*11e8ecddSJessica Hamiltonload_bootcode: 249*11e8ecddSJessica Hamilton push %si /* Save %si */ 250*11e8ecddSJessica Hamilton call read 251*11e8ecddSJessica Hamilton pop %si /* Restore */ 252*11e8ecddSJessica Hamilton movl PART_END_LBA(%di),%eax /* See if this was the last LBA */ 253*11e8ecddSJessica Hamilton cmpl (%si),%eax 254*11e8ecddSJessica Hamilton jnz next_boot_lba 255*11e8ecddSJessica Hamilton movl PART_END_LBA+4(%di),%eax 256*11e8ecddSJessica Hamilton cmpl 4(%si),%eax 257*11e8ecddSJessica Hamilton jnz next_boot_lba 258*11e8ecddSJessica Hamilton jmp start_loader /* Jump to boot code */ 259*11e8ecddSJessica Hamilton 260*11e8ecddSJessica Hamiltonnext_boot_lba: 261*11e8ecddSJessica Hamilton incl (%si) /* Next LBA */ 262*11e8ecddSJessica Hamilton adcl $0,4(%si) 263*11e8ecddSJessica Hamilton mov %es,%ax /* Adjust segment for next */ 264*11e8ecddSJessica Hamilton addw $SECSIZE/16,%ax /* sector */ 265*11e8ecddSJessica Hamilton cmp $0x9000,%ax /* Don't load past 0x90000, */ 266*11e8ecddSJessica Hamilton jae start_loader /* 545k should be enough for */ 267*11e8ecddSJessica Hamilton mov %ax,%es /* any boot code. :) */ 268*11e8ecddSJessica Hamilton jmp load_bootcode 269*11e8ecddSJessica Hamilton 270*11e8ecddSJessica Hamilton/* 271*11e8ecddSJessica Hamilton * Move to the next partition. If we walk off the end of the sector, load 272*11e8ecddSJessica Hamilton * the next sector. 273*11e8ecddSJessica Hamilton */ 274*11e8ecddSJessica Hamiltonnext_part: 275*11e8ecddSJessica Hamilton decl GPT_ADDR+GPT_NPART /* Was this the last partition? */ 276*11e8ecddSJessica Hamilton jz try_mbr /* UUID boot signature not found */ 277*11e8ecddSJessica Hamilton movw GPT_ADDR+GPT_PART_SIZE,%ax 278*11e8ecddSJessica Hamilton addw %ax,%bx /* Next partition */ 279*11e8ecddSJessica Hamilton cmpw $PART_ADDR+0x200,%bx /* Still in sector? */ 280*11e8ecddSJessica Hamilton jb scan 281*11e8ecddSJessica Hamilton incl GPT_ADDR+GPT_PART_LBA /* Next sector */ 282*11e8ecddSJessica Hamilton adcl $0,GPT_ADDR+GPT_PART_LBA+4 283*11e8ecddSJessica Hamilton jmp load_part 284*11e8ecddSJessica Hamilton 285*11e8ecddSJessica Hamilton/* 286*11e8ecddSJessica Hamilton * If loading boot sectors from a GPT partition fails, try booting a MBR part. 287*11e8ecddSJessica Hamilton * Reset stack/segment. Could have been tainted by the GPT loading code. 288*11e8ecddSJessica Hamilton */ 289*11e8ecddSJessica Hamiltontry_mbr: 290*11e8ecddSJessica Hamilton xorw %ax,%ax /* Zero */ 291*11e8ecddSJessica Hamilton movw %ax,%es /* extra segment */ 292*11e8ecddSJessica Hamilton movw $LOAD,%sp /* Reset stack */ 293*11e8ecddSJessica Hamilton 294*11e8ecddSJessica Hamilton xorw %si,%si /* Will point to active partition */ 295*11e8ecddSJessica Hamilton movw $(EXEC+PT_OFF),%bx /* Point to partition table start */ 296*11e8ecddSJessica Hamilton movw $0x4,%cx /* Tested entries counter (4 total) */ 297*11e8ecddSJessica Hamiltonread_mbr_entry: 298*11e8ecddSJessica Hamilton cmpb %ch,(%bx) /* Null entry? (%ch just zeroed) */ 299*11e8ecddSJessica Hamilton je next_mbr_entry /* Yes */ 300*11e8ecddSJessica Hamilton jg err_part_table /* If 0x1..0x7f */ 301*11e8ecddSJessica Hamilton testw %si,%si /* Active already found? */ 302*11e8ecddSJessica Hamilton jnz err_part_table /* Yes */ 303*11e8ecddSJessica Hamilton movw %bx,%si /* Point to active */ 304*11e8ecddSJessica Hamiltonnext_mbr_entry: 305*11e8ecddSJessica Hamilton addb $0x10,%bl /* Till */ 306*11e8ecddSJessica Hamilton loop read_mbr_entry /* done */ 307*11e8ecddSJessica Hamilton testw %si,%si /* Active found? */ 308*11e8ecddSJessica Hamilton jnz read_bootsect /* Yes, read OS loader */ 309*11e8ecddSJessica Hamiltontry_diskless: 310*11e8ecddSJessica Hamilton int $0x18 /* Else, BIOS: Diskless boot */ 311*11e8ecddSJessica Hamilton 312*11e8ecddSJessica Hamilton 313*11e8ecddSJessica Hamilton/* 314*11e8ecddSJessica Hamilton * Ok, now that we have a valid drive and partition entry, load either CHS 315*11e8ecddSJessica Hamilton * or LBA from the partition entry and read the boot sector from the partition. 316*11e8ecddSJessica Hamilton */ 317*11e8ecddSJessica Hamiltonread_bootsect: 318*11e8ecddSJessica Hamilton movw %sp,%bx /* Write addr. (%sp points to LOAD) */ 319*11e8ecddSJessica Hamilton pushw %si /* Points at active part. entry; */ 320*11e8ecddSJessica Hamilton /* save, else 'read' will trash it */ 321*11e8ecddSJessica Hamiltontest_flag: 322*11e8ecddSJessica Hamilton cmpb $1,%dh /* Test flag set by set_chs above */ 323*11e8ecddSJessica Hamilton jz read_chs /* CHS read if set */ 324*11e8ecddSJessica Hamiltonread_lba: 325*11e8ecddSJessica Hamilton addw $0x8,%si /* Start LBA of partition, 32-bit */ 326*11e8ecddSJessica Hamilton movw $LBABUF,%di /* So far either QWORD 1 or 0, so */ 327*11e8ecddSJessica Hamilton movsl /* more significant bytes are all 0 */ 328*11e8ecddSJessica Hamilton xchg %di,%si /* Copy to buffer and swap pointers */ 329*11e8ecddSJessica Hamilton subw $0x4,%si /* Adjust back to start of buffer */ 330*11e8ecddSJessica Hamilton call read 331*11e8ecddSJessica Hamilton jmp finished_read /* Skip the CHS setup */ 332*11e8ecddSJessica Hamiltonread_chs: 333*11e8ecddSJessica Hamilton movb 0x1(%si),%dh /* Load head */ 334*11e8ecddSJessica Hamilton movw 0x2(%si),%cx /* Load cylinder:sector */ 335*11e8ecddSJessica Hamilton movb $2,%al /* Read two sectors */ 336*11e8ecddSJessica Hamilton movb $2,%ah /* BIOS: Read sectors from disk */ 337*11e8ecddSJessica Hamilton int $0x13 /* Call the BIOS */ 338*11e8ecddSJessica Hamiltonfinished_read: 339*11e8ecddSJessica Hamilton jc err_reading /* If error */ 340*11e8ecddSJessica Hamilton 341*11e8ecddSJessica Hamilton 342*11e8ecddSJessica Hamilton/* 343*11e8ecddSJessica Hamilton * Now that we've loaded the bootstrap, check for the 0xaa55 signature. If it 344*11e8ecddSJessica Hamilton * is present, execute the bootstrap we just loaded. 345*11e8ecddSJessica Hamilton */ 346*11e8ecddSJessica Hamilton popw %si /* Restore %si (active part entry) */ 347*11e8ecddSJessica Hamilton movb %dl,(%si) /* Patch part record with drive num */ 348*11e8ecddSJessica Hamilton cmpw $MAGIC,0x1fe(%bx) /* Bootable? */ 349*11e8ecddSJessica Hamilton jne err_noboot /* No, error out. */ 350*11e8ecddSJessica Hamilton /* Else, start loader */ 351*11e8ecddSJessica Hamiltonstart_loader: 352*11e8ecddSJessica Hamilton xorw %ax,%ax 353*11e8ecddSJessica Hamilton movw %ax,%es /* Reset %es to zero */ 354*11e8ecddSJessica Hamilton jmp $0,$LOAD /* Jump to boot code */ 355*11e8ecddSJessica Hamilton 356*11e8ecddSJessica Hamilton 357*11e8ecddSJessica Hamilton/* Auxiliary functions */ 358*11e8ecddSJessica Hamilton 359*11e8ecddSJessica Hamilton 360*11e8ecddSJessica Hamilton/* 361*11e8ecddSJessica Hamilton * Load a sector (64-bit LBA at %si) from disk %dl into %es:%bx by creating 362*11e8ecddSJessica Hamilton * a EDD packet on the stack and passing it to the BIOS. Trashes %ax and %si. 363*11e8ecddSJessica Hamilton */ 364*11e8ecddSJessica Hamiltonread: 365*11e8ecddSJessica Hamilton pushl 0x4(%si) /* Set the LBA */ 366*11e8ecddSJessica Hamilton pushl 0x0(%si) /* address */ 367*11e8ecddSJessica Hamilton pushw %es /* Set the address of */ 368*11e8ecddSJessica Hamilton pushw %bx /* the transfer buffer */ 369*11e8ecddSJessica Hamilton pushw $0x1 /* Read 1 sector */ 370*11e8ecddSJessica Hamilton pushw $0x10 /* Packet length */ 371*11e8ecddSJessica Hamilton movw %sp,%si /* Packet pointer */ 372*11e8ecddSJessica Hamilton movw $0x4200,%ax /* BIOS: LBA Read from disk */ 373*11e8ecddSJessica Hamilton int $0x13 /* Call the BIOS */ 374*11e8ecddSJessica Hamilton add $0x10,%sp /* Restore stack */ 375*11e8ecddSJessica Hamilton jc err_reading /* If error */ 376*11e8ecddSJessica Hamilton ret 377*11e8ecddSJessica Hamilton 378*11e8ecddSJessica Hamilton 379*11e8ecddSJessica Hamilton/* 380*11e8ecddSJessica Hamilton * Output an ASCIZ string pointed at by %si to the console via the BIOS. 381*11e8ecddSJessica Hamilton */ 382*11e8ecddSJessica Hamiltonputstr.0: 383*11e8ecddSJessica Hamilton movw $0x7,%bx /* Page:attribute */ 384*11e8ecddSJessica Hamilton movb $0xe,%ah /* BIOS: Display */ 385*11e8ecddSJessica Hamilton int $0x10 /* character */ 386*11e8ecddSJessica Hamiltonputstr: 387*11e8ecddSJessica Hamilton lodsb /* Get character */ 388*11e8ecddSJessica Hamilton testb %al,%al /* End of string? */ 389*11e8ecddSJessica Hamilton jnz putstr.0 /* No */ 390*11e8ecddSJessica Hamilton ret 391*11e8ecddSJessica Hamilton 392*11e8ecddSJessica Hamilton 393*11e8ecddSJessica Hamilton/* 394*11e8ecddSJessica Hamilton * Various error message entry points. 395*11e8ecddSJessica Hamilton */ 396*11e8ecddSJessica Hamiltonerr_part_table: 397*11e8ecddSJessica Hamilton movw $msg_badtable,%si /* "Bad Part. Table!" */ 398*11e8ecddSJessica Hamilton call putstr 399*11e8ecddSJessica Hamilton jmp halt 400*11e8ecddSJessica Hamilton 401*11e8ecddSJessica Hamilton 402*11e8ecddSJessica Hamiltonerr_reading: 403*11e8ecddSJessica Hamilton movw $msg_ioerror,%si /* "Read Error!" */ 404*11e8ecddSJessica Hamilton call putstr 405*11e8ecddSJessica Hamilton jmp halt 406*11e8ecddSJessica Hamilton 407*11e8ecddSJessica Hamilton 408*11e8ecddSJessica Hamiltonerr_noboot: 409*11e8ecddSJessica Hamilton movw $msg_noloader,%si /* "No Sys Loader!" */ 410*11e8ecddSJessica Hamilton call putstr 411*11e8ecddSJessica Hamilton /* fall-through to halt */ 412*11e8ecddSJessica Hamilton 413*11e8ecddSJessica Hamilton 414*11e8ecddSJessica Hamiltonhalt: 415*11e8ecddSJessica Hamilton cli 416*11e8ecddSJessica Hamilton hlt 417*11e8ecddSJessica Hamilton jmp halt 418*11e8ecddSJessica Hamilton 419*11e8ecddSJessica Hamilton 420*11e8ecddSJessica Hamilton/* Data section */ 421*11e8ecddSJessica Hamilton 422*11e8ecddSJessica Hamilton 423*11e8ecddSJessica Hamilton#ifdef VALIDATE_DRV 424*11e8ecddSJessica Hamilton/* Messages must be shortened so the code fits 440 bytes */ 425*11e8ecddSJessica Hamiltonmsg_badtable: .asciz "BadPTbl!" 426*11e8ecddSJessica Hamiltonmsg_ioerror: .asciz "IOErr!" 427*11e8ecddSJessica Hamiltonmsg_noloader: .asciz "NoSysLdr!" 428*11e8ecddSJessica Hamilton#else 429*11e8ecddSJessica Hamiltonmsg_badtable: .asciz "Bad Part. Table!" 430*11e8ecddSJessica Hamiltonmsg_ioerror: .asciz "Read Error!" 431*11e8ecddSJessica Hamiltonmsg_noloader: .asciz "No Sys Loader!" 432*11e8ecddSJessica Hamilton#endif 433*11e8ecddSJessica Hamilton 434*11e8ecddSJessica Hamilton/* Boot partition UUID signature */ 435*11e8ecddSJessica Hamilton .org UUID,0x0 /* Zero-pad up to UUID offset */ 436*11e8ecddSJessica Hamilton 437*11e8ecddSJessica Hamiltonboot_uuid: 438*11e8ecddSJessica Hamilton .long 0x42465331 /* 'BFS1' (formally, UUID time-low) */ 439*11e8ecddSJessica Hamilton .word 0x3ba3 /* UUID time-mid */ 440*11e8ecddSJessica Hamilton .word 0x10f1 /* UUID time-high & version (v1) */ 441*11e8ecddSJessica Hamilton .byte 0x80 /* UUID DCE 1.1 variant */ 442*11e8ecddSJessica Hamilton .byte 0x2a /* '*' (formally, UUID clock-seq-low) */ 443*11e8ecddSJessica Hamilton .byte 0x48 /* 'H' */ 444*11e8ecddSJessica Hamilton .byte 0x61 /* 'a' */ 445*11e8ecddSJessica Hamilton .byte 0x69 /* 'i' */ 446*11e8ecddSJessica Hamilton .byte 0x6b /* 'k' */ 447*11e8ecddSJessica Hamilton .byte 0x75 /* 'u' */ 448*11e8ecddSJessica Hamilton .byte 0x21 /* '!' */ 449*11e8ecddSJessica Hamilton 450*11e8ecddSJessica Hamilton#ifndef MBR_CODE_ONLY 451*11e8ecddSJessica Hamilton/* Disk signature */ 452*11e8ecddSJessica Hamilton .org DISKSIG,0x0 /* Zero-pad up to signature offset */ 453*11e8ecddSJessica Hamilton 454*11e8ecddSJessica Hamiltonsig: 455*11e8ecddSJessica Hamilton .long 0 /* OS Disk Signature */ 456*11e8ecddSJessica Hamilton .word 0 /* "Unknown" in PMBR */ 457*11e8ecddSJessica Hamilton 458*11e8ecddSJessica Hamilton/* Partition table */ 459*11e8ecddSJessica Hamilton .org PT_OFF,0x0 /* Won't pad, just documenting */ 460*11e8ecddSJessica Hamilton 461*11e8ecddSJessica Hamiltonpartbl: 462*11e8ecddSJessica Hamilton .fill 0x10,0x4,0x0 /* Partition table */ 463*11e8ecddSJessica Hamilton .word MAGIC /* Magic number */ 464*11e8ecddSJessica Hamilton#endif 465