1/* $OpenBSD: mbr.S,v 1.16 2002/01/08 23:14:51 kjell Exp $ */ 2 3/* 4 * Copyright (c) 1997 Michael Shalayeff and Tobias Weingartner 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by Michael Shalayeff. 18 * 4. The name of the author may not be used to endorse or promote products 19 * derived from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 23 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS 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/* Copyright (c) 1996 VaX#n8 (vax@linkdead.paranoia.com) 35 * last edited 9 July 1996 36 * many thanks to Erich Boleyn (erich@uruk.org) for putting up with 37 * all my questions, and for his work on GRUB 38 * You may use this code or fragments thereof in a manner consistent 39 * with the other copyrights as long as you retain my pseudonym and 40 * this copyright notice in the file. 41 */ 42 43 .file "mbr.S" 44 45#include <machine/asm.h> 46#include <assym.h> 47 48#define data32 .byte 0x66 49#define addr32 .byte 0x67 50 51#define BOOTBIOS 0x7c0 /* segment where we are loaded */ 52#define BOOTRELOC 0x7a0 /* segment where to relocate */ 53#define PARTSZ 16 /* each partition table entry is 16 bytes */ 54 55#ifdef DEBUG 56#define CHAR_S 'S' /* started */ 57#define CHAR_R 'R' /* relocated */ 58#define CHAR_L 'L' /* looking for bootable partition */ 59#define CHAR_B 'B' /* loading boot */ 60#define CHAR_G 'G' /* jumping to boot */ 61 62#define DBGMSG(msg) \ 63 movb $msg, %al; \ 64 /* call Lchr */; \ 65 .byte 0xe8; \ 66 .word Lchr - . - 2 67#else /* !DEBUG */ 68#define DBGMSG(msg) 69#endif /* !DEBUG */ 70#define puts(s) \ 71 data32; \ 72 movl $s, %esi; \ 73 /* call Lmessage */; \ 74 .byte 0xe8; \ 75 .word Lmessage - . - 2 76 77 .text 78 79 .globl start 80start: 81 /* Adjust %cs to be right */ 82 data32 83 ljmp $BOOTBIOS, $1f 841: 85 /* Set up stack */ 86 movl %cs, %ax 87 cli 88 movl %ax, %ss 89 data32 90 movl $0xfffc, %esp 91 sti 92 93 /* Set up data segment */ 94 movl %ax, %ds 95 DBGMSG(CHAR_S) 96 97 /* Relocate 512 bytes so we can load PBS here */ 98 data32 99 movl $BOOTRELOC, %eax 100 movl %ax, %es 101 data32 102 xorl %esi, %esi 103 data32 104 xorl %edi, %edi 105 data32 106 movl $0x200, %ecx 107 cld 108 rep 109 movsb 110 111 /* Jump to relocated self */ 112 data32 113 ljmp $BOOTRELOC, $reloc 114reloc: 115 DBGMSG(CHAR_R) 116 117 /* Set up %es and %ds */ 118 pushl %ds 119 popl %es /* next boot is at the same place as we were loaded */ 120 pushl %cs 121 popl %ds /* and %ds is at the %cs */ 122 123#ifdef SERIAL 124 /* Initialize the serial port to 9600 baud, 8N1. 125 * Do we need to do this? Most things at this level 126 * do not know or care (on a PC) where the output is 127 * happening to go. I think if we are headless, 128 * /boot should figure (as it does now) that out. 129 * 130 * If there is a problem with this stage of the boot 131 * process, connect up a monitor and kbd, and see what 132 * is going on. Left here for the time being. 133 * 134 * --Toby. 135 */ 136 xorl %ax, %ax 137 movb $0xe3, %ax 138 data32 139 movl $SERIAL, %dx 140 int $0x14 141#endif 142 143 /* bootstrap passes us drive number in %dl 144 * 145 * XXX - This is not always true. We currently 146 * check if %dl points to a HD, and if not we 147 * complain, and set it to point to the first 148 * HDD. Note, this is not 100% correct, since 149 * there is a possibility that you boot of of 150 * HD #2, and still get (%dl & 0x80) == 0x00, 151 * these type of systems will loose. I don't 152 * know of any like this, but I've come to the 153 * conclusion, that if it can exist, it will, 154 * someplace in the PC world. If anyone knows 155 * how to fix this, speak up! 156 * 157 * Toby - Thu Jul 31 21:01:00 CDT 1997 158 */ 159 testb $0x80, %dl 160 jnz 1f 161 162 /* MBR on floppy or old BIOS 163 * Note: MBR (this code) should never 164 * be on a floppy. It does not belong 165 * there, so %dl should never be 0x00. 166 * 167 * Here we simply complain (should we?), 168 * and then hardcode the boot drive to 169 * 0x80. 170 */ 171 puts(fdmbr) 172 173 /* If we are passed bogus data, set it to HD #1. 174 * We should load the value from a hard coded 175 * location in this sector. Maybe I'll write 176 * that next, since my machines seem to be one 177 * of the weird ones... 178 */ 179 movb $0x80, %dl 180 181 /* Do we need to check our signature? The BIOS will 182 * check it for us, I doubt there is a need for us to 183 * do the same thing over again. If we fail here, 184 * something terrible is wrong. However, I doubt we 185 * can recover anyways. The message might be nice 186 * for the (l)user though. 187 */ 1881: xorl %bx, %bx 189 # cmpw $DOSMBR_SIGNATURE, (%bx) 190 .byte 0x81, 0xbf 191 .word signature 192 .word DOSMBR_SIGNATURE 193 je sigok 194 puts(esig) 195 196 /* find the first active partition 197 * Note: this should be the only active 198 * partition. We currently don't check 199 * for that, but we really should. If 200 * and when I feel up to it, I'll add 201 * that code. 202 */ 203sigok: 204 data32 205 movl $pt, %esi 206 data32 207 movl $NDOSPART, %ecx 2081: 209 DBGMSG(CHAR_L) 210 # movb (%si), %al 211 .byte 0x8a, 0x44, 0x00 212 cmpb $DOSACTIVE, %al 213 je found 214 data32 215 addl $PARTSZ, %esi 216 loop 1b 217 218 /* No bootable partition */ 219no_part: 220 puts(noboot) 221err_stop: 222 cli 223 hlt 224 /* Just to make sure */ 225 jmp err_stop 226 227 /* Found bootable partition */ 228found: 229 DBGMSG(CHAR_B) 230 pushl %ax 231 /* Save drive and partition */ 232 movl %dx, %ax 233 andl $0x0F, %ax 234 orl $0x30, %ax 235 #movb %al, adrive 236 .byte 0xA2 237 .word adrive 238 239 movl %cx, %ax 240 decl %ax 241 xor $0x03, %ax 242 andl $0x0F, %ax 243 orl $0x30, %ax 244 #movb %al, aprtn 245 .byte 0xA2 246 .word aprtn 247 248 popl %ax 249 250 /* Load values from active partition table entry */ 251 # movb 1(%si), %dh # head 252 .byte 0x8a, 0x74, 0x01 253 # movw 2(%si), %cx # sect, cyl 254 .byte 0x8b, 0x4c, 0x02 255 # movb 4(%si), %al # partition type 256 .byte 0x8a, 0x44, 0x04 257 258/* 259# BIOS call "INT 0x13 Function 0x2" to read sectors from disk into memory 260# Call with %ah = 0x2 261# %al = number of sectors 262# %ch = cylinder 263# %cl = sector 264# %dh = head 265# %dl = drive (0x80 for hard disk, 0x0 for floppy disk) 266# %es:%bx = segment:offset of buffer 267# Return: 268# %al = 0x0 on success; err code on failure 269*/ 270 data32 271 movl $0x200 | 1, %eax /* number of blocks */ 272 xorl %bx, %bx /* put it at %es:0 */ 273 int $0x13 274 jnc 1f 275 puts(eread) 276 jmp err_stop 277 2781: 279 DBGMSG(CHAR_G) 280 puts(info) 281 282 # jump to the new code (%ds:%si is at the right point) 283 data32 284 ljmp $0, $BOOTBIOS << 4 285 /* not reached */ 286 287/* 288 * Display string 289 */ 290Lmessage: 291 pushl %eax 292 cld 2931: 294 lodsb # load a byte into %al 295 testb %al, %al 296 jz 1f 297 /* call Lchr */ 298 .byte 0xe8 299 .word Lchr - . - 2 300 jmp 1b 301 302# 303# Lchr: write the error message in %ds:%si to console 304# 305Lchr: 306 pushl %eax 307 308#ifndef SERIAL 309 pushl %ebx 310 movb $0x0e, %ah 311 xorl %bx, %bx 312 incl %bx /* movw $0x01, %bx */ 313 int $0x10 314 popl %ebx 315#else 316 pushl %edx 317 movb $0x01, %ah 318 data32 319 movl SERIAL, %dx 320 int $0x14 321 popl %edx 322#endif 3231: popl %eax 324 ret 325 326/* Info messages */ 327info: .ascii "Using Drive: " 328adrive: .byte 'X' 329 .ascii " Partition: " 330aprtn: .byte 'Y' 331 .asciz "\r\n" 332 333/* Error messages */ 334fdmbr: .asciz "MBR on floppy or old BIOS\r\n" 335eread: .asciz "Read error\r\n" 336noboot: .asciz "No active partition\r\n" 337esig: .asciz "Invalid Signature\r\n" 338 339endofcode: 340 nop 341 342/* (MBR) NT registry offset */ 343 . = 0x1b8 344 .space 4, 0 345 346/* partition table */ 347/* flag, head, sec, cyl, type, ehead, esect, ecyl, start, len */ 348 . = DOSPARTOFF # starting address of partition table 349pt: 350 .byte 0x0,0,0,0,0,0,0,0 351 .long 0,0 352 .byte 0x0,0,0,0,0,0,0,0 353 .long 0,0 354 .byte 0x0,0,0,0,0,0,0,0 355 .long 0,0 356 .byte DOSACTIVE,0,1,0,DOSPTYP_OPENBSD,255,255,255 357 .long 0,0x7FFFFFFF 358/* the last 2 bytes in the sector 0 contain the signature */ 359 . = 0x1fe 360signature: 361 .short DOSMBR_SIGNATURE 362 . = 0x200 363 364