blob: 6103ae3f3698a86a824f0b3ee5f3b3b15f50c929 [file] [log] [blame]
; -*- fundamental -*- (asm-mode sucks)
; $Id$
; -----------------------------------------------------------------------
;
; NOT Copyright 2000 H. Peter Anvin
;
; This file is in the public domain. Enjoy. However, I would
; appreciate it if modified versions were marked as such, and
; please don't bug me about any version not released by me.
;
; -----------------------------------------------------------------------
;
; mbr.asm
;
; Simple Master Boot Record, including support for EBIOS extensions.
;
; The MBR lives in front of the boot sector, and is responsible for
; loading the boot sector of the active partition. The EBIOS support
; is needed if the active partition starts beyond cylinder 1024.
;
; This MBR determines all geometry info at runtime. It uses only the
; linear block field in the partition table. It does, however, pass
; the partition table information unchanged to the target OS.
;
; This MBR should be "8086-clean", i.e. not require a 386.
;
;
; Note: The MBR is actually loaded at 0:7C00h, but we quickly move it down to
; 0600h.
;
org 0600h
_start: cli
xor ax,ax
mov ds,ax
mov es,ax
mov ss,ax
mov sp,7C00h
sti
cld
mov si,sp ; Start address
mov di,0600h ; Destination address
mov cx,512/2
rep movsw
;
; Now, jump to the copy at 0600h so we can load the boot sector at 7C00h.
; Since some BIOSes seem to think 0000:7C00h and 07C0:0000h are the same
; thing, use a far jump to canonicalize the address.
;
jmp 0:next ; Jump to copy at 0600h
next:
mov [DriveNo], dl ; Drive number stored in DL
;
; Check for CHS parameters. This doesn't work on floppy disks,
; but for an MBR we don't care.
;
mov ah,08h ; Get drive parameters
int 13h
mov [Heads],dh
mov dh,cl
and dh,3Fh ; Max sector number
dec dh ; Sector count
mov [Sectors],dh
mov dx,cx
xchg dh,dl
mov cl,6
shr dh,cl
mov [Cylinders],dx
;
; Now look for one (and only one) active partition.
;
mov si,PartitionTable
xor ax,ax
mov cx,4
checkpartloop:
test byte [si],80h
jz .notactive
inc ax
mov di,si
.notactive: add si,byte 16
loop checkpartloop
cmp ax,byte 1 ; Better be only one
jnz not_one_partition
;
; Now we have the active partition partition information in DS:DI.
; Check to see if we support EBIOS.
;
mov dl,[DriveNo]
mov ax,4100h
mov bx,055AAh
xor cx,cx
xor dh,dh
stc
int 13h
jc no_ebios
cmp bx,0AA55h
jne no_ebios
test cl,1 ; LBA device access
jz no_ebios
;
; We have EBIOS. Load the boot sector using LBA.
;
push di
mov si,dapa
mov bx,[di+8] ; Copy the block address
mov [si+8],bx
mov bx,[di+10]
mov [si+10],bx
mov dl,[DriveNo]
mov ah,42h ; Extended Read
jmp short common_tail
;
; No EBIOS. Load the boot sector using CHS.
;
no_ebios:
push di
mov ax,[di+8]
mov dx,[di+10]
div word [Sectors]
inc dx
mov cx,dx ; Sector #
xor dx,dx
div word [Heads]
; DX = head #, AX = cylinder #
mov ch,al
shr ax,1
shr ax,1
and al,0C0h
or cl,al
mov dh,dl ; Head #
mov dl,[DriveNo]
mov bx,7C00h
mov ah,02h ; Read
common_tail:
int 13h
jc disk_error
pop di
;
; Verify that we have a boot sector, jump
;
test word [7C00h+510],0AA55h
jne missing_os
cli
jmp 7C00h ; Jump to boot sector
not_one_partition:
ja too_many_os
missing_os:
mov si,missing_os_msg
jmp short die
too_many_os:
disk_error:
mov si,bad_disk_msg
die:
.msgloop:
lodsb
xor al,al
jz .now
mov ah,0Eh ; TTY output
mov bx,0007h
int 10h
jmp short .msgloop
.now:
jmp short .now
align 4, db 0 ; Begin data area
;
; EBIOS disk address packet
;
dapa:
dw 16 ; Packet size
.count: dw 1 ; Block count
.off: dw 7C00h ; Offset of buffer
.seg: dw 0 ; Segment of buffer
.lba: dd 0 ; LBA (LSW)
dd 0 ; LBA (MSW)
; CHS information
Heads: dw 0
Sectors: dw 0
Cylinders: dw 0
; Error messages
missing_os_msg db 'Missing operating system', 13, 10, 0
bad_disk_msg db 'Operating system loading error', 13, 10, 0
;
; Maximum MBR size: 446 bytes; end-of-boot-sector signature also needed.
; Note that some operating systems (NT, DR-DOS) put additional stuff at
; the end of the MBR, so shorter is better.
;
PartitionTable equ $$+446 ; Start of partition table
;
; BSS data; put at 800h
;
DriveNo equ 0800h