1 ; -*- fundamental -*- (asm-mode sucks) 2 ; $Id: mbr.asm,v 1.4 2000/07/06 07:33:29 hpa Exp $ 3 ; ----------------------------------------------------------------------- 4 ; 5 ; NOT Copyright 2000 H. Peter Anvin 6 ; 7 ; This file is in the public domain. Enjoy. However, I would 8 ; appreciate it if modified versions were marked as such, and 9 ; please don't bug me about any version not released by me. 10 ; 11 ; ----------------------------------------------------------------------- 12 13 ; 14 ; mbr.asm 15 ; 16 ; Simple Master Boot Record, including support for EBIOS extensions. 17 ; 18 ; The MBR lives in front of the boot sector, and is responsible for 19 ; loading the boot sector of the active partition. The EBIOS support 20 ; is needed if the active partition starts beyond cylinder 1024. 21 ; 22 ; This MBR determines all geometry info at runtime. It uses only the 23 ; linear block field in the partition table. It does, however, pass 24 ; the partition table information unchanged to the target OS. 25 ; 26 ; This MBR should be "8086-clean", i.e. not require a 386. 27 ; 28 29 ; 30 ; Note: The MBR is actually loaded at 0:7C00h, but we quickly move it down to 31 ; 0600h. 32 ; 33 34 org 0600h 35 00000000 FA _start: cli 36 00000001 31C0 xor ax,ax 37 00000003 8ED8 mov ds,ax 38 00000005 8EC0 mov es,ax 39 00000007 8ED0 mov ss,ax 40 00000009 BC007C mov sp,7C00h 41 0000000C FB sti 42 0000000D FC cld 43 0000000E 89E6 mov si,sp ; Start address 44 00000010 BF0006 mov di,0600h ; Destination address 45 00000013 B90001 mov cx,512/2 46 00000016 F3A5 rep movsw 47 48 ; 49 ; Now, jump to the copy at 0600h so we can load the boot sector at 7C00h. 50 ; Since some BIOSes seem to think 0000:7C00h and 07C0:0000h are the same 51 ; thing, use a far jump to canonicalize the address. 52 ; 53 54 00000018 EA[1D00]0000 jmp 0:next ; Jump to copy at 0600h 55 56 next: 57 0000001D 88160008 mov [DriveNo], dl ; Drive number stored in DL 58 ; 59 ; Check for CHS parameters. This doesn't work on floppy disks, 60 ; but for an MBR we don't care. 61 ; 62 00000021 B408 mov ah,08h ; Get drive parameters 63 00000023 CD13 int 13h 64 00000025 8836[F400] mov [Heads],dh 65 00000029 88CE mov dh,cl 66 0000002B 80E63F and dh,3Fh ; Max sector number 67 0000002E FECE dec dh ; Sector count 68 00000030 8836[F600] mov [Sectors],dh 69 00000034 89CA mov dx,cx 70 00000036 86F2 xchg dh,dl 71 00000038 B106 mov cl,6 72 0000003A D2EE shr dh,cl 73 0000003C 8916[F800] mov [Cylinders],dx 74 75 ; 76 ; Now look for one (and only one) active partition. 77 ; 78 00000040 BE[BE01] mov si,PartitionTable 79 00000043 31C0 xor ax,ax 80 00000045 B90400 mov cx,4 81 checkpartloop: 82 00000048 F60480 test byte [si],80h 83 0000004B 7403 jz .notactive 84 0000004D 40 inc ax 85 0000004E 89F7 mov di,si 86 00000050 83C610 .notactive: add si,byte 16 87 00000053 E2F3 loop checkpartloop 88 89 00000055 83F801 cmp ax,byte 1 ; Better be only one 90 00000058 7570 jnz not_one_partition 91 92 ; 93 ; Now we have the active partition partition information in DS:DI. 94 ; Check to see if we support EBIOS. 95 ; 96 0000005A 8A160008 mov dl,[DriveNo] 97 0000005E B80041 mov ax,4100h 98 00000061 BBAA55 mov bx,055AAh 99 00000064 31C9 xor cx,cx 100 00000066 30F6 xor dh,dh 101 00000068 F9 stc 102 00000069 CD13 int 13h 103 0000006B 7223 jc no_ebios 104 0000006D 81FB55AA cmp bx,0AA55h 105 00000071 751D jne no_ebios 106 00000073 F6C101 test cl,1 ; LBA device access 107 00000076 7418 jz no_ebios 108 ; 109 ; We have EBIOS. Load the boot sector using LBA. 110 ; 111 00000078 57 push di 112 00000079 BE[E400] mov si,dapa 113 0000007C 8B5D08 mov bx,[di+8] ; Copy the block address 114 0000007F 895C08 mov [si+8],bx 115 00000082 8B5D0A mov bx,[di+10] 116 00000085 895C0A mov [si+10],bx 117 00000088 8A160008 mov dl,[DriveNo] 118 0000008C B442 mov ah,42h ; Extended Read 119 0000008E EB29 jmp short common_tail 120 ; 121 ; No EBIOS. Load the boot sector using CHS. 122 ; 123 no_ebios: 124 00000090 57 push di 125 00000091 8B4508 mov ax,[di+8] 126 00000094 8B550A mov dx,[di+10] 127 00000097 F736[F600] div word [Sectors] 128 0000009B 42 inc dx 129 0000009C 89D1 mov cx,dx ; Sector # 130 0000009E 31D2 xor dx,dx 131 000000A0 F736[F400] div word [Heads] 132 ; DX = head #, AX = cylinder # 133 000000A4 88C5 mov ch,al 134 000000A6 D1E8 shr ax,1 135 000000A8 D1E8 shr ax,1 136 000000AA 24C0 and al,0C0h 137 000000AC 08C1 or cl,al 138 000000AE 88D6 mov dh,dl ; Head # 139 000000B0 8A160008 mov dl,[DriveNo] 140 000000B4 BB007C mov bx,7C00h 141 000000B7 B402 mov ah,02h ; Read 142 common_tail: 143 000000B9 CD13 int 13h 144 000000BB 7214 jc disk_error 145 000000BD 5F pop di 146 ; 147 ; Verify that we have a boot sector, jump 148 ; 149 000000BE F706FE7D55AA test word [7C00h+510],0AA55h 150 000000C4 7506 jne missing_os 151 000000C6 FA cli 152 000000C7 E9(007C) jmp 7C00h ; Jump to boot sector 153 154 not_one_partition: 155 000000CA 7705 ja too_many_os 156 missing_os: 157 000000CC BE[FA00] mov si,missing_os_msg 158 000000CF EB03 jmp short die 159 too_many_os: 160 disk_error: 161 000000D1 BE[1501] mov si,bad_disk_msg 162 die: 163 .msgloop: 164 000000D4 AC lodsb 165 000000D5 30C0 xor al,al 166 000000D7 7409 jz .now 167 000000D9 B40E mov ah,0Eh ; TTY output 168 000000DB BB0700 mov bx,0007h 169 000000DE CD10 int 10h 170 000000E0 EBF2 jmp short .msgloop 171 .now: 172 000000E2 EBFE jmp short .now 173 174 align 4, db 0 ; Begin data area 175 176 ; 177 ; EBIOS disk address packet 178 ; 179 dapa: 180 000000E4 1000 dw 16 ; Packet size 181 000000E6 0100 .count: dw 1 ; Block count 182 000000E8 007C .off: dw 7C00h ; Offset of buffer 183 000000EA 0000 .seg: dw 0 ; Segment of buffer 184 000000EC 00000000 .lba: dd 0 ; LBA (LSW) 185 000000F0 00000000 dd 0 ; LBA (MSW) 186 187 ; CHS information 188 000000F4 0000 Heads: dw 0 189 000000F6 0000 Sectors: dw 0 190 000000F8 0000 Cylinders: dw 0 191 192 ; Error messages 193 000000FA 4D697373696E67206F- missing_os_msg db 'Missing operating system', 13, 10, 0 194 00000103 7065726174696E6720- 195 0000010C 73797374656D0D0A00 196 00000115 4F7065726174696E67- bad_disk_msg db 'Operating system loading error', 13, 10, 0 197 0000011E 2073797374656D206C- 198 00000127 6F6164696E67206572- 199 00000130 726F720D0A00 200 201 ; 202 ; Maximum MBR size: 446 bytes; end-of-boot-sector signature also needed. 203 ; Note that some operating systems (NT, DR-DOS) put additional stuff at 204 ; the end of the MBR, so shorter is better. 205 ; 206 207 PartitionTable equ $$+446 ; Start of partition table 208 209 ; 210 ; BSS data; put at 800h 211 ; 212 DriveNo equ 0800h