An Examination of the Standard MBR
( Master Boot Record )
[ Embedded in Microsoft's FDISK Programs
from MS-DOS 3.30 through MS-Windows™ 95 (A)
]

Web Presentation and Text are Copyright©2012 by Daniel B. Sedory
NOT to be reproduced in any form without Permission of the Author !

This page examines the Standard MBR code which had been used in Microsoft's FDISK utility since MS-DOS 3.30 (as a matter of fact only a small portion of its code was changed since it was first created for IBM DOS version 2.00 at the beginning of 1983. So we've got a very good reason for using the phrase Standard MBR when discussing this code!).

This MBR is also the same as the Standard IPL (Initial Program Loader) code for the Ranish Partition Manager and the "write new MBR code" function in many other utilities (TestDisk used this MBR code until version 5.7, in 2005, when we decided to use only free Open Source GNU GPL code, replacing the "standard MBR i386 boot sector code" by mbr-1.1.8). However, since the introduction of the FAT32 File System (in Win 95B), the code created by FDISK is more complex than what you'll find here. Note: the MBR code presented here is also OS-independent (you can use it to boot any OS on a PC * ).


Other Microsoft MBR pages:
  The MBR created by Windows 95B/98/98SE and ME's FDISK
  The MBR created by Windows 2000/XP/2003 Installs or Disk Management Utility
  The MBR created by Windows Vista OS Installs or Disk Management Utility
  The MBR created by Windows 7 Installs or Disk Management Utility

And Microsoft OS Volume Boot Records:
  An Examination of the Windows 95B/98/98SE/Me OS Boot Record (MSWIN4.1)
  An Examination of the Windows 2000/XP OS Boot Record (NTFS)
  An Examination of the Windows Vista OS Volume Boot Record (NTFS)
  An Examination of the Windows 7 OS Volume Boot Record

Confused? Send me an email if you have a specific question about the MBR or any Boot Records...

IMPORTANT: One of the first things that any PC user should do after setting up a new hard disk (or creating a new partition with a utility such as Partition Magic) is to make a copy of its MBR; especially if you have more than one partition on the disk! Why? If you accidentally overwrite this sector, or are infected by a Boot sector virus, you may never be able to access some or even all of your disk again!   Even the most expensive HD utility might not correctly restore the Partition Table of a multi-partitioned hard disk!
Some advice: Save the Partition Table data on floppy disks or even on paper(!); it does no good to have the data you need to access your HD on the un-accessible HD itself! There are many ways you can do this... See the MBR Tools Page. Any good Disk Editor will allow you to manually enter data you've written down under an easy to use Partition Table View, or you can use Power Quest's excellent little utility program "MBRutil" (under any version of Windows!) and "MBRUTILD" (under DOS) to save the binary data to a file on a floppy diskette and later restore the MBR from the saved file.

____________
* NOTE: Even though we're examining the code created by Microsoft's FDISK utility, this MBR is OS-independent. Its code can be used to start the bootup process for any operating system's Boot Record on an x86-CPU based (PC) computer as long as that OS is: 1) on the Primary Master hard drive, 2) set to be the only Active partition, 3) it's Boot Sector is located at or under cylinder 1024 of the hard drive (since this MBR uses the standard INT 13 Read Function which is limited to that value) and 4) it has a boot loader in the first sector of that partition. For the Linux OS you can install LILO as a Boot Record rather than in the MBR and following sectors, but for systems with multiple OSs this isn't very practical.

There have been many MBRs or IPLs (Initial Program Loaders) created for booting an OS and even for booting multiple OSs. See Multi-OS Booting on our "Tools and References" Page for some alternative code and Boot Managers (Windows NT/2000/XP can also boot multiple OSs using its boot.ini and NTLDR files).
 



 Absolute Sector 0 (Cylinder 0, Head 0, Sector 1)

        0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
 0000  FA 33 C0 8E D0 BC 00 7C 8B F4 50 07 50 1F FB FC  .3.....|..P.P... 
 0010  BF 00 06 B9 00 01 F2 A5 EA 1D 06 00 00 BE BE 07  ................ 
 0020  B3 04 80 3C 80 74 0E 80 3C 00 75 1C 83 C6 10 FE  ...<.t..<.u..... 
 0030  CB 75 EF CD 18 8B 14 8B 4C 02 8B EE 83 C6 10 FE  .u......L....... 
 0040  CB 74 1A 80 3C 00 74 F4 BE 8B 06 AC 3C 00 74 0B  .t..<.t.....<.t.
 0050  56 BB 07 00 B4 0E CD 10 5E EB F0 EB FE BF 05 00  V.......^.......
 0060  BB 00 7C B8 01 02 57 CD 13 5F 73 0C 33 C0 CD 13  ..|...W.._s.3...
 0070  4F 75 ED BE A3 06 EB D3 BE C2 06 BF FE 7D 81 3D  Ou...........}.=
 0080  55 AA 75 C7 8B F5 EA 00 7C 00 00 49 6E 76 61 6C  U.u.....|..Inval
 0090  69 64 20 70 61 72 74 69 74 69 6F 6E 20 74 61 62  id partition tab
 00A0  6C 65 00 45 72 72 6F 72 20 6C 6F 61 64 69 6E 67  le.Error loading
 00B0  20 6F 70 65 72 61 74 69 6E 67 20 73 79 73 74 65   operating syste
 00C0  6D 00 4D 69 73 73 69 6E 67 20 6F 70 65 72 61 74  m.Missing operat
 00D0  69 6E 67 20 73 79 73 74 65 6D 00 00 00 00 00 00  ing system......
 00E0  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
 00F0  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
 0100  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
 0110  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
 0120  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
 0130  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
 0140  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
 0150  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
 0160  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
 0170  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
 0180  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
 0190  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
 01A0  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
 01B0  00 00 00 00 00 00 00 00 00 00 00 00 00 00 80 01  ................
 01C0  01 00 0B 7F BF FD 3F 00 00 00 C1 40 5E 00 00 00  ......?....@^... 
 01D0  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................ 
 01E0  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................ 
 01F0  00 00 00 00 00 00 00 00 00 00 00 00 00 00 55 AA  ..............U. 
        0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F


An Examination of the Assembly Code


7C00 FA            CLI                  ; Disable maskable Interrupts
7C01 33C0          XOR	AX,AX           ; Zero out both the Accumulator and
7C03 8ED0          MOV	SS,AX           ;    the Stack Segment register.
7C05 BC007C        MOV	SP,7C00	        ; Set Stack Pointer to 0000:7C00
7C08 8BF4          MOV	SI,SP           ; Source Index: Copy from here...
7C0A 50            PUSH	AX
7C0B 07            POP	ES              ; Zero-out Extra Segment
7C0C 50            PUSH	AX
7C0D 1F            POP	DS              ; Zero-out  Data Segment
7C0E FB            STI                  ; Enable Interrupts again

7C0F FC            CLD                  ; Clear Direction Flag (df=0).
7C10 BF0006        MOV	DI,0600         ; Destination Index: New copy of
                                        ;  code will begin at 0000:0600
7C13 B90001        MOV	CX,0100         ; Copy 256 Words (512 bytes)
                                        ;    (100 hex = 256 decimal)
7C16 F2 (*)        REP (*)              ; REPeat the following MOVSW
                                        ; instruction for 'CX' times(*).
7C17 A5            MOVSW                ;  Copy two bytes at a time.

7C18 EA1D060000    JMP	0000:061D       ; Jump to new copy of code...


; Since the preceding routine copies itself and all of the following
; code to 0000:0600 and then jumps to 0000:061D before continuing to
; run, the following addresses have been changed to reflect the
; code's actual location in memory at the time of execution.


; This next bit of code tries to find an entry in the partition table
; that indicates at least one of them is ACTIVE (i.e., bootable). The
; first byte of a partition entry is used as the indicator: If it's
; an 80h, yes; if 00 then no it's not bootable. If none of the four
; possible partitions is active, then an error message is displayed.

061D BEBE07        MOV	SI,07BE           ; Location of first entry
                                          ; in the partition table
                                          ; (see Sample Table below).
0620 B304          MOV	BL,04             ; Maximum of 4 Table Entries.
0622 803C80        CMP	BYTE PTR [SI],80  ; Is this one bootable (80h)?
0625 740E          JE	0635              ; Yes, so jump to next test!
0627 803C00        CMP	BYTE PTR [SI],00  ;  No; is it a 00? If not, it's
062A 751C          JNE	0648              ;   an Invalid partition table.
062C 83C610        ADD	SI,+10            ; Check next entry for 80h ...
                                          ; (10h = 16 bytes per entry)
062F FECB          DEC	BL                ; Subtract 1 from Entry Counter.
0631 75EF          JNZ	0622              ; Have all entries been tested?
0633 CD18          INT  18                ; Yes, and NONE of them were
                                          ;    bootable, so start...
                                          ; ROM-BASIC (only available on
                                          ; some IBM machines!) Many BIOS
                                          ; simply display "PRESS A
                                          ; KEY TO REBOOT" when an
                                          ; Interrupt 18h is executed.


; We found an Active partition, so all the other entries are checked
; for being non-bootable (first byte = 0x00), or there's an error!
; (Only one entry in the Partition Table can be marked as 'Active.')

; Before doing so, we load the Head, Drive, Cylinder and Sector data
; into DX and CX for use by the DOS Interrupt 13 commands later.

0635 8B14          MOV	DX,[SI]           ; Drive  -> DL /   Head -> DH
                                          ; For the standard MBR code,
          ; DL will always be 80h; which means ONLY the first drive can
          ; be bootable! [ This part of the code is often changed by MBR
          ; replacements to boot from another (second, etc.) drive! ]

0637 8B4C02        MOV	CX,[SI+02]        ; Sector -> CL / Cylinder -> CH

063A 8BEE          MOV	BP,SI             ; Save offset of Active Entry
                                          ;  pass to Volume Boot Sector.
063C 83C610        ADD	SI,+10            ; Do next Table Entry
063F FECB          DEC	BL                ; Is this the last entry?
0641 741A          JZ	065D              ; All Entries look OK, so...
                                          ; -> Jump to Boot-routine!
0643 803C00        CMP	BYTE PTR [SI],00  ; Non-bootable entry (00h)?
0646 74F4          JE	063C              ; Yes, so check next entry.


; If there was an error, then this next routine displays the message that
; SI points to.  After printing the ASCII-Z string (null terminated), the
; program 'locks up' by going into an infinite loop (at 065B):

0648 BE8B06        MOV	SI,068B       ; -> "Invalid partition table"

064B AC            LODSB              ; Load byte at [SI] into AL ...
                                      ;   and increment the SI value.
064C 3C00          CMP	AL,00         ; Is it a zero-byte yet ?
064E 740B          JE	065B          ; If yes, were done.  If not ...
0650 56            PUSH	SI            ;  Store string pointer on stack.
0651 BB0700        MOV	BX,0007       ; Use Function 0E (Write Text) of
0654 B40E          MOV	AH,0E         ;  DOS Interrupt 10 to send the
0656 CD10          INT	10            ;  character in AL to the screen.
0658 5E            POP	SI
0659 EBF0          JMP	064B

065B EBFE          JMP  065B          ; Infinite Loop.  You must
                                      ;    power-down or Reboot!


; Now we can load the first sector of the Active Partition (on most drives,
; this would be Absolute Sector 63 for the first or only partition of your
; Hard Drive. Absolute Sectors 2 thru 62 are normally empty, unless you've
; installed a large MBR replacement, disk translation software for a very
; large HD or some kind of multi-OS or security/encryption boot code).
;
; The first two words of the partition entry are the drive/head
; and the sector/cylinder numbers of the first partition sector.
; This data is in the format required by the INT 13 call below.

065D BF0500        MOV	DI,0005       ; Retry 5 times (if necessary)...
0660 BB007C        MOV	BX,7C00       ; Load OS Boot Sector to 0000:7C00
0663 B80102        MOV	AX,0201       ; Function 02h. Read 1 sector.
0666 57            PUSH	DI
0667 CD13          INT  13            ;   Note: This old INT 13 Read
                                      ; is limited to 1024 cylinders.
0669 5F            POP	DI
066A 730C          JNC	0678          ; Carry Flag set? If no, jump!
066C 33C0          XOR	AX,AX         ; Yes, so we had an error! Must
066E CD13          INT  13            ; ...reset drive (Function 00h)
0670 4F            DEC	DI            ; Decrement counter (if > 0)
0671 75ED          JNZ	0660          ;   and try again...

0673 BEA306        MOV	SI,06A3       ; Or, declare: "Error loading
0676 EBD3          JMP	064B          ; operating system" and hang!

; The section of code above is often changed by MBR replacements that will
; tell you if it ever takes more than ONCE to try loading the OS Boot code!
; Surely you'd want to know this wouldn't you?!
;    This old code was obviously made in the days when hard drives, memory
; chips and the boot process itself may have been quite unreliable.


; Once a boot sector for the Active Partition has been loaded into memory,
; it must be checked to see if it is valid. This is accomplished by simply
; checking the last word of the sector; it must be the hex number 0xAA55.

0678 BEC206        MOV	SI,06C2         ; -> "Missing operating system"
                                        ; Set up SI, in case we have an
                                        ; error in the Boot Sector read.
067B BFFE7D        MOV	DI,7DFE         ; Point to the last Word of Boot
                                        ; Sector. It should be AA55 Hex.

067E 813D55AA      CMP	WORD PTR [DI],AA55 ; Is it? ('Signature' Check.)
0682 75C7          JNE	064B               ; If not, display Error Message
                                           ;         and 'lock-up' system.

0684 8BF5          MOV	SI,BP	        ;   SI=BP ->  Both are equal to...
                                        ; offset of Active Partition Entry
                                        ; which is used by OS Boot code.
0686 EA007C0000    JMP	0000:7C00       ;   Jump to OS Boot Sector code
                                        ;       and continue booting-up!

Location of Error Messages in Memory


068B                                   49 6E 76 61 6C              Inval
0690  69 64 20 70 61 72 74 69-74 69 6F 6E 20 74 61 62   id partition tab
06A0  6C 65 00 45 72 72 6F 72-20 6C 6F 61 64 69 6E 67   le.Error loading
06B0  20 6F 70 65 72 61 74 69-6E 67 20 73 79 73 74 65    operating syste
06C0  6D 00 4D 69 73 73 69 6E-67 20 6F 70 65 72 61 74   m.Missing operat
06D0  69 6E 67 20 73 79 73 74-65 6D 00                  ing system.


A Sample Partition Table

This shows a sample partition table and where it would appear in memory during the boot-up process. See the References Page for links to complete listings of Partition Identifiers. For a detailed explanation of how to interpret the data in the table, see the file PTGUIDE.TXT in my Mbrdemo.zip download below. This Sample Table contains entries for all four records; each record is 16 bytes long. I've underlined all the bytes in the first (7BEh through 7CDh) and last (7EEh through 7FDh) of the 4 records here:

07BE                                            80 01                 ..
07C0  01 00 06 3F 3F C4 3F 00-00 00 81 1E 0C 00 00 00   ...??.?.........
07D0  01 C5 05 3F 7F 47 C0 1E-0C 00 40 0F 08 00 00 00   ...?.G....@.....
07E0  41 48 82 3F 7F 53 00 2E-14 00 00 BD 00 00 00 00   AH.?.S..........
07F0  41 54 83 3F BF 0F 00 EB-14 00 00 91 0B 00 55 AA   AT.?..........U.

And this is how it would be seen in a disk editor that can interpret Partition Table data:

  Partition    Active  Starting Loc   Ending Loc   Relative  Number of
    Type        Boot   Cyl Head Sec  Cyl Head Sec   sectors    sectors
-------------  ------  ------------  ------------   -------    -------
DOS FAT-16      Yes      0   1   1   196  63  63         63     794241
Extended        No     197   0   1   327  63  63     794304     528192
LINUX Swap      No     328   0   1   339  63  63    1322496      48384
LINUX Ext2FS    No     340   0   1   527  63  63    1370880     758016

During boot-up, these locations are later replaced by communications parameters for COM2 thru COM4 and other data. Here's a listing of my own computer's memory after boot-up for these same memory locations:

07BE                                            7A 02                 z.
07C0  AC 02 43 4F 4D 32 20 20 20 20 DC 00 70 00 00 80   ..COM2    ..p..€
07D0  7A 02 B2 02 43 4F 4D 33 20 20 20 20 00 00 0D 0E   z...COM3    ....
07E0  00 80 7A 02 B8 02 43 4F 4D 34 20 20 20 20 E8 D2   .€z...COM4    ..
07F0  01 D7 07 38 CD 01 3B 0E 00 00 7C 04 18 00 59 04   ......;...|...Y.



* NOTE: On Microsoft's Use of the x86 Machine Code Instruction F2

Technically, Intel's F2 machine code byte will be disassembled as either REPNZ (by MS-DEBUG's U command) or REPNE (most other debuggers). I've used the simple REP mnemonic in my disassembly of the code above, because that's its real function here! Even though Intel CPUs end up performing a simple repetition of any MOVSW (or similar class of) instruction following an F2 byte (for as many times as the value found in the CX register), an ideal Assembly program should never use an F2 byte in such cases. Why? Well, apart from the fact that all respectable x86 assemblers encode a simple REP instruction only as an F3 machine code byte, it confuses a lot of beginners trying to figure out how the repetition can continue when the Zero flag bit is often NZ (not zero) the whole time! The reason is because the CPU does not check the flag bits while repeating Move String, Byte or Word (MOVSB/MOVSW) instructions! It only checks the Direction Flag (df) to see if the Source (SI) and Destination (DI) registers should be incremented when df=0 ('cleared') or decremented when df=1 ('set') for the number in the CX (Count) register. Since it was preceded by the CLD instruction at 7C0F, it will be incrementing the locations. The mnemonics REPE, REPZ, REPNE and REPNZ are supposed to apply only to the Compare (CMPSB/CMPSW) and Scan (SCASB/SCASW) String functions. Furthermore, since Intel has simply stated that:

"The REP prefix can be added to the INS, OUTS, MOVS, LODS, and STOS instructions, and the REPE, REPNE, REPZ, and REPNZ prefixes can be added to the CMPS and SCAS instructions. (The REPZ and REPNZ prefixes are synonymous forms of the REPE and REPNE prefixes, respectively.)" [Intel Architecture Software Developer’s Manual, Volume 2: Instruction Set Reference (©1997), page 3-404.]
It seems to us that Microsoft's use of the F2 machine code byte with MOVSW should be considered UNDOCUMENTED at best. Note that Microsoft's code in both their newer FAT32 MBR and the original MBR created for DOS 2.00 (until DOS 3.30) all use an F3 byte (rather than F2) for the only "Move String" instruction (MOVSB) found in them. [Note: Microsoft has never used the F2 byte in their MBR code after Windows 95(A). It appears only in MBR sectors created by the MS-DOS 3.30 and later FDISK programs, or any utilities based upon that code.]

Back to the Code above

MBR Demonstration Program
(if you want to investigate all the details)


Download the following .ZIP file which contains MBR_DEMO.BIN (You can rename it: MBR_DEMO.COM if you wish; it's safe to execute "as is" in a DOS-Window [ under Win9x that is; do  NOT use this program under Windows NT, 2000 or XP -- these OSs don't allow direct access to your hard drive and will not allow MBR_DEMO to run to completion! ]

But the only way to actually see how an MBR functions using this Demo is by stepping through the code with a debugger; you will be shown how to use MS-DEBUG to do that.) Various text files explaining the operation of the Master Boot Record are also included in: MBRDEMO.ZIP (28 kb; 24 JUN 2003).
Read MBR_DEMO.TXT in MBRDEMO.ZIP for all the details.

Better still, learn how to use the Bochs Debugger to step through this code while it's actually attempting to boot up an OS under the free Bochs Emulator.



First Published: 2000
Updated: August 17, 2004 (17.08.2004); May 19, 2012 (19.05.2012); May 12, 2013 (12.05.2013).
Last Update: May 26, 2013. (26.05.2013)


You can write to me using this: online reply form. (It opens in a new window.)

The Starman's FREE TOOLS Page

MBR and Boot Records Index

The Starman's Realm Index Page