Sponsoring website: Emergency Boot CD

# An Examination of the
Windows™ 7 (and Vista)
VBR ( Volume Boot Record )
or Boot Sector (and Beyond)

[ Embedded in untfs.dll,
winsetup.dll and various other
System files; see Introduction ]
Web Presentation and Text are Copyright©2012, 2015 by Daniel B. Sedory
NOT to be reproduced in any form without Permission of the Author !

This page examines the Windows™ 7 OS's Volume Boot Record (VBR); which is considered to be only the first sector of the system area at the beginning of a Win 7 OS volume (thus, its alternate name: Boot Sector). The BOOTMGR Loader code, immediately following the VBR Sector, spans across the boundaries of eight more sectors: Seven full 512-byte sectors, plus 40 bytes at the beginning of the eighth sector. This structure is similar to the layout of the Windows XP VBR and its NTLDR Loader code. [Note: If you compare the Windows 7 BOOTMGR Loader code to the Vista BOOTMGR Loader (both of which have the same total number of bytes), there are 19 bytes different in the executable code. But, after examining all the differences, we found they were only in the offsets of jump instructions, which had to be adjusted due to the fact the Windows 7 Boot Sector had added 12 new bytes to its code, forcing many of the jump instructions in the BOOTMGR Loader to also change. Therefore, the source code instructions for both the Windows Vista and Windows 7 BOOTMGR Loaders are still identical.]

- Introduction

- Summary of Code and Data Sections within the VBR
- A View of the Windows 7 VBR Sector in a Disk Editor
- Message Offset Bytes (for Error Messages)
- An Examination of the Windows 7 VBR Sector Assembly Code

Other 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 8 / 8.1 OS Volume Boot Record (NTFS)
A Comparison of Windows™ Vista, 7 and 8 VBR Code
And Microsoft MBR pages:
An Examination of the Standard MBR created by MS-DOS FDISK
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 / 8 OS's Installs or Disk Management
Confused? Send us an email if you have a specific question about the MBR or any Boot Records...

Just as we urged readers of our Win 7 MBR page to make a copy of their MBR sector, you may wish to create copies of your Win 7 VBR. Though more difficult to work with; considering all the details stored in this sector, there may come a time when you need/want to edit or replace this and other system sectors manually. Some advice: Save all the data from the BIOS Parameter Block (BPB) area of the sector somewhere apart from your main hard disk or write it down on paper(!); it does no good to have data you might need to access your OS on the un-accessible HD itself! There are many ways you can do this... See our MBR Tools Page. Any good Disk Editor will allow you to manually enter data you've written down, or you can use a number of utility programs to save the binary data to a file on say a thumb drive, and later on restore the VBR and other sectors from the saved file(s).

# Introduction

This page examines the Windows™ 7 OS Volume Boot Record code; the code which actually tests and begins to load a Windows™ 7 operating system from within the OS volume.

For our Windows™ 7 install, all the code bytes of Win7's Volume Boot Record sector were also found inside the following files (listed by location, alphabetically; with offset to first byte of the code). In each case, there will be a full 512 bytes that comprise the VBR sector, but locations for the Volume Serial Number and other vital data in the BPB area are all zero-filled in these 'template' files; the correct data being entered when the file is copied to disk by the installation program or operating system. The last two bytes will always be a 55h followed by an AAh:
(Note: For each of the files in this list, there are also copies of them in various folders under the C:\Windows\winsxs\ folder.)

1. C:\Windows\System32\autochk.exe [Offset: 80530h]; immediately followed by all 3,624 bytes of the BOOTMGR Loader code (beginning at offset 80730h and continuing through 81557h) plus the next 4,056 bytes (all zeros) for a total of 8,192 bytes (16 sectors).
("Auto Check Utility"; File version: "6.1.7601.17514 (win7sp1_rtm.101119-1850)"; 777,728 bytes; Modification Date: "11/20/2010 5:24 AM").
2. C:\Windows\SysWOW64\autochk.exe [Offset: 66D58h]; immediately followed by all 3,624 bytes of the BOOTMGR Loader code (beginning at offset 66F58h and continuing through 67D7Fh); again followed by 4,056 zero bytes ending at offset 68D57h; 16 sectors total.
("Auto Check Utility"; File version: "6.1.7601.17514 (win7sp1_rtm.101119-1850)"; 668,160 bytes; Modification Date: "11/20/2010 4:16 AM").
3. C:\Windows\System32\autoconv.exe [Offset: 83F30h]; immediately followed by all 3,624 bytes of the BOOTMGR Loader code (beginning at offset 84130h and continuing through 84F57h); again followed by 4,056 zero bytes ending at offset 85F2Fh; 16 sectors total.
("Auto File System Conversion Utility"; File version: "6.1.7601.17514 (win7sp1_rtm.101119-1850)"; 793,088 bytes; Modification Date: "11/20/2010 5:24 AM").
4. C:\Windows\SysWOW64\autoconv.exe [Offset: 69970h]; immediately followed by all 3,624 bytes of the BOOTMGR Loader code (beginning at offset 69B70h and continuing through 6A997h); again followed by 4,056 zero bytes ending at offset 6B96Fh; 16 sectors total.
("Auto File System Conversion Utility"; File version: "6.1.7601.17514 (win7sp1_rtm.101119-1850)"; 679,424 bytes; Modification Date: "11/20/2010 4:16 AM").
5. C:\Windows\System32\autofmt.exe [Offset: 7CF30h]; immediately followed by all 3,624 bytes of the BOOTMGR Loader code (beginning at offset 7D130h and continuing through 7DF57h); again followed by 4,056 zero bytes ending at offset 7EF2Fh; 16 sectors total.
("Auto File System Format Utility"; File version: "6.1.7601.17514 (win7sp1_rtm.101119-1850)"; 763,904 bytes; Modification Date: "11/20/2010 5:24 AM").
6. C:\Windows\SysWOW64\autofmt.exe [Offset: 64938h]; immediately followed by all 3,624 bytes of the BOOTMGR Loader code (beginning at offset 64B38h and continuing through 6595Fh); followed by the 4,056 zero bytes ending at offset 66937h; 16 sectors total.
("Auto File System Format Utility"; File version: "6.1.7601.17514 (win7sp1_rtm.101119-1850)"; 658,944 bytes; Modification Date: "11/20/2010 4:16 AM").
7. C:\Windows\System32\RelPost.exe [Offset: 148E0h]; immediately followed by all 3,624 bytes of the BOOTMGR Loader code (beginning at offset 14AE0h and continuing through 15907h); followed by the 4,056 zero bytes ending at offset 168DFh; 16 sectors total.
("Windows Diagnosis and Recovery"; File version: "6.1.7600.16385 (win7_rtm.090713-1255)"; 173,056 bytes; Modification Date: "07/13/2009 5:39 PM").
8. C:\Windows\System32\untfs.dll [Offset: 5E7A0h]; immediately followed by all 3,624 bytes of the BOOTMGR Loader code (beginning at offset 5E9A0h and continuing through 5F7C7h); followed by the 4,056 zero bytes ending at offset 6079Fh; 16 sectors total.
("NTFS Utility DLL"; File version: "6.1.7601.17514 (win7sp1_rtm.101119-1850)"; 403,968 bytes; Modification Date: "11/20/2010 5:27 AM").
9. C:\Windows\SysWOW64\untfs.dll [Offset: 4FC00h]; immediately followed by all 3,624 bytes of the BOOTMGR Loader code (beginning at offset 4FE00h and continuing through 50C27h); followed by the 4,056 zero bytes ending at offset 51BFFh; 16 sectors total.
("NTFS Utility DLL"; File version: "6.1.7601.17514 (win7sp1_rtm.101119-1850)"; 346,624 bytes; Modification Date: "11/20/2010 4:21 AM").
10. C:\Windows\System32\oobe\winsetup.dll [Offset: 1EC980h]; immediately followed by all 3,624 bytes of the BOOTMGR Loader code (beginning at offset 1ECB80h and continuing through 1ED9A7h); followed by the 4,056 zero bytes ending at offset 1EE97Fh; 16 sectors total.
("Windows System Setup"; File version: "6.1.7601.17514 (win7sp1_rtm.101119-1850)"; 2,199,040 bytes; Modification Date: "11/20/2010 5:27 AM").

Note: The code for the whole Windows 7 Boot Record Area actually spans across 9 (512-byte) sectors: This includes the Boot Sector we're examining here, plus 40 bytes in the ninth one, for a total of 4,136 bytes [40 + (512 x 8)]. And, technically, because the Boot Record area is a full 16 contiguous sectors (Sectors 0 - 15 of the Volume), even the 4,056 zero-bytes of the remaining padded area are loaded into Memory by the VBR code; see the code lines below at 07C0:00BB and following.

Like all previous MS Boot Records, the first three bytes are often called the Jump Instruction. But only the first two bytes (EB 52 in this case) are actually used to form the actual JMP (Jump) code to the rest of the executable x86 (PC) Assembly code; the third byte (90h) is just a NOP ('No Op' or do nothing) instruction. The next 8 bytes are the "OEM ID" or System Name ("NTFS" and four blank spaces) for an NTFS volume; followed by the BPB (BIOS Parameter Block).

Just like the _ BPB _ area for the Windows™ XP Volume Boot Record sector, this one also has all the fields that an NTFS volume has in common with FAT16 and FAT32 Boot Records; such as Bytes per Sector, Sectors per Cluster, etc. and even the old Media Descriptor byte (F8), but again, this one does not contain "System ID" or "Volume Label" fields, nor any system file names. However, if you can locate "bootmgr" on your system and dig into its code, you will find a number of system file names, such as winload.exe and BCD in there.

All the elements of a Win7 VBR's _ BPB _ area are the same as those for earlier NTFS boot records (for details on the NTFS BPB, see our NTFS Boot Record page). Just like Vista, a new Microsoft retail DVD Windows 7 OS install will have 2,048 reserved sectors at the beginning of an MBR partitioned disk, so its 100 MiB "System Reserved" partition VBR will have "00 08 00 00" (0x800 = 2048) at offsets 1Ch through 1Fh in its BPB area. In the VBR below, copied from a Windows 7 OS's C: drive, we see the bytes "00 28 03 00" shown between the brackets at those offsets (which represent 206,848 sectors; 0x32800 = 206848). This is the total of the 2048 sector offset at the beginning of the disk plus the 100 MiB size (100 MiB = 104,857,600 bytes/512-byte sectors = 204800 sectors) of that first partition (2048 + 204800 = 206848 sectors).

The following is a disk editor view of how the bytes of this VBR are stored on a hard disk in the first sector of a Windows 7 OS install's C: drive volume:

     Relative Sector 0 (within the Volume)

                                              NTFS BPB          "OEM ID"
                                                  |                 |
             0  1  2  3  4  5  6  7  8  9  A  B  C| D  E  F         |
     0000:  EB 52 90 4E 54 46 53 20 20 20 20 00 02 08 00 00  .R.NTFS    .....
     0010:  00 00 00 00 00 F8 00 00 3F 00 FF 00[00 28 03 00] ........?.......
     0020:  00 00 00 00 80 00 80 00 FF CF FC 02 00 00 00 00  ..........?.....
     0030:  00 00 0C 00 00 00 00 00 02 00 00 00 00 00 00 00  ................
     0040:  F6 00 00 00 01 00 00 00 6B E5 F9 78 1A FA 78 EA  ........k..x..x.
     0050:  00 00 00 00 FA 33 C0 8E D0 BC 00 7C FB 68 C0 07  .....3.....|.h..
     0060:  1F 1E 68 66 00 CB 88 16 0E 00 66 81 3E 03 00 4E  ..hf......f.>..N
     0070:  54 46 53 75 15 B4 41 BB AA 55 CD 13 72 0C 81 FB  TFSu..A..U..r...
     0080:  55 AA 75 06 F7 C1 01 00 75 03 E9 DD 00 1E 83 EC  U.u.....u.......
     0090:  18 68 1A 00 B4 48 8A 16 0E 00 8B F4 16 1F CD 13  .h...H..........
     00A0:  9F 83 C4 18 9E 58 1F 72 E1 3B 06 0B 00 75 DB A3  .....X.r.;...u..
     00B0:  0F 00 C1 2E 0F 00 04 1E 5A 33 DB B9 00 20 2B C8  ........Z3... +.
     00C0:  66 FF 06 11 00 03 16 0F 00 8E C2 FF 06 16 00 E8  f...............
     00D0:  4B 00 2B C8 77 EF B8 00 BB CD 1A 66 23 C0 75 2D  K.+.w......f#.u-
     00E0:  66 81 FB 54 43 50 41 75 24 81 F9 02 01 72 1E 16  f..TCPAu$....r..
     00F0:  68 07 BB 16 68 70 0E 16 68 09 00 66 53 66 53 66  h...hp..h..fSfSf
     0100:  55 16 16 16 68 B8 01 66 61 0E 07 CD 1A 33 C0 BF  U...h..fa....3..
     0110:  28 10 B9 D8 0F FC F3 AA E9 5F 01 90 90 66 60 1E  (........_...f`.
     0120:  06 66 A1 11 00 66 03 06 1C 00 1E 66 68 00 00 00  .f...f.....fh...
     0130:  00 66 50 06 53 68 01 00 68 10 00 B4 42 8A 16 0E  .fP.Sh..h...B...
     0140:  00 16 1F 8B F4 CD 13 66 59 5B 5A 66 59 66 59 1F  .......fY[ZfYfY.
     0150:  0F 82 16 00 66 FF 06 11 00 03 16 0F 00 8E C2 FF  ....f...........
     0160:  0E 16 00 75 BC 07 1F 66 61 C3 A0 F8 01 E8 09 00  ...u...fa.......
     0170:  A0 FB 01 E8 03 00 F4 EB FD B4 01 8B F0 AC 3C 00  ..............<.
     0180:  74 09 B4 0E BB 07 00 CD 10 EB F2 C3 0D 0A 41 20  t.............A
     0190:  64 69 73 6B 20 72 65 61 64 20 65 72 72 6F 72 20  disk read error
     01A0:  6F 63 63 75 72 72 65 64 00 0D 0A 42 4F 4F 54 4D  occurred...BOOTM
     01B0:  47 52 20 69 73 20 6D 69 73 73 69 6E 67 00 0D 0A  GR is missing...
     01C0:  42 4F 4F 54 4D 47 52 20 69 73 20 63 6F 6D 70 72  BOOTMGR is compr
     01D0:  65 73 73 65 64 00 0D 0A 50 72 65 73 73 20 43 74  essed...Press Ct
     01E0:  72 6C 2B 41 6C 74 2B 44 65 6C 20 74 6F 20 72 65  rl+Alt+Del to re
     01F0:  73 74 61 72 74 0D 0A 00 8C A9 BE D6 00 00 55 AA  start.........U.
             0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F

Figure 1.

The last 116 bytes of this Boot Record contain Error Messages, Message Offset bytes and the Word-sized signature ID (or Magic number) of AA55h. Remember that hex Words (numerical data requiring more than a single byte) for Intel x86 CPUs are always stored in memory with the Least-Significant byte first and the Most-Significant byte last to make CPU processing quicker.

Each Error Message begins with the Hex bytes 0Dh and 0Ah; a Carriage Return and Line Feed, and ends with a 00h byte which makes these what's commonly known in various programming languages as zero-terminated or 'sz' strings (a character string followed by a single zero byte). The error messages are exactly the same as those under Windows XP, except 'NTLDR' has been replaced by "BOOTMGR".

Note that the string of letters ("TCPA") at offsets E3h through E6h are not coincidental; they stand for "Trusted Computing Platform Alliance" and are actually part of the code which tests for the existence of a TPM chip. If the hardware supports TPM (Trusted Platform Module) version 1.2, then it can be used to provide extra functionality for Win 7's BitLocker™ Drive Encryption. Neither are the bytes at offsets 6Fh through 72h a coincidence. The characters ("NTFS") are used in the code to check for an "OEM ID" of that name, and display "A disk read error occurred" if that string is not found (at offset 0003).

The eight physical sectors directly following a Windows™ 7 NTFS Boot Sector, contain code which can interface with the older NTLDR file (in order to boot up Windows™ NT, 2000, XP, 2003 OS partitions) plus code to interact with the new BOOTMGR (boot manager) program introduced with the Vista OS. This code is still necessary when booting up a Windows™ OS (even though the bootmgr or NTLDR files may have been copied to the OS partition you start booting up from; as would be the case if, for example, you installed Windows™ 7 on a disk already containing a bootable Win 98 OS in the first partition followed by a Win 7 install partition). When the code in such an altered volume boot record is executed, it will look for, and require the existence of, the Windows™ XP or 7/8 OS partition's system code in order to boot-up the original Windows™ 98 OS (cf. FAT32 Boot Record under Windows NT OSs).

The four bytes at offsets 1F8h through 1FBh ("8C A9 BE D6") are used by the Microsoft Windows™ 7 VBR for a very specific purpose; for English versions of Windows 7, you'll always see these same Hex values ("8C A9 BE D6") in your VBR. They're used by the code to display Error Messages on your screen. But for those using Windows™ 7 in a different language, their VBRs may have different values in the second, third and fourth bytes depending upon how many characters are in each of the messages. In the disassembled code, we'll point out where these values show up. In any case, since the code portion above the messages will always be the same, the first offset (018Ch) will never change no matter what languages (or string lengths) are used.

Now that you know what the bytes at offsets 1F8h through 1FBh are used for, you could change these error messages to display whatever you wish (as long as they all fit into the space between offsets 18Ch and 1F7h) by counting the character lengths and using a disk editor to change the appropriate bytes in the VBR sector.

After the code in your disk drive's MBR sector transfers control to this Boot Sector, it will test critical aspects of the Win 7 operating system, then load and run the BOOTMGR Loader (or "bootstrap") code which will eventually run the actual "bootmgr" program that finally attempts to load an operating system!

# An Examination of the Assembly Code

You can learn a great deal about the instructions used here by obtaining the x86 Opcode Windows Help file and Ralf Brown's Interrupt List from our Intro to Assembly page.

Here's a Listing of the disassembled code (; with comments) after first being loaded into Memory at 0000:7C00 by the Windows 7 MBR code. Until noted, the instructions below are referenced to a CS (Code Segment) of 0000. If you see an asterisk (*) next to an instruction, it means MS-DEBUG can not disassemble its code; you'd only see "DB nn" displayed.

    7C00 EB52          JMP     7C54         ; Jump over BPB (BIOS Parameter
                                            ;   Block) to code at 7C54.
    7C02 90            NOP

    ; 7C03 thru 7C0A  'NTFS    '  8-byte System Name or OEM ID. (Some think
    ;                                   this is part of the BPB; it's not!)

    ; 7C0B thru 7C53   BIOS Parameter Block (BPB) Compare with XP VBR here.
    ;      0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F

    7C03           4E 54 46 53 20 20 20 20 00 02 08 00 00      NTFS    .....
    7C10  00 00 00 00 00 F8 00 00 3F 00 FF 00 00 28 03 00   ........?.......
    7C20  00 00 00 00 80 00 80 00 FF CF FC 02 00 00 00 00   ..........?.....
    7C30  00 00 0C 00 00 00 00 00 02 00 00 00 00 00 00 00   ................
    7C40  F6 00 00 00 01 00 00 00 6B E5 F9 78 1A FA 78 EA   ........k..x..x.
    7C50  00 00 00 00                                       ....

    7C54 FA            CLI                  ; Disable maskable Interrupts.
    7C55 33C0          XOR     AX,AX        ; Zero out both the Accumulator
    7C57 8ED0          MOV     SS,AX        ;   and Stack Segment Registers.
    7C59 BC007C        MOV     SP,7C00      ; Set Stack Pointer to 0000:7C00
    7C5C FB            STI                  ; Enable Interrupts again.

    ; NOTE: The code here simply changes the Segment reference for locations in
    ; memory. It switches the Segment from 0000 to 07C0 when RETF is executed
    ; at 0000:7C65. The next instruction, at 07C0:0066, is the same location
    ; as linear address 0x7C66 (or, 0000:7C66).

    7C5D 68C007      * PUSH    07C0         ; New segment ref. to be used for
    7C60 1F            POP     DS           ;   both Data (DS = Data Segment)
    7C61 1E            PUSH    DS           ;   . . .
    7C62 686600      * PUSH    0066         ;   and Code segments . . .
    7C65 CB            RETF                 ;   after this RETF instruction.

For those of you who have taken the time to set up BOCHS to step through this code, we want to clear-up some confusion about how the Stack is displayed in its GUI Debugger: Even though BOCHS is debugging "CPU: Real Mode 16" code, its display always shows the 32-bit registers, eax, ebx, etc., so we mentally eliminate the upper 16 bits of the display when in 16-bit mode (we drew black lines through those bytes in Figure 2 below). But the most confusing thing may be how values on the Stack are displayed: Always as 32 bits even when the Memory Location Addresses count up by only 16 bits! So, you must first mentally block out the four leading zero bytes (we've used black lines again to do so in the figure below). After that, the key to interpreting values on this Stack is knowing that it is arranged in order to show 16-bit WORD values, but due to a PC's little-endian architecture, where the least significant byte in a numerical WORD comes first, the Memory is not only displayed as increasing from Top to Bottom, but also from RIGHT to LEFT. Therefore, the 16-bit WORD in Memory Locations 7bfe to 7bff (which is: 0x07C0) is referenced only by its lower byte in Memory, 7BFE, which corresponds to the byte at the RIGHT side of the WORD:
Figure 2.

So, all Code (CS) and Data (DS) Segments in the instructions which follow are in reference to Segment 07C0. This means the next instruction is, technically: 07C0:0066 (so only the "Offsets" are shown below). Note, however, in debuggers, such as BOCHS, which use Linear Memory addressing, these would be displayed as 0x7C66 and following.

    0066 88160E00      MOV     [000E],DL  ; DL = Drive # (often 80h); see MBR code @ 727.
                                          ; Used here at 0096, 013D and in Subrtn. @ 11D.

    006A 66813E03004E544653 * CMP  DWORD PTR [0003],5346544E  ;/ Points to -> "NTFS" at 7C03.
                                                              ;| Check if NTFS Boot Record, and
    0073 7515          JNZ     008A                 ;\ if not, display Disk read error -> 016A.

    ; NOTE: A Windows 7 or 8 OS must be run on a computer with INT 13 Extensions!
    ; ==========================================================================
    0075 B441          MOV     AH,41        ;/ Function 41h (with BX=55AAh):
    0077 BBAA55        MOV     BX,55AA      ;|  Checks for INT 13 Extentions
    007A CD13          INT     13           ;|  in BIOS.  If CF flag cleared
    ;| and [BX] changes to AA55h, they are installed;  Major version is in
    ;| AH: 01h=1.x; 20h=2.0/EDD-1.0; 21h=2.1/EDD-1.1; 30h=EDD-3.0.
    ;| CX = API subset support bitmap. If bit 0 is set (CX is 'odd' number),
    ;|    extended disk access functions (AH=42h-44h,47h,48h) are supported.
    ;\    So, only if _no_ extended support is available, will it fail.

    007C 720C          JB      008A         ; If CF flag not cleared, then
                                            ; declare 'Disk error' -> 016A.
    007E 81FB55AA      CMP     BX,AA55      ; Was [BX] changed to AA55h ?
    0082 7506          JNZ     008A         ; If not, 'Disk error' -> 016A.
    0084 F7C10100      TEST    CX,0001      ; If bit 0 of CX isn't zero ...
    0088 7503          JNZ     008D         ; ... we Jump to 07C0:008D.
    008A E9DD00        JMP     016A         ; If zero, -> 'error routine'.

    008D 1E            PUSH    DS           ; Save DS on Stack
    008E 83EC18        SUB     SP,+18       ; Make room for Buffer on Stack
    0091 681A00      * PUSH    001A         ; Size of Buffer = 1Ah = 26 bytes
    0094 B448          MOV     AH,48        ; Function 48h of INT 13 :
                                            ; "GET DRIVE PARAMETERS"
    0096 8A160E00      MOV     DL,[000E]    ; Put Drive Number (usually 80h) in DL.
                                            ; (Already set at 0066; usually 80h.)
    009A 8BF4          MOV     SI,SP        ; Put SP into SI to set up Buffer on
                                            ;   the Stack for Drive Parameters.
    009C 16            PUSH    SS           ;/ These two lines change
    009D 1F            POP     DS           ;\ DS to zero before doing INT13.
    009E CD13          INT     13           ; Get Drive Parameters.
    +------------------------------------------------------+
    |  Format of INT 13, Function 48h, DRIVE PARAMETERS:   |
    |						       |
    | Offset  Size    Description   		       |
    | ------  -----  ------------------------------------  |
    |  00h    WORD   (CALL) Size of Buffer (1Ah for v1.x)  |
    |                 (RET) Size of Returned Data          |
    |  02h    WORD    Information Flags, Bitfields:        |
    | +==================================================+ |
    | |  Bits  Description				     | |
    | |  ----  ------------------------------------------| |
    | |    0   DMA boundary errors handled transparently | |
    | |    1   C/H/S Information is valid.		     | |
    | |    2   Removable Drive.			     | |
    | |    3   Write with verify supported.		     | |
    | |    4   Drive has change-line support:	     | |
    | |		(Required if Drive is Removable!)    | |
    | |    5   Drive can be locked:			     | |
    | |		(Required if Drive is Removable!)    | |
    | |    6    CHS Information set to maximum supported | |
    | |	        values; _not_ current media.	     | |
    | | 15-7   Reserved (0).			     | |
    | |       (Bits 4-6 are only valid if bit 2 is set.) | |
    | +==================================================+ |
    |  04h    DWORD   Number of physical Cylinders	       |
    |  08h    DWORD   Number of physical Heads on drive    |
    |  0Ch    DWORD   Number of physical Sectors Per Track |
    |  10h    QWORD   Total Number of Sectors on drive     |
    |  18h    WORD    Bytes per Sector (200h = 512)        |
    +------------------------------------------------------+

Parameters for a small 365 MiB BOCHS drive we first used to study this code were found as follows:
Figure 3.
Note: The drive parameters for a Windows 7 OS drive quite often have 255 Heads (the BIOS on some Laptop/Notebook PCs may be around 240 instead). So for 63 Sectors per Track at 512 Bytes per Sector, each full Cylinder would equal 16,065 sectors. But in order to get Bochs to even begin to function with a flat image based upon such a drive, the drive parameters in its configuration file can not exceed a value of 16 Heads.
Note: The Cylinder count stored in chips on the controller boards of disk drives cannot exceed 16,383 (0x3FFF), so for any drive or image file larger than 16383 x 16 x 63 (or a Maximum CHS of: 16382,15,63) = 16,514,064 sectors (8,455,200,768 bytes; about 8.45 GB), only the data for Total Sectors would be valid. However, there are further limitations by a PC's BIOS Interrupt 13h code (which reads/writes sectors from/to a drive among other things) and the maximum number of bits availble for use by a Partition Table's CHS Starting and Ending entries on a Basic partitioned drive (see our notes about a 'bug' in MS-DOS here and Partition Tables here), which reduces the limitation of CHS addressable drives to 1024 x 255 x 63 (for a Maximum CHS of: 1023,254,63) = 16,450,560 sectors (8,422,686,720 bytes; or about 8.42 GB).
Real Example: When debugging the MBR and VBR of a 36 GiB Win 7 image of exactly 75,497,472 sectors (38,654,705,664 bytes); obviously not installed under Bochs, we simply approximated its pseudo-CHS values as: 74898,16,63 (Bochs actually didn't care if we used some other cylinder values as long as there were 16 heads!) Running the code above (using any [x,16,63] CHS parameter values in Bochs; provided x was greater than 16838) still resulted in the correct sector count in Memory locations 7BF4 to 7BFB for that drive: "00 00 80 04 00 00 00 00" (in little-endian) = 0x4800000 = 75497472 sectors.
But when running BOCHS on a different PC, we got: "e0 fe 7f 04 00 00 00 00" = 0x47FFEE0 = 75497184 sectors (under the same settings)!

    00A0 9F            LAHF                 ; Load Status flags into AH
    00A1 83C418        ADD     SP,+18       ; Change Stack Pointer to 7BFC
    00A4 9E            SAHF                 ; Save AH into flags register.
    00A5 58            POP     AX           ; Usually 200h (512 bytes/sector).
    00A6 1F            POP     DS           ; DS goes back to 07C0.
    00A7 72E1          JB      008A         ; If below, 'Disk error' -> 016A
    00A9 3B060B00      CMP     AX,[000B]    ; [0B - 0C] (Usually, 200h = 512 Bytes per Sector.)
    00AD 75DB          JNZ     008A         ; If not zero, 'Disk error' -> 016A
    00AF A30F00        MOV     [000F],AX           ; Copies Bytes per Sector into 7c10 to 7c0F.
    00B2 C12E0F0004  * SHR     WORD PTR [000F],04  ; For a 200h in 7c10 to 7c0F, shifts the
                                                   ; binary '1' bit (or the '2' of 200h) in
    ; the MSB to the right by 4 places; thus SHR WORD,04 is the same as dividing it by 16:
    ;                          10 0000 0000 (200h) -> 00 0010 0000 (20h)
    ; Or: 512/16 = 32 (20h), and the contents of 7C0F becomes 32 (20h).

    ; The reason for doing the math above is because for each loop of the code executed below
    ; (starting at 00C5), each sector will be copied by adding the Sector Size divided by 16
    ; to the initial Segment value of 07C0; this way, only the Segment part of the "Transfer
    ; Buffer"'s Segment:Offset needs to be changed.

    00B7 1E            PUSH    DS           ; Save current DS on Stack.
    00B8 5A            POP     DX           ; Change DX to 7c0.
    00B9 33DB          XOR     BX,BX        ; zero-out BX register.

The Win 7 MBR already loaded the first sector (Boot Sector) of our Win 7 VBR into Memory at 7C00 through 7DFF (which is being executed here). The next 3 instructions set up the code which follows to copy the remaining 15 sectors (if 512 bytes/sector is in use) of the Volume Boot Record Area into Memory locations 7E00 through 9BFF (normally only about half those sectors contain executable code; the remaining bytes being zero-padded):

    00BB B90020        MOV     CX,2000      ; 2000h = 8192 = 16 512-byte sectors,
                                            ; or only 2 4096-byte sectors.
    00BE 2BC8          SUB     CX,AX        ; If AX=200; CX - AX -> CX, so
                                            ; the 2000 in CX becomes: 1E00.
    00C0 66FF061100  * INC     DWORD PTR [0011]  ; Sets [7C11] = 1 (it was 0).
                                                 ; Used in setting the offset
    ; from an initial sector location (at line 121) in the Extended Disk Read
    ; Subroutine (7C0:011D) below, where it is increased by 1 (at line 154)
    ; for each loop, until no more sectors are left to read. Total number of
    ; sectors to read having been set at lines 00BB and 00BE above.

The following code from 00C5 through 00D5 (and the Subroutine it CALLs at 011D through 0169) is used to load the BOOTMGR Loader code and zero-byte padding into Memory (see notes at 00D4):

    00C5 03160F00      ADD     DX,[000F]    ; Add [7C1F] to DX for each pass, so
                                            ; 1st pass (of 15): 20h + 7c0 = 7e0.

    00C9 8EC2          MOV     ES,DX        ; 1st pass: ES = 7E0, 2nd pass:  800,
    ;  3rd: 820; 4th:  840,  5th: 860,  6th: 880,  7th: 8A0,  8th: 8C0, 9th: 8E0,
    ; 10th: 900, 11th: 920, 12th: 940, 13th: 960, 14th: 980   and      15th: 9A0.

    00CB FF061600      INC     WORD PTR [0016]  ; [7C16] changes from 0 -> 1.
                                                ; This is a flag which is set(1)
    ; to control how the Extended Disk Read Subroutine will be used (see lines
    ; at 15F and 163 in Subroutine at 011D).

    00CF E84B00        CALL    011D

    00D2 2BC8          SUB     CX,AX  ; 1st pass: 1e00 (in CX) - 200h = 1C00.
                                      ; 2nd pass: 1c00 (in CX) - 200h = 1A00,
    ; 3rd: 1800, 4th: 1600, 5th: 1400, 6th: 1200, 7th: 1000, 8th: 0E00,
    ; 9th: 0C00, 10th: A00, 11th: 800, 12th: 600, 13th: 400, 14th: 200.  On
    ; the 15th pass: CX becomes zero, so the next instruction stops looping.
      =====================================================================

    00D4 77EF          JA      00C5   ; This loops until all 15 sectors of
                  (or: JNBE)          ; the BOOTMGR Loader Area are copied
                                ; from the drive to Memory locations 7E00h
                                ; through 9BFFh; the code ends at 8C27h,
                                ; but it's followed by 4,056 zero bytes.

    ; =================================================================
    ;  This code (from 00D6 through 010B) is related to discovering if
    ;  TPM version 1.2 interface support is operational on the system.
    ;
    ; Comments below checked with the document, "TCG PC Client Specific
    ; Implementation Specification For Conventional BIOS" (Version 1.20
    ; FINAL/Revision 1.00/July 13, 2005/For TPM Family 1.2; Level 2), §
    ; 12.5, pages 85 ff.  TCG and "TCG BIOS DOS Test Tool" (MSDN).

    00D6 B800BB        MOV    AX,BB00   ; With AH = BBh and AL = 00h
    00D9 CD1A          INT    1A        ; Int 1A ->  TCG_StatusCheck

    00DB 6623C0      * AND    EAX,EAX  ;/   If EAX does not equal zero,
    00DE 752D          JNZ    010D     ;\ then no BIOS support for TCG.

    00E0 6681FB54435041   * CMP    EBX,41504354  ; EBX must also return ..
                                                ; the numerical equivalent
    ; of the ASCII character string "TCPA" ("54 43 50 41") as a further
    ; check. (Note: Since hex numbers are stored in reverse order on PC
    ; media or in Memory, a TPM BIOS would put 41504354h in EBX.)

    00E7 7524             JNZ    010D       ;  If not, exit TCG code.
    00E9 81F90201         CMP    CX,0102    ; Version 1.2 or higher ?
    00ED 721E             JB     010D       ;  If not, exit TCG code.

    ; If TPM 1.2 found, perform a: "TCG_CompactHashLogExtendEvent".
    ; 06FD 666807BB0000 * PUSH   0000BB07  ; Setup for INT 1Ah AH = BB,
                                           ; AL = 07h command (p.94 f).
    00EF 16               PUSH    SS
    00F0 6807BB         * PUSH    BB07
    00F3 16               PUSH    SS
    00F4 68700E         * PUSH    0E70
    00F7 16               PUSH    SS
    00F8 680900         * PUSH    0009
    00FB 6653           * PUSH    EBX
    00FD 6653           * PUSH    EBX
    00FF 6655           * PUSH    EBP
    0101 16               PUSH    SS
    0102 16               PUSH    SS
    0103 16               PUSH    SS
    0104 68B801           PUSH    01B8
    0107 6661             POPAD
    0109 0E               PUSH    CS
    010A 07               POP     ES
    010B CD1A             INT     1A      (BIOS Clock)

    ; On return, "(EAX) = Return Code as defined in Section 12.3" and
    ;            "(EDX) = Event number of the event that was logged".
    ; ================================================================

Note: The following 11 bytes of code (from offsets 10D through 117) are new to the Windows 7 VBR (they are not found in Vista's VBR). This code uses the REPeat and STOSB (STOre String Byte) instructions to overwrite a block of Memory with the byte value found in AL (which is zero); effectively zero-filling all the Linear Memory locations from AA28 (09A0:1028) through B9FF (09A0:1FFF): A span of 4,056 bytes (B9FFh - AA28h + 1 = FD8h; which is 4056 in decimal).

    010D 33C0             XOR     AX,AX      ; Zero out the Accumulator,
                                             ;  which sets AL = 0.

    ; Extra Segment (ES) was already set to 09A0 by adding 20h to DX
    ; (which begins as 7C0) 15 times in a row:  (0Fh x 20h = 1E0h) + 7C0h = 9A0h.

    010F BF2810           MOV     DI,1028    ; 1028h = 4,136
    0112 B9D80F           MOV     CX,0FD8    ; to zero-fill with 4,056 bytes
    0115 FC               CLD
    0116 F3AA             REP     STOSB      ; REP STOSB BYTE PTR ES:[DI], AL

    ; The starting location of ES:DI (09A0:1028) is equivalent to a Linear (or Absolute)
    ; Memory Location of:
    ;                      (Segment value * 16h) + Offset value = 9A00 + 1028h = AA28

    ; The VBR code has already loaded Linear Memory locations 7E00 through 8C27 with the
    ; BOOTMGR Loader Code (3,624 bytes) plus another 4,056 zero bytes; which brings the
    ; last Memory location of these 16 sectors to: 8C27 + FD8 = 9BFF hex.

    ; By using a Bochs command (set al = 0x22) just before executing the STOSB instruction, we were able
    ; to fill all 4,056 byte locations with 22h instead of zero; making it very easy to locate this area
    ; in Memory and observe what happened when we continued to execute the BOOTMGR's Bootstrap Loader
    ; code in the Boot Record Area's second and following sectors. See Figures 4 and 5 below.

    ; The BOOTMGR Loader (or "Bootstrap") code copies file system data from the partition on the
    ; drive that it has boot-up from (usually the System Reserved partition) into Memory locations
    ; A000 and following, searching for the location of the bootmgr file. More info about this
    ; may be found on our BOOTMGR Loader Code page.

    ; Speculating:  AA28 - 9BFF - 1 = E28 (3,624 decimal). Why does the code need to zero-out
    ; the same number of zero bytes (4,056) found at the end of the Boot Loader Area, which
    ; are also exactly the same number of bytes away from the end of the 16 sectors we already
    ; loaded as there are of the number of bytes of code they contain (3,624)?

    ; (Curiously, 1028 hex = 4,136, the exact number of bytes in the Win 7 VBR + BOOTMGR Loader Code!)

Figure 4.
Figure 5.

This is the normal "Exit point" for the VBR code, where execution jumps to Linear Memory location 7E7A (or 07C0:027A):

    0118 E95F01          JMP     027A   ; Entry point into BOOTMGR Loader
                                        ;   (or "bootstrap") Code in Boot
                                        ;    Record Area's second sector.
    011B 90              NOP
    011C 90              NOP

    ; The following code uses INT 13, Function 42h ("Extended Disk Read") to read
    ; 1 sector at a time of the remaining 15 sectors of the Boot Record Area into
    ; Memory; starting at location 7E00.  It does this by pushing what's called
    ; the "Disk Address Packet" (DAP) onto the Stack in reverse order of how the
    ; Interrupt will read the data, so the 00h (Reserved) and 10h (Packet Size)
    ; bytes are the last to be pushed onto the Stack (see instruction 0138 below):
    ;
    ; Offset Size	   Description of DISK ADDRESS PACKET's (DAP's) Contents
    ; ------ -----  ------------------------------------------------------------
    ;   00h	 BYTE   Size of packet (10h or 18h; 16 or 24 bytes).
    ;   01h	 BYTE   Reserved (00).
    ;   02h	 WORD   Number of blocks to transfer (Only 1 sector at a time here).
    ;   04h	 DWORD  Points to -> Transfer Buffer (0000 07E0 for this code), so:
    ;                            07E0:0000 = Memory Location 7E00 (1st pass;
    ;               Transfer Buffer is changed for each of 15 passes).
    ;   08h	 QWORD  Starting Absolute Sector (on Disk Drive or media) obtained
    ;               from verified Location of Volume Boot Sector after being
    ;               loaded into Memory by MBR code.
    ;
    ;   10h	 QWORD  NOT USED HERE. (EDD-3.0; optional) 64-bit flat address
    ;               of transfer buffer; only used if DWORD at 04h is FFFF:FFFF.
    ;               (Then size of packet would be 24 bytes.)
    ; =========================================================================
    ;           SUBROUTINE - INT 13 Function 42h Extended DISK READ
    ; =========================================================================
    011D 6660         * PUSHAD              ; "Push All Double" - all 32-bit
                                            ;   GP Regs pushed onto Stack!
    011F 1E             PUSH    DS          ; Currently DS = 07c0.
    0120 06             PUSH    ES          ; 1st pass: ES = 07e0.
    0121 66A11100       MOV     EAX,[0011]  ; 1st pass: EAX = 1; 2nd = 2, etc.

    0125 6603061C00     ADD     EAX,[001C]  ; [7C1C] + [7C11]; which for first
    ; pass is often: 800h + 1 = 801h (2049), the first sector after Boot Sector
    ; of System Reserved partition. 2nd pass, read from: 802h (Sector 2050), etc.

    012A 1E             PUSH    DS         ; Save DS, since DS -> 0 at 0142.
    012B 666800000000 * PUSH    00000000   ;\
    0131 6650         * PUSH    EAX        ;/ Location of Sector to Read from.
    0133 06             PUSH    ES         ;\ Segment part of Transfer Buffer
    0134 53             PUSH    BX         ;/  Offset part of Transfer Buffer
    0135 680100       * PUSH    0001       ; Copy only 1 sector.
    0138 681000       * PUSH    0010       ; Reserved and Packet Size bytes.
    013B B442           MOV     AH,42      ; Function 42h (INT13)
    013D 8A160E00       MOV     DL,[000E]  ; Drive # (usually 80h) -> DL
                                           ; (This was set at 0066 above.)
    0141 16             PUSH    SS         ; (which is zero)...
    0142 1F             POP     DS         ;  ...changing DS to zero.
    0143 8BF4           MOV     SI,SP      ; DS:SI must point to -> "Disk
                                           ;    Address Packet" on Stack.
                                           ;    ( DS:SI -> 0000:7BC8 )
    0145 CD13           INT     13         ; Read Sector from media.

    Upon entry into the INT 13 Interrupt with AX=4201, we have:
         DL = drive number = 80h
      DS:SI -> Disk Address Packet = 0000:7BC8 (Top of Stack;
            onto which we stored all required data as follows!)
    Format of DAP:
    -----------------------------
    Offst Size  Description
    -----------------------------------------------------------
      00  BYTE  Size of packet (in this case: 10h or 16 bytes) [7BC8]
      01  BYTE  Reserved (00)                                  [7BC9]
      02  WORD  Number of Blocks to Transfer (always 1 here;   [7BCA - 7BCB]
                "01 00" -> 0001 )

      04 DWORD  -> Transfer Buffer = (00 00 E0 07) = 07E0:0000 [7BCC - 7BCF]
                                     ( First Pass)
      08 QWORD  Starting Absolute Sector Number = 801h = 2049  [7BD0 - 7BD7]
                                       (Example Pass )
                (for non-LBA devices, compute as follows:
    ( ( (Cylinder x Number of Heads) + Selected Head) ) x Sectors
      Per Track)  + Selected Sector - 1), or for here:

              ( ( (0 x 16) + 1) x 63) + 1 - 1 = 63

    ==========================================================
    Return: CF clear if successful and AH = 00h
    ==========================================================
    	CF   set on error; AH = error code and DAP's block
                 count field set to number of blocks (sectors)
                 successfully transferred.
    ----------------------------------------------------------

    0147 6659         * POP     ECX
    0149 5B             POP     BX
    014A 5A             POP     DX
    014B 6659         * POP     ECX
    014D 6659         * POP     ECX
    014F 1F             POP     DS
    0150 0F821600     * JB      016A
    0154 66FF061100   * INC     DWORD PTR [0011]  ; 1st pass: [7C11] -> 2.
                                                  ; On 15th pass [7C11] = 10h (16).

    0159 03160F00       ADD     DX,[000F]  ; 1st pass: 7e0 + 20h = 800h.
                                           ; 2nd pass: 800 + 20h = 820h,
    ; etc.  And on last (15th) pass, DX = 9A0 + 20h =  9C0.

    015D 8EC2           MOV     ES,DX      ; Just as we commented on the
    ; lines at 00C5 and 00C9 above, here too ES = DX, and
    ; on the last pass (15th), it becomes: 9C0.

    015F FF0E1600       DEC     WORD PTR [0016]  ; [7C16] goes back -> 0 (flag is cleared).

    0163 75BC           JNZ     0121       ; If flag is not set, go back and
                                           ; read another sector. Win 7 Boot Sector
                                           ;
    0165 07             POP     ES
    0166 1F             POP     DS
    0167 6661         * POPAD              ; "Pop All Double" - all 32-bit
                                           ;   GP Regs reset from Stack!

    0169 C3             RET                ; Return to 00D2.

    ; Note:  When the last character of any Error Message has been displayed on
    ; the screen, the HLT instruction at offset 0176 should prevent any further
    ; code execution. But if it doesn't, the JMP instruction at 0177 loops back
    ; to the HLT instruction; effectively locking the computer into an endless
    ; loop (whether HLT stops execution or not)!  You must reboot the machine.

    016A A0F801        MOV     AL,[01F8]  ; [1F8] = 8C + 100 -> 18C h
    016D E80900        CALL    0179       ; Displays: "A disk read error occurred"
    0170 A0FB01        MOV     AL,[01FB]  ; [1FB] = D6 + 100 -> 1D6 h
    0173 E80300        CALL    0179       ; Displays: "Press Ctrl+Alt+Del to restart"

    0176 F4            HLT                ; HLT: Not found in Vista VBR code!
    0177 EBFD          JMP     0176

    ;     INT 10, Function 0Eh (Teletype Output) is used to display each
    ; character of the error messages.

    0179 B401          MOV     AH,01      ; Adds 100h to offsets from above.
    017B 8BF0          MOV     SI,AX      ; Offset of message -> Source Index Reg.
    017D AC            LODSB              ; Load one character into AL from [SI].
    017E 3C00          CMP     AL,00      ;/ Have we reached end of message
    0180 7409          JZ      018B       ;\   marker?(00) If so, then RETurn.
    0182 B40E          MOV     AH,0E      ;/ Otherwise use Teletype Output to ...
    0184 BB0700        MOV     BX,0007    ;|   (Display page 0, normal white
                                          ;|            on black characters.)
    0187 CD10          INT     10         ;| ... display one character at a time,
    0189 EBF2          JMP     017D       ;\ and go back for another character...

    018B C3            RET

Location of Error Messages and
Message Offsets in Memory

           0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F

    018C                                      0D 0A 41 20              ..A
    0190  64 69 73 6B 20 72 65 61 64 20 65 72 72 6F 72 20  disk read error
    01A0  6F 63 63 75 72 72 65 64 00 0D 0A 42 4F 4F 54 4D  occurred...BOOTM
    01B0  47 52 20 69 73 20 6D 69 73 73 69 6E 67 00 0D 0A  GR is missing...
    01C0  42 4F 4F 54 4D 47 52 20 69 73 20 63 6F 6D 70 72  BOOTMGR is compr
    01D0  65 73 73 65 64 00 0D 0A 50 72 65 73 73 20 43 74  essed...Press Ct
    01E0  72 6C 2B 41 6C 74 2B 44 65 6C 20 74 6F 20 72 65  rl+Alt+Del to re
    01F0  73 74 61 72 74 0D 0A 00 8C A9 BE D6 00 00 55 AA  start.........U.
           0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F

First Published: March 30, 2012. (30.03.2012).
Updated: March 28, 2012 (28.03.12), April 15, 2012 (15.04.2012); April 19, 2012 (19.04.2012); May 29, 2015 (29.05.2015); 14 JUN 2015 (14.06.2015); 12 JUL 2015 (12.07.2015); 28 JUL 2015 (28.07.2015); 19 AUG 2015 (19.08.2015).
Last Update: 21 September 2015. (21.09.2015). (And we're not finished yet!)

You can write to us 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