An Introduction to the
PC's (Personal Computer's)
BIOS (Basic I/O System)
NOTE: This page is still under construction; if a topic doesn't make sense, you may contact us for more information.
I had planned on providing examples of different BIOS features to show how
incredibly complex the code became
since the first PC was designed; and another page that highlighted some of the routines at assembly language level
for the BOCHS BIOS, but never got round to doing that. Instead, I spent a great deal of time creating a page on
using the BOCHS Graphical Debugger and some other tools which can be used to see what's inside the compressed
BIOS code of some fairly recent motherboards.
BIOS History (and older BIOS code)
VMWare BIOS Code (and making your own)
Coreboot (what it takes to make your own BIOS ROM file)
A History of the PC's BIOSIt would take a group of accomplished authors working full-time to produce a textbook on the complete history of the PC BIOS in a reasonable amount of time. It will take us much longer to even produce a brief summary of how PC BIOS code has changed over the years. Though we have provided many details on special topics (such as Checksum Bytes and even some assembly listings), we are limited in the research we can conduct and the access we have to different types of computers. Nevertheless, we hope to provide some data on this subject you may not find anywhere else; we appreciate your feedback. Though many of the details (and their order) have changed over the years, this is a list of the fundamental operations which the BIOS (Basic Input/Output System) code must complete before handing control over to an operating system. Due to the complexity of the modern BIOS, completing these items is now often referred to as the POST (Power On Self Test), since the BIOS has also contained code for many other tasks and features for quite some time:
As can be seen from the partial list above, a computer's BIOS is inextricably linked to its hardware. Therefore a history of the BIOS code must also include at least an historical summary of changes in PC hardware. Before computers with new processors, other internal devices (such as a real time clock), different types of memory, etc. ever became available to the public, they invariably required changes in the BIOS code. It's important to note the major differences (such as, bus width and addressable memory) in the Intel® processor family (see table below) for any historical study of the PC's BIOS.
Except for some early notebook CPUs (e.g., The advent of 64-bit processors meant computers might possibly access up to 16 EiB (16 Binary Exa Bytes) of memory at some point in the future. However, all 7th and 8th-generation 64-bit CPUs have been manufactured with far less than 64-bit address lines; 36-bit (for 64 GiB) and now 40-bit (for 1 TiB) are common. As noted above, a PC's chipset (such as its MCH) has often been the limiting factor regarding memory; and is still often true. For example, a GIGABYTE™ GA-G33M-DS2R from 2007, with an LGA775 socket for many different Intel 64-bit CPUs, only supported up to 8 GiB[3] of system memory due to the limitations of its 82G33 Graphics and Memory Controller Hub (GMCH).[4] Of course, in order to generally make use of more than 4 GiB of RAM, a 64-bit OS is also needed. (Note: PCs with 32-bit OSs often show only about 3.2 to 3.3 GiB available when 4 GiB is installed, since addressable hardware; especially onboard video controllers, may use hundreds of MB for their own support.) We will have more to say about how BIOS code was affected by changes in the amount of memory these processors could access.
The IBM PC BIOS Code; Clones, Lawsuits and CompatiblesIBM published the full source code for the BIOS of all of their early PCs. The code is quite easy to find online from various sites today; both in PDF copies of the early Technical Reference manuals (e.g., here's a copy of the IBM 5150 Technical Reference manual; PDF pages "193/393" and following contain the BIOS ROM code listing) and as files containing the actual binary bits extracted directly from the old BIOS chips. In fact, some emulators, such as PCE, actually make use of the original BIOS and ROM BASIC code which is why we can reproduce this error in the first ROM BASIC version. It must be noted that there were at least three "personal computers" available to the public prior to the IBM PC: The Apple II and the Commodore PET 2001 (both 6502 CPU based); which made use of the term 'personal computer,' and then the TRS-80 (using a Zilog Z80 CPU). Of the three, Apple published its BIOS code, and later a book containing all the ROM BASIC code for the TRS-80 also became available. In less than a year after release of the IBM PC, Eagle Computer created a clone which had BIOS code so close, if not identical, to that of the IBM PC, they were immediately sued by IBM. Eagle was forced to stop production until eventually rewriting their BIOS, but by then most of the compatibles such as the Compaq PCs were using legally designed compatible BIOS code. Other clone companies such as Corona Data Systems, were sued and lost as well. Prior to Compaq's legally engineered BIOS, which cost them 1 Million Dollars, Columbia Data Products had already created the first legally PC compatible BIOS, and soon after Compaq's IBM PC compatibles hit the market, Phoenix Technologies created their own PC compatible BIOS in a way that could never be legally assailed. I recommend reading all of this Quora article by the one who wrote the code! (Here's another article which delves more into How the First BIOS Code was Written.) Following the Phoenix BIOS, Award Software; which began as an early BIOS startup in 1983 in California, but was later sold to a company in Taiwan in 1993, became a noticeable competitor. But in 1998 it was merged into Phoenix Technologies. The only other major BIOS company, AMI (American Megatrends, Inc.), began producing BIOS software in 1986, among its other products; including motherboards, helping to keep them solvent to this day. They have had some "technical problems" over the decades, the most noticeable to the public being the "Happy Birthday Trojan" (though that term may not be quite accurate), which on November 13, 1993, caused many PCs with their BIOS chip to halt at boot-up and repeatedly play the happy birthday tune through the PC's speaker. However, they are still selling BIOS code, and a recent motherboard from Gigabyte (which had used AWARD BIOS in the past), is now using AMI UEFI BIOS code (in a 256 Mbit GigaDevice 25Q Series flash chip on their B460M DS3H).
If an OS needs to access the BIOS code, How does it do so?First, some necessary background: For many years after the first IBM PC was shipped, a number of routines in the PC's BIOS code were absolutely critical for almost every single application or utility program that ever ran under IBM PC DOS or MS-DOS. The code contained what are still called Interrupts for accessing the Keyboard, Memory, Video routines for the display, the floppy diskette drive, speaker and any other peripherals. As early operating systems grew, OS code with its own Interrupt calls was also developed to run in between applications and the BIOS code. Eventually, modern OS code, through the use of what came to be called drivers, eventually replaced most BIOS Interrupts with their own routines, allowing them direct access to the hardware; though increasing and tightening the layers between an application and the hardware. However, until that occurred, there were dedicated Memory bus locations that any program could use to by-pass an OS and hand control over to BIOS Interrupt code, get input from the keyboard or write directly to Memory locations used by a monitor for what was displayed on its screen (or any other hardware that had a specific bus output PORT on the system)! In the beginning, these Memory (or bus PORT) locations were hardwired to the BIOS chips (or physical lines on a PC hardware bus) and were directly accessed by using specific CPU commands. Of the maximum of 1 Megabyte of memory the first PC's CPU (an Intel 8088) could possibly access, the highest "Memory Address" lines (0xF4000 through 0xFFFFF; exactly 48 KiB;) were connected directly to the BIOS and ROM BASIC chips (the BIOS using only the highest 8 KiB). Thus, for many early versions of DOS, one could quite easily make a binary copy of the whole BIOS using the DEBUG utility and piping the output to a file! This is basically what my BIOSDUMP program further below does (but it cannot run under 64-bit Win 7 or later). However, for many decades now, there has generally been no way for an operating system, let alone an application, to be able to directly access a BIOS chip's contents! Some motherboard manufacturers have provided customers with specialized utility programs to make backup copies of the BIOS code, but this is nothing like being able to divert full control of a PC to the BIOS code from inside an application as one could do in the early days of DOS! (You could, for example, enter a single command in DEBUG which would reboot the PC in much the same way as pressing the CTRL + ALT + DEL keys did back then! At a DEBUG prompt that command is: "g = f000:fff0", or: "g = ffff:0" This should work under any DOS emulation or virtual machine. But attempting to do so under any Windows NT or XP OS will simply stop the DEBUG program.) Some Labwork: Install either VMware Player (see item 1) under Replacing the VMware BIOS below) or Oracle VM VirtualBox or both. If you do decide to install both, I highly
recommend using VMware Player as your primary virtual machine, and do not install any networking for VirtualBox.
You may also have some conflicts with USB adapters, etc. when running both a VMware VM and VirtualBox at the same time. Some important quick
help: Once you click your mouse cursor inside any VMware virtual machine window, to get it back again for use with your Host OS,
you must press both the CTRL and ALT keys at the same time! Under VirtualBox, you must press only
the CTRL key on the right side of the keyboard.
And for those addicted to using a mouse cursor, I've created a diskette image file with a mouse.com mouse driver you can run under DOS; along with some other useful utilities, so download tsrutils.zip now, connect the floppy image under your DOS VMs, copy mouse.com to your DOS drive (and perhaps even add it to the AUTOEXEC.BAT file so it will be installed at boot-up). The image file also includes my BIOSDUMP files to capture the DOS compatible BIOS code in use by whatever virtual machine program you're using. Note: Each BIOSDUMP capture will create a .BIN file of 64 KiB (65,536 bytes); so be sure you have enough room in the folder you run them in!
Where is a PC's BIOS code stored? Various types of BIOS chips.Over the course of the PC's history, BIOS code has been stored in many different types of non-volatile
memory, the first of which was truly Read Only Memory (
For testing or even small production runs, If the BIOS chip became corrupted, it required purchasing a pre-programmed replacement chip; unless a
user was so unlucky as to find the PC manufacturer had soldered the BIOS chip to the board! Even then, the BIOS chip
generally still had 24 rather large pins, and an electronics hobbyist could disable (or cut away) the old chip and solder the
new one to the existing legs (pins) without having to unsolder the old chip. Of course, if the cost of a programmed chip was
too high, then a better board with more features would win out. The worst class of motherboards in relation to BIOS chips were
those that stored the code in a chip soldered onto the board and also required the user to run an upgrade under Windows,
without anything else running! So, forgetting to disconnect the Network cable or to use TASK MANAGER to kill all but the
essential processes, meant you could easily turn such a motherboard into a useless piece of junk! Today, a PC's BIOS may reside in a small 8-pin, Note: If you'd like to contribute to a listing of the different types of BIOS chips and methods used to access them, we'd appreciate hearing from you; perhaps including some digital photos of your motherboard (and/or a closeup of the BIOS chip, once we determine where it's located) You can email us here.
How to Identify your PC's ChipsetThe best source of information, if it's available, would be from the engineers who designed your PC's motherboard.
ASUS™ and GIGABYTE™ both provide manuals online for most of their products; other motherboard companies may as well. A
number of chips on our GIGABYTE boards were listed in these manuals. However, most likely due to the cost of support, most PC
manufacturers do not supply you with such details.
Once you have the Chipset data, you can search a chip manufacturer's site for details on how data in the chip might be accessed; that data can be used by independent utility programmers to show the actual contents of a BIOS chip, as well as by motherboard manufacturers for use in their own BIOS upgrade programs. Some Board manufacturers may even provide a Windows-based utility to make a copy of your BIOS code! [Note: We do not recommend performing a BIOS upgrade, unless you have been assured it will allow your PC to function in some new way you require it to; such as recognizing a larger disk drive, or fixing a problem. We are only pointing out it may be easy to copy the code from your PC's BIOS chip using a software tool; not to use such tools for overwriting BIOS code, without considering the possibility it may become corrupted.] The following shows one such utility running on a PC (we used the PrintScreen key to capture its image; NEVER do this when upgrading!) and added the yellow rectangle and caption:
Note: For anyone wishing to access the BIOS code on a modern PC - without such a utilty, you would first need
to know how to use Intel's
The Location of a PC's First InstructionVirtually every PC, since the very first IBM® Personal Computer produced in 1981, to the latest Intel® or AMD® based PC, has had exactly the same Memory address hard-wired into its CPU as a reference for its first instruction![6] This means every PC's CPU will always begin executing machine code instructions from essentially the same location inside its BIOS chip, or for PCs that must first move (or decompress) their BIOS code to Memory, from an equivalent location in Memory. That address is: F000:FFF0 (in Segment:Offset notation) or: FFFF0h (in Linear notation). You may also find it represented by FFFF:0000 [See Figure 1 below; as listed in IBM's original Technical Reference manual; P/N 6025008], or as just FFFF:0 (in Normalized Segment:Offset notation). [Read Section 3 of our page on Segment:Offset Addressing to understand why FFFF:0 is equivalent to the Segment:Offset pair F000:FFF0.] IBM® named this address the "Power On Reset Vector " and it always contains a far jump instruction to the beginning of the BIOS chip's Power-on RESET code. Here's a display of what you'd find in that location and the next 12 bytes of an original IBM® PC's BIOS chip:
The first five bytes (shown in green ) comprise the Power-On Reset Far Jump. These 5 bytes disassemble to: JMP F000:E05B As you can see, Segment F000: is embedded inside this instruction, thus the reason its location is often referenced as F000:FFF0. Although the location of this far jump instruction is essentially 'set in stone' for all PC BIOS, it's not a requirement that where it jumps to next always be the same; yet every PC BIOS we've ever examined always jumps to "F000:E05B". Of the twelve IBM engineers assigned to create the IBM Personal Computer (model 5150), David J. Bradley[7] developed the code for its BIOS. So he's the one who, among all its other details, decided where in Memory the BIOS would place and execute the code from the first sector of the IBM PC's first floppy diskette's Boot Record. The location he chose was 0x7C00 (or 0000:7C00 in Segment:Offset notation). Unlike the first 'jump address' mentioned above (to F000:E05B), later BIOS authors could not have chosen a different location in Memory for loading the initial bootstrap routines without having their code become incompatible with existing boot diskettes! So IBM (and all the PC-clone companies which followed) continued to use that same location in Memory for their hard disk drive's Master Boot Records (MBRs). Release DateThe next eight bytes (shown in yellow ) were originally called the "RELEASE MARKER" by IBM; they always contain the release date of the BIOS code (which was 04/24/81 for those first PCs). [ In Figure 1, there's an error in the machine
code listing for the location of the Power On RESET code in the "JMP RESET" instruction. This is exactly how the
original "IBM Personal Computer Technical Reference Manual," was printed. This should have been listed as: EA5BE000F0 rather than "EA5B0000F0";
if you check the address shown on page A-5, it's obvious "RESET" begins at the address we've specified.] Anyone running a Microsoft/IBM OS from DOS through Windows 7 (32-bit), should be able to enter the following DEBUG commands (Windows users must first click on start —> Programs —> Accessories —> Command prompt to open a 'Command Prompt' window. Windows 7 users may be required to select 'Run As Administrator' next to the Command Prompt icon in order to access DEBUG), and obtain results similar to the following (DEBUG.EXE should already be in your path):
ENTER the commands shown in green at the DEBUG prompt ("-"). You can see we have the same Jump instruction as the original Personal Computer on this one, but this BIOS code was released on April 14, 2003 ("04/14/03"). (For more on the use of DEBUG, see our Guide to MS-DEBUG). Here's a Windows 7 (32-bit) Command Prompt using DEBUG to show its PC's BIOS release date of "06/18/09": ![]() On early PCs, RAM was an expensive and limited resource that was used as wisely as possible for the the execution of user's programs. Since the original PC could be purchased with only 16 KiB (16 x 1024 bytes = 16,384 bytes) of memory, we know for a fact it would have been impossible to fit the 32 KiB of ROM BASIC code into memory. But using half the available memory for even the 8 KiB of initial bootstrap code made no sense, since it could be accessed from its own ROM chip just as fast as any code in the dynamic RAM chips; both having a 250 nano second access time[8]. Once RAM became much faster than ROM or EEPROM ICs and PCs commonly had many megabytes of memory, system engineers had motive enough to first copy bootstrap routines from the BIOS code into memory, then execute it there. This made it possible for BIOS programmers to explore a number of other advantages to having their code shadowed in RAM; which we'll point out in our next section. But first, we need to mention some methods for making copies of whatever BIOS code still remains in memory after a PC boots up: How to Save BIOS code from the First 1 MiB of a PC's MemoryAs we mentioned above, for first generation PCs, BIOS code always had to be read directly from its chip(s).
Not only when the PC was booting-up, but every time a program used a system Interrupt or needed to access any other BIOS
code stored in its ROM (Read Only Memory) chip(s). In those days, the address lines corresponding to the last segment of
memory were hard-wired only to locations within the BIOS chip(s). Later on, PCs were made in which the BIOS code was
first copied into RAM and then used from there instead of directly from the BIOS chip(s). If you have access to a PC with
an Intel® 80286 (or possibly one with an i386) CPU, you might be able to use DEBUG to change various bytes of the BIOS
code in memory, since early computers lacked the ability to write-protect portions of memory. In order to quickly skim through the contents of any *.BIN file created by these programs, or to search for either a text string or hex byte pattern, we recommend using the free hex/disk editor, HxD. BIOS Checksum BytesThe last location in an early PC's BIOS chip was called its CHECKSUM byte. It was used to help check
that none of the chip's bytes had become corrupted (changed values). For example, the Checksum Byte of the first IBM
Personal Computer is "EB". This value was computed by first adding together every
preceding byte of the PC's 8 KiB BIOS code, two bytes at a time, keeping only the last 8-bits (one byte) of the sum, and
finally subtracting that value from 100 hex. Thus, the Checksum Byte ensures that running an "8-bit Checksum
operation" on every byte in the BIOS chip will produce a result of zero (0). [ Note: An 8 KiB file full of only FF bytes would also have an 8-bit Checksum of
zero, but its 32-bit Checksum would be 1FE000; which is the sum of all 8,192 of its
bytes added together (2,088,960 decimal).] In summary, an 8-bit Checksum Byte can be computed as follows (we
also show in the table below all checksum data for the original IBM PC's three different BIOS chip versions):
If you wish to compute the 8-bit (or 16- or 32-bit) Checksum of a file, you can easily do so using HxD, as shown here: ![]() This BIOS file begins with the part number of its programmed ROM chip (5700051) followed by IBM's copyright phrase ("COPR. IBM 1981") which some have mistaken as an erroneous spelling of 'Corp.'
What Most Can Find Ain't All There Is!
|
![]() | This bit-map file had to be converted from a special AWARD BIOS Bit-map file ("AWBM") after extracting it from an LHA compressed file named "AwardBmp.bmp" stored within a PC's actual 128 KiB BIOS chip. |
To see just how sophisticated modern BIOS code has become; using compression and possibly even encrypting its machine code, we've decided to delve into some of the methods used by BIOS manufacturers for our readers. We want you to see how much BIOS code has changed over the decades.
If you have a particular interest in this topic, feel free to write to us about your own PC's BIOS for help in obtaining a copy of what's actually stored in its BIOS chip(s) and/or a BIOS upgrade file.
This section deals primarily with the use of VMWare's BIOS under a Microsoft Windows OS, but our first example here was
originally created by Pete Batard for VMWare users under a linux OS. However, you can use Pete's VMWare bios.rom file just fine
under any Windows XP, 7, 8, 10 or 11 OS!
1) If you do not already have VMWare installed on your Windows PC, you
can get the FREE VMWare Player 17 (not
Workstation) for Windows 10 from TECHSPOT (or Player 12.5.7 for an older CPU / Windows OS) and also for linux.
2)
First, proceed to Pete's webpage for creating your own
BIOS code to run under VMWare and read the interesting discussion on Pete's blog about the steps required for doing so under
linux and how he made his own BIOS file.
3) Then download the file, vmbios-1.0.tgz, under his
"Goodies" section near the bottom. If you don't know how to extract from a .tgz file, you can use the free 7-Zip to do so! (An absolutely fantastic tool for opening almost any compressed file, even
executables and more which I wrote a bit about here concerning the NTFS File System.)
4) In 7-Zip, open the '.tar' file, and finally extract only the bios.rom file into one of your VMWare virtual machine
folders; actually, I'd recommend creating a new minimal VM titled "SerialPort" (or similar) for testing any new BIOS (such as my
own modified versions below) which will write to a text file in that folder.
5) Inside that VM folder, look for its .vmx file, open it in any plain text editor; such
as Notepad (or Notepad++) and add (insert) the following line (including spaces and quote marks) to that file (the location shouldn't
matter, but I put it about 4 or 5 lines below the top in mine):
bios440.filename = "bios.rom"
6) Be sure to add a serial port to the VM's resources (you can name the text file whatever you want):
7) Whatever else you have in that VM; such as an HDD with an OS, doesn't matter, since Pete's "bios.rom" code will go into an endless loop after writing to the serial output text file. NOTE: The VM may first ask if you want to "Append" to or "Replace" that file (then you must power off the VM Guest):
Open the file in the VM's folder and you'll see the "Hello BIOS World!" message.
If you open Pete's bios.rom file with a Hex file editor (we of course, recommend using HxD to do so), the first thing you'll see is the ID string he decided to put at the beginning of his file. (If you feel like it, you could change that; it's not code, and it's never checked.)
Using whatever hex file editor you prefer, jump to offset 0x7F000 (for HxD, use: CTRL + G then enter 7F000). As shown in the pic below, since Pete's code ends with the ASCII message string (and there's plenty of room for a whole page of text), go ahead and modify the string with whatever you wish to print. But, be sure you include a 0x00 byte at the end:
Save your modified file and run the VM again. Now your message should appear in the serial output file.
My Windows 10 PC has the latest Microsoft distribution of ubuntu linux installed; along with all the files necessary to assemble (with GNU as) and create a new "bios.rom" file as described on Pete's blog page. I don't expect everyone who reads this page to do that, but you should be able use (and even modify the string in) the bios2.rom file presented here.
BACKGROUND STORY: For some time I'd been interested in adding (injecting) some extra code into VMWare's Legacy BIOS.440.ROM file in order to see which Port 0x80 Diagnostic Codes it would pass through before attempting to locate a bootable OS. After reading Pete's blog, rather than waiting to learn how to use AS and especially LD to create some suitable code for doing so, I simply replaced some of his instructions with NOPs, copied the code 'as is' to a free area, then 'hacked' a number of the jumps using DOS DEBUG until I was able to get it to spit out a message each time the BIOS code executed an OUT 0x80 instruction.
I'm hopeful that others can learn some things from my slight revision of Pete's code (see bios2.S in the Zip file) as well as how to set a specific location in a .ROM file for execution to jump to! The attached bios2.ld file shows that in order to have execution jump to F000:D500 (offset 0x7D500 in the included bios2.rom file), it was only necessary to change the line beginning with "main_address = " to: main_address = 4096M - 11008; (the "11008" was arrived at by solving: 10000h - 0D500h or: 65,536 - 54,528 = 11,008); the value is straight decimal bytes without any M or K suffix. Download the BIOS2.ZIP file, put the bios2.rom file in your test folder, make sure to edit the .vmx file for the new .ROM file, run the VM and note this code executes as if it were the same; with only a change in its message. Instead of using two 32-bit SHIFT instructions, this .ROM file uses all 16-bit code. I've also included in the ZIP file a disassembly of the code using DOS DEBUG to prove that point.
This section will provide you with everything necessary to understand how to inject some code into the official VMWare BIOS and the reason why I did so: Since the BIOS code runs as an emulation under an already existing OS, there is no possible way to connect a hardware diagnostic card to a PCI bus in order to obtain any possible diagnostic codes. The question being: Was there even such a routine in the BIOS code; or was it a very 'stripped down' version that could never be used with an actual motherboard?
First Step: Locate a copy of the official "BIOS.440.ROM" file. If you have a rather old version of VMWare
Player (or Workstation); such as version 6 or 7, then you should be able to find the following "6006" file here:
C:\Program Files\VMware\.rsrc\BINRES\6006 (The file size will be 512 KiB; exactly 524,288 bytes, and under VMWare 7.1.4
build-385536, the file was dated "March 26, 2011, 12:41 AM".) For those who've downloaded and installed a fairly recent VMWare
Player (versions 16 or 17, for example), you can simply search your system for "BIOS.440.ROM" (using a search tool such as
Everything), but you might find it here:
C:\Program Files (x86)\VMware\VMware Workstation\x64\BIOS.440.ROM (along with a number of other .ROM files). No matter
which file you obtain; either a "6006," or a .ROM, nor what the file's date is, the contents will always be the same! The
BIOS file will have these hash values:
MD5: 88A6E1E0706B8669FF962A22CADBB974
SHA1: 4DEF8FFE004164C8D3EDDF6E921CEF0F7BB7C22B
SHA256: 77416D8CBF98B6DBF68D9AA68222A1D2B8C51D6BAA47AAFE62F5216B41F239B0
Getting to Know the File:
Who made this code?
At offsets 0x74280 through 0x742CD you'll find: "PhoenixBIOS 4.0 Release 6.0" and "Copyright 1985-2001 Phoenix Technologies
Ltd." which indicates the code must have originated with Phoenix Technologies, but there's also the string "Copyright 2000-2020 VMware,
Inc." (at offsets 0x7348B and following) showing that at least some changes were made specifically for WMware which allowed them to copyright
the code. I can't help wondering if the file's copyright expired a couple years ago? Does anyone know for sure? A couple other strings of interest
would be: "Intel Corporation" and "440BX Desktop Reference Platform" (indicating the code was created for the Intel 440 BX
chipset among other possible hardware specifics). In fact, VMware has been telling everyone for years that their VM's emulate the following
hardware:[9]
Intel 440BX-based motherboard
NS338 SIO chipset = PC97338 Super I/O compliant chips
82093AA I/O Advanced Programmable Controller (I/O APIC)
Phoenix BIOS 4.0 Release 6 with VESA (video display) BIOS
I added the Super I/O compliance above, since the tests with Pete Batard's code showed that their means of communicating across Serial
COM ports (listed as a National Semiconductor NS338 Super I/O chip) must be compliant with the more general data sheet he referenced as
PC97338.
Some Recommendations: To further your understanding (though not strictly necessary), unless you have
access to a working Windows XP machine, I'd highly recommend setting up a VMware Player VM of Win XP (SP-3) OS in order to use 16-bit Apps
which are impossible to run under a 64-bit Win OS; this will also allow you to use DOS DEBUG in a
Command window. HOWEVER (and especially for dealing with any 32-bit instructions you will encounter in the BIOS.440.ROM file), I'd highly recommend
adding Enhanced DEBUG to your tools; though it may have some quirks compared to the
orignal DEBUG in some cases, so I wouldn't consider it a fully compatible replacement. An even better way to examine the machine code found
in this file would be to dynamically execute what you can under The Bochs (GUI) Enhanced
Debugger (Bochs does not emulate the same hardware that VMware does, so this BIOS code will fail at some point when run as its
BIOS (you would need to replace the existing "romimage:" line in its .bxrc file with: "romimage:
file="BIOS.440.ROM", address=0xfff80000, options=none # 512k at memory top" - what follows the # sign is a comment).
The Serendipitous Location of one "E9 00 00" Near Jump: If you search the file for all the instances of
"E9 00 00," you'll find over 50 of them! But for our Code Injection Example, the only bytes we are interested in are found at offset 0x7E753 becasue they follow what can be called a motherboard manufacturer's Diagnostic Checkpoint (that is, the x86 Assembly
instruction: OUT 0x80, AL) which sends a chosen Hexadecimal Code out Port 80h. But there is no physical bus to connect a POST (Diagnostic) Card to, so what can we do? Yes, inject our own
routine into the BIOS code that will send those diagnostic codes out a SERIAL PORT instead!
More Details: Of the whole 512 KiB contents of the BIOS.440.ROM file, only the last 16 KiB comprises what's know as the "Boot
Block" (labeled by Phoenix the BB.ROM file when the whole thing is separated into its individual components), and the first 5,802 bytes
of BB.ROM are likely unused padding of zero bytes (from offsets 0x7C000 to possibly 0x7D6A9). This is one of the reasons I chose to inject my code
into offsets 0x7D500 and following (over 416 bytes available; leaving more than enough room for my strings, and also because "D5" looks
like my initials; ;-) ). To find the correct bytes for a 3-byte backwards JMP to offset 0x0D500, DEBUG (or Enhanced DEBUG) users would simply open
DEBUG and enter (GREEN indicating what to enter at DEBUG prompt; Yellow xxxx's would be whatever initial working segment the OS assigned):
-a e753 xxxx:E753 jmp d500 xxxx:E756 [Just press ENTER key here!] -u e753 e755 xxxx:E753 E9AAED JMP D500 ---- |
Creating the Code:
The first time I wrote out this code I made use of MASM 6.15 under a Windows XP VM. I've
made it available here for anyone interested (but it required using a bunch of NOPs that had to be edited
after a .COM file was assembled). So, I've written a linux Assembly file (serial.S) which I'll include with another .ld file and the .ROM
output file below. DESCRIPTION: First, this code preserves the AL byte which the original Phoenix BIOS code would send OUT Port 80h, but I had to
do a little manipulation on it (making it ASCII instead of Hex) before saving it in the DI Register. The rest of the code loops through many of the same
assembly instructions you saw in Pete Batard's code, but TWICE, because I added some instructions to print out that Diagnotic Code value in between. And
of course, the code to return back to the original execution sequence in the VMware BIOS code replaces Pete's endless loop code!
Second Edit: Having made a JMP to location 0x7D500 in your ALT_BIOS.440.ROM file, now it's time to overwrite (not insert) the bytes
at that location with the ROM code you'll find (or create yourself from the assembly files) in this ZIP
file. [ Update: Though not actually necessary, for any future Assembly coders, I revised my Hex to ASCII "hack" with code
that converts the low-end Hex digit (A-F included) to ASCII in this revised serial.S file. Simply
substitute this serial.S file for the one in the previous download, or use the bytes found in the other file (serial.rom.bin) to modify ALT_BIOS.440.ROM; this code is technically 3 bytes longer than the previous ROM output file, but since the
BIOS.440.ROM file is zero-byte 'padded' you don't need to copy and write the last byte.]
This file
has a lot in it: serial.S, the Assembly file for creating the code under linux; serial.ld, the linux LINKER file
which is a necessary part; Makefile, the file linux uses when you enter "make" at a folder prompt with
those 3 files in it, to create the output files! Then, serial.rom, the file my version of linux made from them, as well as a copy of
masm6_serial.com, the binary MASM 6.15 made from the MASM 6 Assembly file I linked to above; MASM6_CODE.txt and
SERIAL_CODE.txt, which allow you to compare the actual machine code bytes both of those assemblers used. Since the VMware BIOS file
is likely still copyrighted, you'll need to finish editing it using the included serial.rom file. This will require a Hex Editor that can
copy hex bytes from one file and then write them into another file (without changing its size; most can do this). The bytes we need to copy are located
offsets 0x7D500 through 0x7D5ED in the serial.rom file; copy those bytes. Open your ALT_BIOS.440.ROM file and set the cursor at offset 0x7D500,
and if you're using HxD, select "Edit" and then "Paste Write" (not 'Insert'). Here's what it should look like at that point:
[ Update: For those who might like some code which is capable of converting any Diagnostic Code from 0x00 to 0xFF into ASCII, you can download serial3.S (and associated files); as before, you can overwrite the BIOS file at offsets 0x7D500 and following with the bytes you'll find in serial3.rom.]
Write those bytes to the file, be sure you have the line bios440.filename = "ALT_BIOS.440.ROM" (or whatever filename
you decided to call it) in the VM's .vmx file, and proceed to test it out. After acknowledging whether you want to replace or append to whatever
file you created for the Serial output, unlike the previous ROMs, which stopped dead, this code should continue to where it doesn't find an OS or boots up
whatever OS you may have already installed in your VM folder. Now look in the folder and open that Serial port textfile. What do you see?
When I tested the first version of my code (not the one you have now), I had to ask, "Why did it stop there?" I already knew how far I
could go when running the BIOS under Bochs, and expected it would provide many more checkpoints, but it didn't! And the more I examine this
VMware BIOS (and hear from others), it seems to be splotches of separated code modules that might never boot an actual motherboard without connecting
more of the code together. I don't have enough factual data to actually make this claim, but it almost seems as if the VMware executable code is overseeing
whether the BIOS should or should not execute certain modules or carry out certain tests. I do know that at one time the minds working on Coreboot
finally decided it wasn't possible to create a useful BIOS ROM for VMware. And recently, I found out there's a section of code in the BIOS ROM made
specifically for communicating with VMware binaries while a VM is running; here's a security article
where you can read more about that (and yes, I verified those instructions do exist in the BIOS.440.ROM file).
For Lab 4 below, we highly recommend reading our page on: Downloading, Installing and Using the IDA 7 Free Version to examine BIOS (and other) files!
Yes, you already know there are some 'Strings' in the BIOS.440.ROM file, but apart from those, it's quite possible for a number of hex bytes (that one could attempt to disassemble as code) to be Data! As an example of such occurrences, search the VMware BIOS file from offsets 0x7E854 through 0x7E8E9, then answer the question: Do you see any kind of pattern? (Hint: In the "Initial Code" link I provided above, you might recall seeing the hex value "E854" before.) If necessary, spend some more time observing the bytes, then (with another hint), try answering: This whole section is basically a Table of Jump Addresses associated with what code you've already seen?
In the Near Future I'd be happy to email anyone about this!
1[Return to Text] On page 8 of the ASUS® CUSL2-C, Intel® 815EP ATX Motherboard, USER'S MANUAL, Revision 1.04 E639, Copyright ©2000 by ASUSTeK Computer Inc., it states: "Equipped with three Dual Inline Memory Module (DIMM) sockets to support PC100/PC133-compliant SDRAMs (available in 64, 128, 256, 512MB densities) up to 512 MB." [Emphasis ours.] Note: The Black Pearl Edition (CUSL2-CBP) was no different; its User Manual has the same note on page 12.
2[Return to Text] On page 9 of the Intel® 815 Chipset Family:, 82815EP and 82815P, Memory Controller Hub
(MCH), March 2001, Document Reference Number: 290693-002, Copyright © 2000,2001 Intel Corporation, under
"Integrated SDRAM Controller" it lists: "32 MB to 512 MB using 16Mb/64Mb/128Mb/256Mb technology". And
on page 50, it quite clearly states: "The maximum supported main
memory capacity is 512 MB." [Emphasis ours.]
3[Return to Text] On page 12 of the
GA-G33M-DS2R/, GA-G33M-S2, LGA775 socket motherboard for Intel®
Core™ processor family/, Intel® Pentium® processor family/Intel® Celeron® processor family, User's
Manual, Rev. 1003, 12ME-G33MD2R-1003R, ©2007 by GIGABYTE™ you'll find: "4 x 1.8V DDR2 DIMM sockets supporting up to 8 GB of system memory."
[Emphasis ours.] The fact that GIGABYTE included four sockets on this board, means we'll only need to purchase DIMMs
of 2 GB each when moving from a 32 to 64-bit OS to take full advantage of that 8 GiB of memory. 4[Return to Text] On page 28 of the Intel® 3 Series Express Chipset, Family, Datasheet, - For the Intel®
82Q35, 82Q33, 82G33 Graphics and Memory Controller Hub (GMCH) and Intel® 82P35 Memory Controller Hub (MCH), August
2007, you'll find: "Using 1 Gb device technologies, the largest
memory capacity possible is 8 GB, assuming Dual Channel Mode with four x8 double sided un-buffered non-ECC DIMM memory
configuration.." [Emphasis ours.] And on page 17: "Supports 1-Gb, 512-Mb DDR2 or DDR3 technologies, for x8 and x16 devices, 8 GB maximum memory."
[Emphasis ours.] 5[Return to Text] See this link for how
the motherboard manufacturer, GIGABYTE®, explains their 6[Return to Text] Technically, this has not been exactly true for a long time. We're still looking for
an Intel 80286 CPU Manual, but can state for certain that for any PC running on an i386 or later CPU, the BIOS chip's first
instruction is actually accessed through address 0xFFFFFFF0. This is just 16 bytes below 4 GiB.
Something to think about: How does code at that high of a Memory location become the same as the 0xFFFF0
20-bit address under a first generation IBM PC processor?
After RESET, address lines A{31-20} are automatically asserted for instruction fetches. This fact,
together with the initial values of CS:IP, causes instruction execution to begin at physical address FFFFFFF0H. Near
(intrasegment) forms of control transfer instructions may be used to pass control to other addresses in the upper 64K
bytes of the address space. The first far (intersegment) JMP or CALL instruction causes A{31-20} to drop low, and the
80386 continues executing instructions in the lower one megabyte of physical memory. This automatic assertion of address
lines A{31-20} allows systems designers to use a ROM at the high end of the address space to initialize the system. We will have a lot more to say about this in the future, and hope to
provide a much clearer explanation using our own memory diagrams, so everyone can understand the process. 7[Return to Text] References: Article on 8[Return to Text] "The ROM is packaged in 24-pin modules and has an access time of 250 ns and a cycle time of
350 ns. .... All memory is parity-checked and consists of 16 K by 1 bit or ([sic]64 K by 1 bit) chips with an access time of 250
ns and a cycle time of 410 ns." Page 1-5, "Section 1: Hardware," IBM Personal Computer Technical Reference
manual, Revised Edition (April, 1983), of the IBM® Personal Computer Hardware Reference Library. 9[Return to Text] Source:
Virtual Machine Chipset and BIOS Support.
DualBIOS™ system.
For example, from the Intel 80386, Programmer's Reference Manual, 1986, on page 176 (of 421), under Section 10.2.3
"First Instructions," we find: David J. Bradley in Wikipedia.
Published: 15 December 2007 (15.12.2007), Revised: 27 September 2010 (27.09.2010).
Updated: 20 October 2010 (20.10.2010), 30 March 2011 (30.03.2011), 22 May 2011 (22.05.2011), 31 May 2011
(31.05.2011), 31 July 2011 (31.07.2011), 21 August 2011 (21.08.2011), 27 June 2012 (27.06.2012), 22 September 2012 (22.09.2012),
12 November 2012 (12.11.2012); 11-12 March 2023 (11-12.03.2023); 16 March 2023 (16.03.2023), update to Serial.S file;
14 March 2023 (14.03.2023), added more History, BIOS details and Lab 4.
Last Update: 20 March 2023 (20.03.2023); some corrections, added Labwork details for DOS VMs.
You can write to us using this: author's
email address. (It opens in a new window.)
MBR and Boot Records
Index
The Starman's Realm Index Page