Installing and removing versions of Windows NT, Windows 9x, and Linux on a computer often leads to mysterious computer behavior. Recently, I thought that I had completely removed Linux from a computer, but the computer wouldn't boot without a Linux-ish error message. I zapped every partition and still Linux raised its head—despite a seemingly empty hard disk. PC veterans attribute mysteries of this type to an area of the disk called the Master Boot Record (MBR). Unless you know a few tricks, NT, other versions of Windows, and DOS lack simple tools for working with the MBR.
The MBR sits on your hard disk's first sector in a 512-byte area. The MBR provides a table of contents of the disk's partitions and their sizes. As a result, formatting the C drive to delete the MBR would be ineffective because the MBR sits outside the area of the disk known as drive C. Think of it this way: The MBR is a book's table of contents, and the C drive is the first chapter; ripping the pages of the first chapter out of the book wouldn't remove the first chapter's entry in the table of contents. The MBR has two parts: a short program that performs part of your PC's booting process and data that represents the table of contents.
In my case of trying to remove Linux, Linux modified the program inside the MBR, and the program emitted the error message. When you first try to fix a bulky MBR, try Fdisk. Fdisk is the only NT, Windows, and DOS command that directly affects the MBR. Fdisk has an undocumented option that replaces your computer's original MBR program: Run DOS or Windows, open up a command line, and type
This procedure should replace the MBR, but sometimes it won't. Fdisk does a sanity check before writing out this program, and sometimes Fdisk decides not to rewrite the MBR's program. Unfortunately, that's the error message I saw when trying to use Fdisk on my Linux system. I have no idea why Fdisk decided not to rewrite the program. I've removed Linux from systems without getting back talk from Fdisk, but for some reason, Fdisk wasn't cooperating that day. I figured that the best approach was to wipe the MBR clean and rebuild the drive. But I had to figure out how to accomplish this task with Fdisk failing me. Time for Plan B and a little DEBUG magic.
Since 1983, Microsoft has shipped its OSs (i.e., NT, Windows, and DOS) with a helpful tool called DEBUG. A cool feature of DEBUG lets you create and execute small assembly language programs; let's create a program to delete the MBR's data. This assembly language program won't run under NT, so you need to boot Win9x or DOS from a safe-mode command prompt.
Before creating this program, however, let me stress a warning. This program intends to remove your hard disk's main table of contents. If you're successful, you will delete the entire hard disk. Don't try this procedure if you want to save your hard disk's data. This procedure is intended only for drives that you want to restore to their factory-shipped state.
At a command prompt, start DEBUG. You know DEBUG is running when you see a hyphen (-). The hyphen is DEBUG's way of saying, "DEBUG reporting for duty and standing by." DEBUG commands generally consist of one letter followed by letters and numbers. (By the way, the numbers will be in hexadecimal format.)
To zap a disk's MBR, you create an area in RAM that is 512 bytes long and fill it with zeros. Then, you write a short assembly language program to tell the PC to write that 512-byte area of memory to the first sector of the first disk. The first sector is sometimes referred to as sector 0/0/1. You identify sector and disk locations with three numbers: the head number (0 for the first head), the cylinder number (0 for the first cylinder), and the sector number on that particular head/cylinder combination (1 for the first sector). If you're wondering why we use 0/0/1 rather than 0/0/0, I don't know of a good reason; attribute it to a historical accident. We number heads and cylinders from zero, but we number sectors starting at one.
To create the zeroed-out area of memory, type
F 9000:0 L 200 0
DEBUG responds with another hyphen. You just created an area starting at address 9000:0 (addresses are always two numbers separated by a colon) that is 512 bytes long (200 in hex equals 512 in decimal), and you filled that area with zeros. DEBUG accepts uppercase or lowercase letters, but it needs spaces between parameters: One space between F and 9000:0, another space before L, another space before 200, and a final space before 0.
Next, you enter the assembly language program. The program tells the computer to copy one sector of data from 9000:0 to head 0, cylinder 0, sector 1. To start the assembly language program, you need to tell the computer to write the sector of data by invoking a built-in BIOS program in your computer's BIOS. The BIOS program is at software interrupt 13 (i.e., INT 13). To write out a sector of data, INT 13 must first know where to find the data. You tell INT 13 how to find the data by putting the data's address in internal CPU areas called registers BX and ES. Then, you tell INT 13 which drive, head, cylinder, and sector to write the data to by placing the data in two more registers, CX and DX. You then tell INT 13 to write (rather than read or some other function) and the number of sectors to write by placing the data in another register called AX. The command INT 13 says to execute the command. Tell the system to return control to you with another command, INT 20.
To tell DEBUG that you're ready to start entering assembly language code, type
and press Enter. The prompt will change from a hyphen to an address, such as 0267:0100. That address is where your system will store your command. To run the program, you must enter assembly language code into your computer's memory by typing the following eight lines:
Mov dx,9000 Mov es,dx Xor bx,bx Mov cx,0001 Mov dx,0080 Mov ax,0301 Int 13 Int 20
Each of these lines begins with Mov, Xor, or Int, followed by a space, and followed by one or more parameters separated by commas. Type the first line as Mov, followed by a space, and followed by dx,9000 without a space between dx and 9000. If you mistype a command, DEBUG responds with ^ Error. The circumflex (^) points to the parameter that it doesn't understand. (If you've entered assembly language with an earlier DOS version of DEBUG, you'll be pleased that the DEBUG version that comes with Win98 is a lot more forgiving. You can type movdx,9000 without any spaces, and DEBUG still figures out the exact syntax of the assembly language command.)
After you type the above lines, press Enter twice to return to the hyphen. You can check your work by typing
u 100 L 12
which stands for unassemble the 18 (hex 12) bytes starting at address 100. Press Enter, and you'll see what DEBUG thinks you typed. If you really messed up and you want to start over, type q (for quit) and press Enter; you'll return to the C prompt.
If you like what you see, you can activate the program by typing g (for go) at the hyphen and pressing Enter. You'll receive the message Program terminated normally. Your MBR is now wiped clean, and you can start installing NT, Win98, or another OS as if the hard disk were brand new.
I know the first few lines of the program look tortured: The first Mov dx,9000 places the value 9000 hex into the DX register; the next line puts the value of DX into the ES register. Why not just put the value 9000 into ES? Because of a quirk in the Intel architecture, you can't directly place data into the ES register except through other registers. The next line, Xor bx,bx, is a quick way to put the value 0 into the BX register. After ES contains 9000 and BX contains 0, then INT 13 knows where to get the data: ES, BX, or 9000:0. The next command, Mov cx,0001, is necessary because INT 13 expects the cylinder number (0) and the sector number (1) packed together into CX in that way: cylinder/sector. Similarly, Mov dx,0080 packs both the target head (0) and drive (80) into register DX. INT 13 refers to the first physical hard disk as 80, the second as 81, and so on. Mov ax,0301 once more packs two pieces of information into one register. INT 13 identifies the write sector command as function number 3. INT 13 needs to know how many sectors to write—one—and those two get packed together into 0301.
I figured out how to complete this process about 10 years ago. I don't use DEBUG often, but it saves me a couple of times a year; I hope it's useful for you. One more thing—please don't email me for Linux advice. I'm just starting out myself and couldn't be of much help. Happy MBR blasting!