1*479ab7f0SSascha Wildner/* 2*479ab7f0SSascha Wildner * Copyright (c) 1999 Robert Nordier 3*479ab7f0SSascha Wildner * All rights reserved. 4*479ab7f0SSascha Wildner * 5*479ab7f0SSascha Wildner * Redistribution and use in source and binary forms are freely 6*479ab7f0SSascha Wildner * permitted provided that the above copyright notice and this 7*479ab7f0SSascha Wildner * paragraph and the following disclaimer are duplicated in all 8*479ab7f0SSascha Wildner * such forms. 9*479ab7f0SSascha Wildner * 10*479ab7f0SSascha Wildner * This software is provided "AS IS" and without any express or 11*479ab7f0SSascha Wildner * implied warranties, including, without limitation, the implied 12*479ab7f0SSascha Wildner * warranties of merchantability and fitness for a particular 13*479ab7f0SSascha Wildner * purpose. 14*479ab7f0SSascha Wildner * 15*479ab7f0SSascha Wildner * 16*479ab7f0SSascha Wildner * $FreeBSD: src/sys/boot/i386/mbr/mbr.s,v 1.6 2000/06/27 20:04:10 jhb Exp $ 17*479ab7f0SSascha Wildner * $DragonFly: src/sys/boot/pc32/mbr/mbr.s,v 1.3 2003/11/10 06:08:36 dillon Exp $ 18*479ab7f0SSascha Wildner */ 19*479ab7f0SSascha Wildner 20*479ab7f0SSascha Wildner/* 21*479ab7f0SSascha Wildner * A 512 byte MBR boot manager that simply boots the active partition. 22*479ab7f0SSascha Wildner */ 23*479ab7f0SSascha Wildner 24*479ab7f0SSascha Wildner .set LOAD,0x7c00 # Load address 25*479ab7f0SSascha Wildner .set EXEC,0x600 # Execution address 26*479ab7f0SSascha Wildner .set PT_OFF,0x1be # Partition table 27*479ab7f0SSascha Wildner .set MAGIC,0xaa55 # Magic: bootable 28*479ab7f0SSascha Wildner 29*479ab7f0SSascha Wildner .set NHRDRV,0x475 # Number of hard drives 30*479ab7f0SSascha Wildner 31*479ab7f0SSascha Wildner .globl start # Entry point 32*479ab7f0SSascha Wildner .code16 33*479ab7f0SSascha Wildner 34*479ab7f0SSascha Wildner/* 35*479ab7f0SSascha Wildner * Setup the segment registers for flat addressing and setup the stack. 36*479ab7f0SSascha Wildner */ 37*479ab7f0SSascha Wildnerstart: cld # String ops inc 38*479ab7f0SSascha Wildner xorw %ax,%ax # Zero 39*479ab7f0SSascha Wildner movw %ax,%es # Address 40*479ab7f0SSascha Wildner movw %ax,%ds # data 41*479ab7f0SSascha Wildner movw %ax,%ss # Set up 42*479ab7f0SSascha Wildner movw $LOAD,%sp # stack 43*479ab7f0SSascha Wildner/* 44*479ab7f0SSascha Wildner * Relocate ourself to a lower address so that we are out of the way when 45*479ab7f0SSascha Wildner * we load in the bootstrap from the partition to boot. 46*479ab7f0SSascha Wildner */ 47*479ab7f0SSascha Wildner movw $main-EXEC+LOAD,%si # Source 48*479ab7f0SSascha Wildner movw $main,%di # Destination 49*479ab7f0SSascha Wildner movw $0x200-(main-start),%cx # Byte count 50*479ab7f0SSascha Wildner rep # Relocate 51*479ab7f0SSascha Wildner movsb # code 52*479ab7f0SSascha Wildner/* 53*479ab7f0SSascha Wildner * Jump to the relocated code. 54*479ab7f0SSascha Wildner */ 55*479ab7f0SSascha Wildner jmp main-LOAD+EXEC # To relocated code 56*479ab7f0SSascha Wildner/* 57*479ab7f0SSascha Wildner * Scan the partition table looking for an active entry. Note that %ch is 58*479ab7f0SSascha Wildner * zero from the repeated string instruction above. We save the offset of 59*479ab7f0SSascha Wildner * the active partition in %si and scan the entire table to ensure that only 60*479ab7f0SSascha Wildner * one partition is marked active. 61*479ab7f0SSascha Wildner */ 62*479ab7f0SSascha Wildnermain: xorw %si,%si # No active partition 63*479ab7f0SSascha Wildner movw $partbl,%bx # Partition table 64*479ab7f0SSascha Wildner movb $0x4,%cl # Number of entries 65*479ab7f0SSascha Wildnermain.1: cmpb %ch,(%bx) # Null entry? 66*479ab7f0SSascha Wildner je main.2 # Yes 67*479ab7f0SSascha Wildner jg err_pt # If 0x1..0x7f 68*479ab7f0SSascha Wildner testw %si,%si # Active already found? 69*479ab7f0SSascha Wildner jnz err_pt # Yes 70*479ab7f0SSascha Wildner movw %bx,%si # Point to active 71*479ab7f0SSascha Wildnermain.2: addb $0x10,%bl # Till 72*479ab7f0SSascha Wildner loop main.1 # done 73*479ab7f0SSascha Wildner testw %si,%si # Active found? 74*479ab7f0SSascha Wildner jnz main.3 # Yes 75*479ab7f0SSascha Wildner int $0x18 # BIOS: Diskless boot 76*479ab7f0SSascha Wildner/* 77*479ab7f0SSascha Wildner * Ok, we've found a possible active partition. Check to see that the drive 78*479ab7f0SSascha Wildner * is a valid hard drive number. 79*479ab7f0SSascha Wildner */ 80*479ab7f0SSascha Wildnermain.3: cmpb $0x80,%dl # Drive valid? 81*479ab7f0SSascha Wildner jb main.4 # No 82*479ab7f0SSascha Wildner movb NHRDRV,%dh # Calculate the highest 83*479ab7f0SSascha Wildner addb $0x80,%dh # drive number available 84*479ab7f0SSascha Wildner cmpb %dh,%dl # Within range? 85*479ab7f0SSascha Wildner jb main.5 # Yes 86*479ab7f0SSascha Wildnermain.4: movb (%si),%dl # Load drive 87*479ab7f0SSascha Wildner/* 88*479ab7f0SSascha Wildner * Ok, now that we have a valid drive and partition entry, load the CHS from 89*479ab7f0SSascha Wildner * the partition entry and read the sector from the disk. 90*479ab7f0SSascha Wildner */ 91*479ab7f0SSascha Wildnermain.5: movw %sp,%di # Save stack pointer 92*479ab7f0SSascha Wildner movb 0x1(%si),%dh # Load head 93*479ab7f0SSascha Wildner movw 0x2(%si),%cx # Load cylinder:sector 94*479ab7f0SSascha Wildner movw $LOAD,%bx # Transfer buffer 95*479ab7f0SSascha Wildner#ifdef AVOID_PACKET_MODE 96*479ab7f0SSascha Wildner cmpb $0xff,%dh # Might we need to use LBA? 97*479ab7f0SSascha Wildner jnz main.7 # No. 98*479ab7f0SSascha Wildner cmpw $0xffff,%cx # Do we need to use LBA? 99*479ab7f0SSascha Wildner jnz main.7 # No. 100*479ab7f0SSascha Wildner#endif 101*479ab7f0SSascha Wildner pushw %cx # Save %cx 102*479ab7f0SSascha Wildner pushw %bx # Save %bx 103*479ab7f0SSascha Wildner movw $0x55aa,%bx # Magic 104*479ab7f0SSascha Wildner movb $0x41,%ah # BIOS: EDD extensions 105*479ab7f0SSascha Wildner int $0x13 # present? 106*479ab7f0SSascha Wildner jc main.6 # No. 107*479ab7f0SSascha Wildner cmpw $0xaa55,%bx # Magic ok? 108*479ab7f0SSascha Wildner jne main.6 # No. 109*479ab7f0SSascha Wildner testb $0x1,%cl # Packet mode present? 110*479ab7f0SSascha Wildner jz main.6 # No. 111*479ab7f0SSascha Wildner popw %bx # Restore %bx 112*479ab7f0SSascha Wildner pushl $0x0 # Set the LBA 113*479ab7f0SSascha Wildner pushl 0x8(%si) # address 114*479ab7f0SSascha Wildner pushw %es # Set the address of 115*479ab7f0SSascha Wildner pushw %bx # the transfer buffer 116*479ab7f0SSascha Wildner pushw $0x1 # Read 1 sector 117*479ab7f0SSascha Wildner pushw $0x10 # Packet length 118*479ab7f0SSascha Wildner movw %sp,%si # Packer pointer 119*479ab7f0SSascha Wildner movw $0x4200,%ax # BIOS: LBA Read from disk 120*479ab7f0SSascha Wildner jmp main.8 # Skip the CHS setup 121*479ab7f0SSascha Wildnermain.6: popw %bx # Restore %bx 122*479ab7f0SSascha Wildner popw %cx # Restore %cx 123*479ab7f0SSascha Wildnermain.7: movw $0x201,%ax # BIOS: Read from disk 124*479ab7f0SSascha Wildnermain.8: int $0x13 # Call the BIOS 125*479ab7f0SSascha Wildner movw %di,%sp # Restore stack 126*479ab7f0SSascha Wildner jc err_rd # If error 127*479ab7f0SSascha Wildner/* 128*479ab7f0SSascha Wildner * Now that we've loaded the bootstrap, check for the 0xaa55 signature. If it 129*479ab7f0SSascha Wildner * is present, execute the bootstrap we just loaded. 130*479ab7f0SSascha Wildner */ 131*479ab7f0SSascha Wildner cmpw $MAGIC,0x1fe(%bx) # Bootable? 132*479ab7f0SSascha Wildner jne err_os # No 133*479ab7f0SSascha Wildner jmp *%bx # Invoke bootstrap 134*479ab7f0SSascha Wildner/* 135*479ab7f0SSascha Wildner * Various error message entry points. 136*479ab7f0SSascha Wildner */ 137*479ab7f0SSascha Wildnererr_pt: movw $msg_pt,%si # "Invalid partition 138*479ab7f0SSascha Wildner jmp putstr # table" 139*479ab7f0SSascha Wildner 140*479ab7f0SSascha Wildnererr_rd: movw $msg_rd,%si # "Error loading 141*479ab7f0SSascha Wildner jmp putstr # operating system" 142*479ab7f0SSascha Wildner 143*479ab7f0SSascha Wildnererr_os: movw $msg_os,%si # "Missing operating 144*479ab7f0SSascha Wildner jmp putstr # system" 145*479ab7f0SSascha Wildner/* 146*479ab7f0SSascha Wildner * Output an ASCIZ string to the console via the BIOS. 147*479ab7f0SSascha Wildner */ 148*479ab7f0SSascha Wildnerputstr.0: movw $0x7,%bx # Page:attribute 149*479ab7f0SSascha Wildner movb $0xe,%ah # BIOS: Display 150*479ab7f0SSascha Wildner int $0x10 # character 151*479ab7f0SSascha Wildnerputstr: lodsb # Get character 152*479ab7f0SSascha Wildner testb %al,%al # End of string? 153*479ab7f0SSascha Wildner jnz putstr.0 # No 154*479ab7f0SSascha Wildnerputstr.1: jmp putstr.1 # Await reset 155*479ab7f0SSascha Wildner 156*479ab7f0SSascha Wildnermsg_pt: .asciz "Invalid partition table" 157*479ab7f0SSascha Wildnermsg_rd: .asciz "Error loading operating system" 158*479ab7f0SSascha Wildnermsg_os: .asciz "Missing operating system" 159*479ab7f0SSascha Wildner 160*479ab7f0SSascha Wildner .org PT_OFF 161*479ab7f0SSascha Wildner 162*479ab7f0SSascha Wildnerpartbl: .fill 0x10,0x4,0x0 # Partition table 163*479ab7f0SSascha Wildner .word MAGIC # Magic number 164