     1                                  ; -*- fundamental -*- (asm-mode sucks)
     2                                  ; $Id: mbr.asm,v 1.6 2002/10/03 10:02:50 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                                  		cpu 8086
    34                                  
    35                                  		org 0600h
    36 00000000 FA                      _start:		cli
    37 00000001 31C0                    		xor ax,ax
    38 00000003 8ED8                    		mov ds,ax
    39 00000005 8EC0                    		mov es,ax
    40 00000007 8ED0                    		mov ss,ax
    41 00000009 BC007C                  		mov sp,7C00h
    42 0000000C FB                      		sti
    43 0000000D FC                      		cld
    44 0000000E 89E6                    		mov si,sp		; Start address
    45 00000010 BF0006                  		mov di,0600h		; Destination address
    46 00000013 B90001                  		mov cx,512/2
    47 00000016 F3A5                    		rep movsw
    48                                  
    49                                  ;
    50                                  ; Now, jump to the copy at 0600h so we can load the boot sector at 7C00h.
    51                                  ; Since some BIOSes seem to think 0000:7C00h and 07C0:0000h are the same
    52                                  ; thing, use a far jump to canonicalize the address.  This also makes
    53                                  ; sure that it is a code speculation barrier.
    54                                  ;
    55                                  
    56 00000018 EA[1D00]0000            		jmp 0:next		; Jump to copy at 0600h
    57                                  				
    58                                  next:
    59 0000001D 88160008                		mov [DriveNo], dl		; Drive number stored in DL
    60                                  ;
    61                                  ; Check for CHS parameters.  This doesn't work on floppy disks,
    62                                  ; but for an MBR we don't care.
    63                                  ;
    64 00000021 B408                    		mov ah,08h			; Get drive parameters
    65 00000023 CD13                    		int 13h
    66 00000025 31C0                    		xor ax,ax
    67 00000027 88F0                    		mov al,dh
    68 00000029 40                      		inc ax				; From 0-based to count
    69 0000002A A3[EC00]                		mov [Heads],ax
    70 0000002D 80E13F                  		and cl,3Fh			; Max sector number
    71 00000030 880E[EE00]              		mov [Sectors],cl
    72                                  		; Note: we actually don't care about the number of
    73                                  		; cylinders, since that's the highest-order division
    74                                  
    75                                  ;
    76                                  ; Now look for one (and only one) active partition.
    77                                  ;
    78 00000034 BE[BE01]                		mov si,PartitionTable
    79 00000037 31C0                    		xor ax,ax
    80 00000039 B90400                  		mov cx,4
    81                                  checkpartloop:
    82 0000003C F60480                  		test byte [si],80h
    83 0000003F 7403                    		jz .notactive
    84 00000041 40                      		inc ax
    85 00000042 89F7                    		mov di,si
    86 00000044 83C610                  .notactive:	add si,byte 16
    87 00000047 E2F3                    		loop checkpartloop
    88                                  
    89 00000049 83F801                  		cmp ax,byte 1			; Better be only one
    90 0000004C 7573                    		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 0000004E 8A160008                		mov dl,[DriveNo]
    97 00000052 B80041                  		mov ax,4100h
    98 00000055 BBAA55                  		mov bx,055AAh
    99 00000058 31C9                    		xor cx,cx
   100 0000005A 30F6                    		xor dh,dh
   101 0000005C F9                      		stc
   102 0000005D CD13                    		int 13h
   103 0000005F 7223                    		jc no_ebios
   104 00000061 81FB55AA                		cmp bx,0AA55h
   105 00000065 751D                    		jne no_ebios
   106 00000067 F6C101                  		test cl,1			; LBA device access
   107 0000006A 7418                    		jz no_ebios
   108                                  ;
   109                                  ; We have EBIOS.  Load the boot sector using LBA.
   110                                  ;
   111 0000006C 57                      		push di
   112 0000006D BE[DC00]                		mov si,dapa
   113 00000070 8B5D08                  		mov bx,[di+8]			; Copy the block address
   114 00000073 895C08                  		mov [si+8],bx
   115 00000076 8B5D0A                  		mov bx,[di+10]
   116 00000079 895C0A                  		mov [si+10],bx
   117 0000007C 8A160008                		mov dl,[DriveNo]
   118 00000080 B442                    		mov ah,42h			; Extended Read
   119 00000082 EB2A                    		jmp short common_tail
   120                                  ;
   121                                  ; No EBIOS.  Load the boot sector using CHS.
   122                                  ;
   123                                  no_ebios:
   124 00000084 57                      		push di
   125 00000085 8B4508                  		mov ax,[di+8]
   126 00000088 8B550A                  		mov dx,[di+10]
   127 0000008B F736[EE00]              		div word [Sectors]
   128 0000008F 42                      		inc dx
   129 00000090 89D1                    		mov cx,dx			; Sector #
   130 00000092 31D2                    		xor dx,dx
   131 00000094 F736[EC00]              		div word [Heads]
   132                                  		; DX = head #, AX = cylinder #
   133 00000098 88C5                    		mov ch,al
   134 0000009A D1E8                    		shr ax,1
   135 0000009C D1E8                    		shr ax,1
   136 0000009E 24C0                    		and al,0C0h
   137 000000A0 08C1                    		or cl,al
   138 000000A2 88D6                    		mov dh,dl			; Head #
   139 000000A4 8A160008                		mov dl,[DriveNo]
   140 000000A8 BB007C                  		mov bx,7C00h
   141 000000AB B80102                  		mov ax,0201h			; Read one sector
   142                                  common_tail:
   143 000000AE CD13                    		int 13h
   144 000000B0 7216                    		jc disk_error
   145 000000B2 5E                      		pop si				; DS:SI -> partition table entry
   146                                  ;
   147                                  ; Verify that we have a boot sector, jump
   148                                  ;
   149 000000B3 813EFE7D55AA            		cmp word [7C00h+510],0AA55h
   150 000000B9 7508                    		jne missing_os
   151 000000BB FA                      		cli
   152 000000BC EA007C0000              		jmp 0:7C00h			; Jump to boot sector; far
   153                                  						; jump is speculation barrier
   154                                  						; (Probably not neecessary, but
   155                                  						; there is plenty of space.)
   156                                  
   157                                  not_one_partition:
   158 000000C1 7705                    		ja too_many_os
   159                                  missing_os:
   160 000000C3 BE[F000]                		mov si,missing_os_msg
   161 000000C6 EB03                    		jmp short die
   162                                  too_many_os:
   163                                  disk_error:
   164 000000C8 BE[0B01]                		mov si,bad_disk_msg
   165                                  die:
   166                                  .msgloop:
   167 000000CB AC                      		lodsb
   168 000000CC 30C0                    		xor al,al
   169 000000CE 7409                    		jz .now
   170 000000D0 B40E                    		mov ah,0Eh			; TTY output
   171 000000D2 BB0700                  		mov bx,0007h
   172 000000D5 CD10                    		int 10h
   173 000000D7 EBF2                    		jmp short .msgloop
   174                                  .now:
   175 000000D9 EBFE                    		jmp short .now
   176                                  
   177 000000DB 00                      		align 4, db 0			; Begin data area
   178                                  
   179                                  ;
   180                                  ; EBIOS disk address packet
   181                                  ;
   182                                  dapa:
   183 000000DC 1000                    		dw 16				; Packet size
   184 000000DE 0100                    .count:		dw 1				; Block count
   185 000000E0 007C                    .off:		dw 7C00h			; Offset of buffer
   186 000000E2 0000                    .seg:		dw 0				; Segment of buffer
   187 000000E4 00000000                .lba:		dd 0				; LBA (LSW)
   188 000000E8 00000000                		dd 0				; LBA (MSW)
   189                                  
   190                                  ; CHS information
   191 000000EC 0000                    Heads:		dw 0
   192 000000EE 0000                    Sectors:	dw 0
   193                                  
   194                                  ; Error messages
   195 000000F0 4D697373696E67206F-     missing_os_msg	db 'Missing operating system', 13, 10, 0
   196 000000F9 7065726174696E6720-
   197 00000102 73797374656D0D0A00 
   198 0000010B 4F7065726174696E67-     bad_disk_msg	db 'Operating system loading error', 13, 10, 0
   199 00000114 2073797374656D206C-
   200 0000011D 6F6164696E67206572-
   201 00000126 726F720D0A00       
   202                                  
   203                                  ;
   204                                  ; Maximum MBR size: 446 bytes; end-of-boot-sector signature also needed.
   205                                  ; Note that some operating systems (NT, DR-DOS) put additional stuff at
   206                                  ; the end of the MBR, so shorter is better.
   207                                  ;
   208                                  
   209                                  PartitionTable	equ $$+446			; Start of partition table
   210                                  
   211                                  ;
   212                                  ; BSS data; put at 800h
   213                                  ;
   214                                  DriveNo		equ 0800h
