1; -----------------------------------------------------------------------
2;
3;   Copyright 2003-2008 H. Peter Anvin - All Rights Reserved
4;
5;   Permission is hereby granted, free of charge, to any person
6;   obtaining a copy of this software and associated documentation
7;   files (the "Software"), to deal in the Software without
8;   restriction, including without limitation the rights to use,
9;   copy, modify, merge, publish, distribute, sublicense, and/or
10;   sell copies of the Software, and to permit persons to whom
11;   the Software is furnished to do so, subject to the following
12;   conditions:
13;
14;   The above copyright notice and this permission notice shall
15;   be included in all copies or substantial portions of the Software.
16;
17;   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18;   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
19;   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20;   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21;   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22;   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23;   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24;   OTHER DEALINGS IN THE SOFTWARE.
25;
26; -----------------------------------------------------------------------
27
28;
29; mbr.asm
30;
31; Simple Master Boot Record, including support for EBIOS extensions.
32;
33; The MBR lives in front of the boot sector, and is responsible for
34; loading the boot sector of the active partition.  The EBIOS support
35; is needed if the active partition starts beyond cylinder 1024.
36;
37; This MBR determines all geometry info at runtime.  It uses only the
38; linear block field in the partition table.  It does, however, pass
39; the partition table information unchanged to the target OS.
40;
41; This MBR should be "8086-clean", i.e. not require a 386.
42;
43
44%include "bios.inc"
45
46;
47; Note: The MBR is actually loaded at 0:7C00h, but we quickly move it down to
48; 0600h.
49;
50		section .text
51		cpu 8086
52		org 0600h
53
54_start:		cli
55		xor ax,ax
56		mov ds,ax
57		mov es,ax
58		mov ss,ax
59		mov sp,7C00h
60		sti
61		cld
62		mov si,sp		; Start address
63		mov di,0600h		; Destination address
64		mov cx,512/2
65		rep movsw
66
67;
68; Now, jump to the copy at 0600h so we can load the boot sector at 7C00h.
69; Since some BIOSes seem to think 0000:7C00h and 07C0:0000h are the same
70; thing, use a far jump to canonicalize the address.  This also makes
71; sure that it is a code speculation barrier.
72;
73
74		jmp 0:next		; Jump to copy at 0600h
75
76next:
77		mov [DriveNo], dl		; Drive number stored in DL
78;
79; Check for CHS parameters.  This doesn't work on floppy disks,
80; but for an MBR we don't care.
81;
82		mov ah,08h			; Get drive parameters
83		int 13h
84		and cx,3Fh			; Max sector number
85		mov [Sectors],cx
86		xor ax,ax
87		mov al,dh
88		inc ax				; From 0-based to count
89		mul cx				; Heads*Sectors
90		mov [SecPerCyl],ax
91		; Note: we actually don't care about the number of
92		; cylinders, since that's the highest-order division
93
94;
95; Now look for one (and only one) active partition.
96;
97		mov si,PartitionTable
98		xor ax,ax
99		mov cx,4
100checkpartloop:
101		test byte [si],80h
102		jz .notactive
103		inc ax
104		mov di,si
105.notactive:	add si,byte 16
106		loop checkpartloop
107
108		cmp ax,byte 1			; Better be only one
109		jnz not_one_partition
110
111;
112; Now we have the active partition partition information in DS:DI.
113; Check to see if we support EBIOS.
114;
115		mov dl,[DriveNo]
116		mov ax,4100h
117		mov bx,055AAh
118		xor cx,cx
119		xor dh,dh
120		stc
121		int 13h
122		jc no_ebios
123		cmp bx,0AA55h
124		jne no_ebios
125		test cl,1			; LBA device access
126		jz no_ebios
127;
128; We have EBIOS.  Load the boot sector using LBA.
129;
130		push di
131		mov si,dapa
132		mov bx,[di+8]			; Copy the block address
133		mov [si+8],bx
134		mov bx,[di+10]
135		mov [si+10],bx
136		mov dl,[DriveNo]
137		mov ah,42h			; Extended Read
138		jmp short common_tail
139;
140; No EBIOS.  Load the boot sector using CHS.
141;
142no_ebios:
143		push di
144		mov ax,[di+8]
145		mov dx,[di+10]
146		div word [SecPerCyl]	; AX = cylinder DX = sec in cyl
147		ror ah,1
148		ror ah,1
149		mov cl,ah
150		mov ch,al			; CL = cyl[9:8], CH = cyl[7:0]
151
152		mov ax,dx
153		div byte [Sectors]		; AL = head AH = sector
154		mov dh,al
155		inc ah
156		or cl,ah			; CX = cylinder and sector
157
158		mov dl,[DriveNo]
159		mov bx,7C00h
160		mov ax,0201h			; Read one sector
161common_tail:
162		int 13h
163		jc disk_error
164		pop si				; DS:SI -> partition table entry
165;
166; Verify that we have a boot sector, jump
167;
168		cmp word [7C00h+510],0AA55h
169		jne missing_os
170		cli
171		jmp 0:7C00h			; Jump to boot sector; far
172						; jump is speculation barrier
173						; (Probably not neecessary, but
174						; there is plenty of space.)
175
176not_one_partition:
177		ja too_many_os
178missing_os:
179		mov si,missing_os_msg
180		jmp short die
181too_many_os:
182disk_error:
183		mov si,bad_disk_msg
184die:
185.msgloop:
186		lodsb
187		and al,al
188		jz .now
189		mov ah,0Eh			; TTY output
190		mov bh,[BIOS_page]		; Current page
191		mov bl,07h
192		int 10h
193		jmp short .msgloop
194.now:
195		jmp short .now
196
197		align 4, db 0			; Begin data area
198
199;
200; EBIOS disk address packet
201;
202dapa:
203		dw 16				; Packet size
204.count:		dw 1				; Block count
205.off:		dw 7C00h			; Offset of buffer
206.seg:		dw 0				; Segment of buffer
207.lba:		dd 0				; LBA (LSW)
208		dd 0				; LBA (MSW)
209
210; CHS information
211SecPerCyl:	dw 0				; Heads*Sectors
212Sectors:	dw 0
213
214; Error messages
215missing_os_msg	db 'Missing operating system', 13, 10, 0
216bad_disk_msg	db 'Operating system loading error', 13, 10, 0
217
218;
219; Maximum MBR size: 446 bytes; end-of-boot-sector signature also needed.
220; Note that some operating systems (NT, DR-DOS) put additional stuff at
221; the end of the MBR, so shorter is better.  Location 440 is known to
222; have a 4-byte attempt-at-unique-ID for some OSes.
223;
224
225PartitionTable	equ $$+446			; Start of partition table
226
227;
228; BSS data; put at 800h
229;
230DriveNo		equ 0800h
231