Practical BIOS Editing
Practical BIOS Editing
by Polygon
of
Rebels Haven Computer Forum
A BIOS is a program that sets register settings in a computer system, that enable it to boot up and
run properly. The file we download and loosely call a BIOS, is in reality the programming medium for
the real BIOS program that is onboard. It is this binary that writes to the volatile memory chip called
CMOS, the settings that we select. Upon boot up, the onboard BIOS program reads the settings from
the CMOS Chip, and sets the system accordingly. The BIOS file we download, is saved in a non-
volatile EEPROM chip that is on the motherboard. Award is up to AWARD6.0 and modern AMI BIOS is
called AMIBIOS8. I will continue the convention of calling the download, a BIOS.
Both AMI and AWARD BIOS are made up of 10-20 binary files called Modules or ROM Modules. Most
are compressed, but a few Modules reside as uncompressed. The BIOS download of a few years back,
were 256K. Modern day BIOS are 512Kb or 1024Kb in size. I suspect in the future, they will grow
even larger.
This screen shot shows the modules in the 256k AN35/N BIOS of just a few years ago, 2004:
Today's most modern P35, DDR3 BIOS, 2007, barely has enough room in 1Meg!:
Using CBROM, we can see the ROM Modules that make up this AWARD BIOS:
0. System BIOS is the main bios program and is the work horse of the BIOS.
1. XGROUP CODE is a extension module as the System BIOS is 128k max.
2. CPU micro code is the info on the CPU's the board supports.
3. ACPI table is all the ACPI information.
4. YGROUP ROM is another extension module
5. Group ROM holds all the text labels for the BIOS
6. SETUP0 holds the format for the BIOS GUI and addresses to the GROUP ROM.
7. OEM0 CODE is a small program file.
8. PCI ROM[A] is the RAID module in this BIOS.
9. PCI ROM[B] is the LAN Boot module in this BIOS.
10. VGA ROM is the VGA BIOS for this boards on-board Video.
11. OEM1 CODE is another small program file.
12. GV3 is Dual Core support module.
13. LOGO is the splash screen we see upon boot up.
All these modules are compressed in this BIOS and usually are in others.
Using MMTool, we can see the ROM Module that make up this AMI BIOS:
The ROM Modules in a AMI BIOS have different names, but by the process of elimination,
most can be identified. The 1B Single Arch Link BIOS is what we call the System BIOS in
the AWARD BIOS. The Multi Language Module is similar to the GROUP Module in the AWARD
BIOS.
While both AWARD and AMI BIOS do the same job, they are very different animals, but we
won't get into that here. The vast majority of information posted relates to AWARD BIOS as
they are the most widespread and have the most software tools for them.
What Do I Need to Mod a BIOS?
Modding a BIOS requires the right programs, or you not going to have success.
1) First needed are the BIOS modding programs. I use Modbin6, CBROM, and a little
program called BIOS Information Tool(bit.exe). "bit.exe" is not working correctly on
newer modern day BIOS, but it still has some use. All 3 programs are discussed, and
linked, in separate topics(Stickys), so I'll assume you'll go find them rather then me
repeat everything here.
3) I've been modding using 32Bit and 64Bit systems in the Command Prompt of
Windows2000 without problem. WinXP seems to work also, but I only tried it once. I also
have been using 64 Bit Conroe systems running Win2000 without issue. The newer BIOS
require newer mod programs, and they are Win32 programs, meaning they will only work
in Windows Command Prompt. As a safety precaution, turn off any program running in
the background like MBM5. Anything the interrupts the CPU while processing a Mod, may
corrupt the BIOS. I discovered this while Video editing, that video files were getting
corrupted. I assume it can happen to a BIOS also...
4) An extra system to perform a "Hot Flash" on. Best would be the exact same board as
your modding a BIOS for. Many boards use the same or equivalent BIOS chip and only a /
F switch is required when using an AWARD flasher to perform a flash on a different board
then the BIOS is for. A "BIOS Saver" is another item that would help getting up and
running again if the BIOS or flash went wrong. I'm not sure if it is still available. A good
option if you don't have a spare system is, to order a few spare BIOS chips from: http://
badflash.com before you start. That way you can do a "Hot Flash" on your test system.
Here's What's Needed for AMI BIOS:
1) First needed are the BIOS modding programs. I use MMTool_312, AMIBCP313, and a
little program called AMIBIOS BIOS Module Manipulation Utility. All 3 programs are linked
in the BIOS Editing Tools Collection. sticky, an some are discussed in separate topics(and
stickys)
2) Items 2-4 above also apply to AMI BIOS, other then use of the AWARD flasher.
Start out by reading the Stickys and all modding topics here and on other BIOS modding
forums linked in a sticky. Go back and read them over until it makes sense and you can
perform the modifications. Read Pinczakko's Guide to Award BIOS Reverse Engineering
and Pinczakko's Guide to Award BIOS Patching several times. I still go through those
articles and pick up something each time. I "practiced" on BIOS's, taking them apart,
making changes, re-inserting ROM Modules, etc. Then looking at them with Modbin or
MMTool, would tell me if the Mod worked. Usually if the BIOS is corrupt or not flashable,
those programs won't open the newly modded BIOS. I also took apart other peoples
modded BIOS's to see what that author did.
BIOS Modding is something that takes a while to grasp, and only an undying interest and
drive, will lead you to a successful understanding of BIOS modding. This is not something
you are going to learn overnight....
"Hot Flashing" means preparing a known good system ready to be flashed in the DOS "Real Mode". Then swap
the "good" BIOS EEPROM with the "bad" one while the power is on. Then flash the "bad" chip with the desired
BIOS, and then turn the system off and swap the now good BIOS chip, back into the dead system. Sounds easy,
right!
First off, the medium that your using to get into the DOS "Real Mode", must already contain the desired BIOS
and flash utility. You copy those on in advance. This requires a 3.5" drive or a bootable CD.
Second, if the 2 systems are not exactly the same, the /F switch must be used in order that the flashing utility
ignores the fact that the BIOS being flashed, is not for that board. So the command line would look like:
When doing a "Hot Flash" on a different board, one must make sure the BIOS EEPROM chip is the same or at
least compatible with the other system. I have checked 6 of my boards(nF3, 2-nF4, ATI482, 6100, nF550) and
they all have the same chip, but made by different manufacturers. The other way to do it if you don't have a 2nd
system, is buy a spare BIOS chip in advance. Also, do not use any switches other then the /F switch when hot
flashing on a different board then the BIOS is for.
If a Hot Flash isn't for you or you need a spare BIOS chip, http://badflash.com can help you out. They supply pre-
programmed chips or blank chips. Your choice....
After having to do 15-20 Hot Flashes in the last 2 weeks, I found that a spare drive that is formatted on a
Win98SE system as a Boot Disc, to be invaluable...
I have a 450Meg HDD left over from the "Old Days" that I formatted as a boot disk. On that drive I loaded BIOS's
for each system that I use to test mod BIOS's on... Each board(6100-939 for example) has it own directory that
is named for that board...
When it's time to Hot Flash, I plug the drive in as a Master on the working system, bootup and get ready to flash
from the "C" drive after navigating to the correct directory in DOS. I then swap in the bad BIOS chip, and flash
using the "/F" switch...
One more tip about Hot Flashing, with the power removed, remove the BIOS chip from both systems, once or
twice, to loosen the spring clips... I've been using a small paper clip that is totally straightened out and has the
very ends bent at a right angle. The little bent end just fits in the openings at the corners of the BIOS chip. The
paper clip is then bent into a "U" shape to use for removing the BIOS chip... One must be very careful when
removing the chip with power on....
Here's a commercial chip extractor on the left and my paperclip version:
I've found that many of the boards I have bought in the last 2 years use the exact same BIOS chip. The numbers
are slightly different if made by different chip makers, but a quick check of cross reference lists, shows they are
the same. Most today are 4meg, 33Mhz chips and have part numbers like: 49FL004T-33JC... Some of the AM2
boards and some of Conroe boards use 8Meg BIOS chips. They will look like: 49FL008T-33JC...
Lifted from another thread on setting up one's HDD for easy flashing:
1) I have a Win98SE system that has a 3½" Floppy drive, to make boot disks. I also have a formatted HDD that
is a Win98SE boot disk. I load my BIOS to be flashed on it and do the flash in DOS "Real Mode" by just letting the
system boot up. Re "DOS Real Mode", Google, if you don't know what that is. Bootdisk.com has a wealth of
information on making boot disks on both 3½" Floppies and CD's.
2) I format a Hard Drive on a Win98SE machine and also select "Copy System Files"... The drive must already
have an "active" partition that was enabled either with "Fdisk" or a Partition Manager.... When finished, the drive
now is a "Boot Disc"... Installing the drive in a system and booting, the DOS Prompt of Win98SE would come
up....
I then copy Win2000, the mainboard CD, and several other programs that I always use into a "Temp" folder...
I then install the drive in the test system and load Win2000 by executing "winnt" that is in the i386 folder of the
copied-to-the-drive, Win2000 installation CD. The install goes fine and your license and key number are entered
normally. Now if the system ever wants a file from the install CD, it's on the system already....
After the OS is installed, and the mainboard drivers are installed, upon boot up, Windows stops and asks which
Operating System do you want to boot off of... When you select "previous", you end up at a Real Mode DOS
prompt. Now you can flash BIOS after BIOS that you saved in a special directory, and on the next boot, select
Win2000 for the test runs... A full discussion on the topic is here...
Originally posted by flycaster51:
quote:
Question, must the two boards have the same chipset? Does the /F switch force the flash even if the
chipsets are different?
Yes it does. The chipset has nothing to do with the flash, but I'll qualify that at the end....
I have flashed Conroe BIOS on AM2 boards and every other combo one can think of with no problem using the "/
F" switch. All different chipsets. Doesn't matter. And, out of all the 30 or so boards I have tested in the last 3
years, there were only 2 different BIOS chips. 4Meg and 8Meg. Different manufacturers, but the chips are
equivalent. There are cross reference PDF's on the net and it's pretty easy to see if they are the same. My 2nd
post goes into that a little.
Now the chipset thing. The new nVidia 680i Reference Board uses a slightly more advanced BIOS chip and when
flashed using the nVidia flasher, it looks for the chipset! It seems to carry the MAC address with the BIOS. If you
take a new AWARD flasher, and execute it with the "/?" switch, at the end is says it supports nVidia blah-blah-
blah chipset something or another.
I tried using the nVidia flasher on a AM2 board to flash the 680i BIOS and it complained the chipset was wrong! I
used a AWARD flasher with "/F" and while it flashed, it would not POST on the 680i! On the 680i if the "/F" is
used, AWD870(the latest) halts and does not finish the flash..... A 680i BIOS chip can only be Hot Flashed on the
680i board, it seems. But either nVidia or AWARD flasher will work. Today, one must always have a spare BIOS
chip if your doing lots of flashes and experimenting. That is why I linked badflash.com...
So, new systems bring new issues, but aside from that issue, the chipset doesn't seen to matter with the Hot
Flash.....
I want to point out that my reply is relative to S939 systems and newer only. Before S939, I haven't looked at,
and probably won't......
I bought some blank SST49LF004B-33-4C-NHE BIOS chips and have found some quirks that are worth
mentioning. The "E" at the end means the chip is made with lead-free materials.
1) A blank BIOS chip cannot be flashed with the /F switch. The flasher just freezes.
2) A blank BIOS chip must be first flashed with a BIOS that is for the host system. Then the desired BIOS for
another system can be flashed using the /F switch.
3) The PM49FL004T-33JCE appears to be the newest chip and is backwards compatible to the others on the list.
The SST49LF004B-33-4C-NHE appears not to be forward compatible, but the SST49LF040B-33-4C-NHE probably
is.
4) Newer boards won't flash certain older BIOS chips.
Remember you are using this information entirely at your own risk. The information
presented may not work for you. If you are not comfortable modifying BIOS's and flashing
them, do not attempt to modify them. You must be able to recover from a "bad" flash.
Is My BIOS Good to Flash?
A few members that are interested in BIOS modding have asked "How Do I Know the BIOS Will
Work?"
In a word, you don't! You must be prepared to do a "Hot Flash" or use a "BIOS Saver" if it's still
available....
A minor verification that can be performed is to re-open the modded BIOS with Modbin6. If
anything is wrong, Modbin6 will display non-alphanumeric characters in the "Edit Setup Screen"
window and/or in other windows. If anything major is wrong, Modbin6 will crash. These are sure
signs that whatever was done, is no good and may render a dead computer if flashed.... Also, not
all BIOS's can be modified with Modbin6. Again, the sure sign to leave well enough alone is, seeing
strange characters in the "Edit Setup Screen" window even before trying the Mod.
If the BIOS is corrupt, you MAY see something like this when escaping out of one of the message
windows:
But like everything, there are exceptions to any rule. Brand new motherboards using 680i, P35, P965, etc chipset,
have BIOS that are corrupted when saved in Modbin6. These will re-open and appear to be OK, but in fact are
corrupt because the latest version of Modbin6 was written before those new BIOS were designed. They have
modules and requirements Modbin6 was not designed for. We need a new updated Modbin6 version.
Using Modbin6
Post questions in the Modbin Discussion Thread
Modbin6 should be run in the "Command Prompt" of Win2000 or XP. It probably will work in Vista also. The subject BIOS
and Modbin6 should be in a directory by themselves when using Modbin6. Depending on the other files names and
extensions that might be in your working directory, the apparent corruption can occur, so don't include any other file not
necessary.
If the un-zipped BIOS file does not have a ".bin" extension, at the command prompt, type and enter: Modbin6 xxxxx.yyy
where xxxxx.yyy represents the actual BIOS file name and extension. Or simply edit the file name to end in ".bin" as all
BIOS files are binary files. Create a separate directory and place the BIOS .bin files and Modbin6 in it and nothing else. I
use a single letter for the directory so then when in the Command Prompt, I have to do a minimum of typing.
The latest available Modbin6 that works for the latest AWARD BIOS, is Linked here:
Modbin6 Version 2.01.02
Selecting "Change BIOS Message", allows one to display anything at the start of POST.
A maximum of 79 characters is the limit:
Selecting "Change BIOS Option", opens a dialog box to select BIOS timing or BIOS option:
Selecting "Change BIOS Option", opens a dialog box to select BIOS timing or BIOS option:
Change BIOS Option, Change BIOS Timing usage, is unknown to me at this time:
Change BIOS Option, Change BIOS Timing usage is unknown to me at this time:
Here we're going to use the menu functions. Pressing "Alt+F" or "Alt+T" or "Alt+H" cause
a dialog box to open. "Alt+F" opens the "File" dropdown box:
"Alt+T" opens the "Tools" dropdown box:
Selecting the "Chipset Register Defaults" opens what appears to be access to all the chipset registers.
The exact capability of this window is unknown right now:
"Alt+H" opens the "Help" dropdown box:
One of the most useful things Modbin6 can do, is to change default BIOS Item settings, or unhide "hidden" settings.
"Hidden" settings are "grayed" out. When selected, various settings become available after pressing "enter":
Here we're going to change Trp from 2T to 4T. 2T is too tight for a default and at 4T, it will match Trcd which is already 4T.
Upon pressing "enter", a window opens and when selected, the setting can be changed using the +/- keys.
If when selected, "enter" is pressed, the available settings are displayed. Also the nomenclature
for the setting could be changed if desired at this point:
Here we have changed both the BIOS default and Setup default Trp to be 4T as a default. All that is left to do is save the
changes. Note that a new file name is required, else the mod BIOS may not be saved:
Here we're going to "unhide" the 183 Divider from a MSI Neo4 Platinum BIOS:
Upon pressing "enter" after selecting the "Max Memlock" Item, a window opens and displays the BIOS default of 200:
Upon pressing "enter", the available settings are displayed. Note that the 183 setting is "Non-Selectable":
Here we have changed the 183 Divider setting to "Selectable" by using the down arrow, and pressing the + key when the
status was selected. Note that both the "BIOS default" and the "Setup default" must be changed. Sometimes changing
one, changes the other. Remember to save the BIOS file as a new name, or it may not be changed. It's a good idea to
save the file from the "Setup Screen Structure Tree" by pressing "Alt+f", and then selecting "save" or "save as":
Note that some BIOS's don't allow changing the "select ability" from Modbin6. See this topic for other methods.
Here we're going to move a BIOS Item that the BIOS Engineer put in a poor spot. This BIOS has the "Cool N' Quiet"
option under Power Management. I'm going to move it to be above the "Spread Spectrum" option as for Overclocking, we
always turn them off...
I've selected the Item to be moved and pressed the space bar. This highlights the option. Note that if we want to move 2
or more Items at the same time, we just highlight them before pressing "insert" where we want them:
Here I've selected where I want the Item to be moved to. This process will place the Item above the Item I've selected:
Pressing the "Insert" key does exactly that. The "Cool N' Quiet" Item is now above the "Spread Spectrum" Item and much
easier to find. It's a good idea to save the file from the "Setup Screen Structure Tree" by pressing "Alt+f", and then
selecting "save" or "save as":
In general, I've found that it is best to try the moves early on in the mod process, and keep backups of every successful
move. The key seems to be moving one Item at-a-time, but even that is not foolproof! Look thru the Setup Screen in
Modbin6 to make sure everything is in the correct position. If it is, make a backup. Like other BIOS Mod techniques, it's a
lot of trial and error, and can take lots of time.
Edit:
A better way to move items, is change their "Position Code" to that of where you want the Item. Several Items can have
the exact same "Position Code". Thanks to luk1999 whose suggestion works perfectly!
Here is a area of interest:
If I move too many items around, that area looks like this: Here is a area of interest:
If I move too many items around, that area looks like this:
And under this heading, we now have things that don't belong:
Edit: I mistakenly flashed a BIOS that had the display screwed up as above by making to many
moves Modbin6 didn't like. The BIOS works perfectly and when running on the system, everything
is in the correct place....
Edit, Edit: A few days later I can't get the exact same BIOS to mess up the display no matter how
many moves I make. I believe, at least with respect to this issue, it's a Modbin6 issue and not
real. If the BIOS can be opened with Modbin6, the chances are excellent the BIOS is not corrupt.
Similar to moving a BIOS Item, we can create a new branch for grouping of similar Items. In this
example, I'm going to group all the Spread Spectrums under 1 heading. There are 2 more in this
BIOS, but because they are under a heading that can be Enabled or Disabled, I'm leaving them
out.
Here I've highlighted the 2 Items to be moved by pressing the Space bar after selecting them:
Here I've navigated down to a unused heading:
To create the new branch, we press "Alt+C" and the branch is created, but with no title:
Navigating up to the title-less heading, we press enter twice and
we're in the edit mode and label the heading:
Oddly enough, the new heading is darkened out and we have to select it and
press "+" to make it visible in the BIOS.
After that we press the space bar to highlight the branch for a move:
Here we have navigated up to where we want the new branch to be, and we pressed insert.
Note that like a individual Item, the branch is inserted above the cursor position:
If the BIOS is corrupt, you may see something like this when escaping out of one of
the message windows, or the BIOS will just not open with Modbin6 any more:
I modded a BIOS with the "Spread Spectrums" branch that was created with "Alt+C" and it flashed fine. Only issues are:
1) The new branch should be added to a unused Item branch. If added to a existing Item, it screws things up.
2) The top entry is grayed out if you do not turn it "on" by selecting the sub-items 1-at-a-time and pressing the "+" key.
Then the branch itself must be turned "on" the same way.
3) Regular branches have [Press Enter] to the right of the branch title. It's unknown how to add that. In the "_EN_CODE.
BIN" module where "Spread Spectrums" is now located, the "00h" to the right of it can be moved over to make more
room for a longer title. But this does not work with regular existing branches. Probably a better way is to use a existing
branch and moving the sub-items in and out 1-at-a-time. That way the [Press Enter] is already there.
Update: 8/20/07
From our work outlined in the Hacking The _ITEM.BIN Module And It's Interaction With _EN_CODE.BIN topic, I have found
a way to add the [Press Enter] on new branches!
Here I have selected 4 Items to put under a unused branch:
I've gone in and labeled it "Spread Spectrums" and enabled it as it was disabled by default:
[Press Enter]
Now for the [Press Enter] I found an existing branch and disabled it to be able to locate it's sequence. I've found some
very interesting things in it's sequence. First off. it only has 1 mask. Secondly, it has 00h for the number of selections, but
has a selection label address that ultimately points to the "Press Enter" label in it's _EN_CODE.BIN module:
I edited the new "Spread Spectrums" branch sequence to have 00h selections and have it's label address pointer point to
where "Press Enter" is located in the _en_code.bin module.
Success! We now can make an unused branch look just like every other branch The branch can be moved to a logical
place at this point, if desired.
Using Modbin6 as a ROM Module Editor
Here's a neat little trick I stumbled across when trying to mod a BIOS that Modbin would corrupt upon saving.
Use Modbin6 as a Module Editor. What, you say! OK, here it is. Go into the BIOS using Modbin6 and make the changes
like unhiding, changing default settings, and changing to selectable as many Items/Options as desired. Save the BIOS. It
will be corrupt if it's one of those new "un-Modbin-able" BIOS. Usually the boot block or something is screwed up is why it
is now corrupt. But the internal ROM Modules are fine
Now take the corrupt modded BIOS and extract the _ITEM.BIN and _EN_CODE.BIN modules. These hold the selectability,
hidden/unhidden and default settings.
Now take an unmodded BIOS and release the _ITEM.BIN and _EN_CODE.BIN modules using the latest CBROM program.
Copy the modded _ITEM.BIN and _EN_CODE.BIN modules to the directory where your releasing those unmodded
versions, and inject the modded ones. And your done! CBROM fixes the checksum.
One issue I did run into was that a certain BIOS wanted the ROM modules to be in the exact order they were originally.
You see, injecting a single module, puts it in, last in line, but at the correct address. OK, so release them all up to and
including the _ITEM.BIN and _EN_CODE.BIN modules. Now inject them back in, in the original order. The /D switch with
CBROM displays the order when used with a unmodded BIOS.
1) In a separate directory, Modbin6 the desired options in the BIOS of interest. Do the minimum needed.
2) Extract _en_code.bin and _item.bin using CBRom 1.55
3) In a different directory, extract and then release, each module starting at the last module, until the _en_code.bin and
_item.bin are reached, but don't extract those 2 modules. Just release them. Save a copy of this BIOS shell in case we
need to redo the mod.
4) Copy the _en_code.bin and _item.bin into the second directory from the 1st directory. These contain the Mods.
5) Insert the modules back into the BIOS using CBRom 1.55 in the exact reverse order that they were released. I make a
copy of the results of: CBRom bios.bin /D to use for reference.
6) Flash the BIOS and make sure all options are saved when selected. I have found a BIOS where the voltage settings
weren't saved when certain mods were made. If the BIOS does not work properly, redo step 1 & 2 with less mods until
the BIOS works. This can take dozens of try's and ten's of hours.
Edit: I found out later that CBROM 1.82 allowed the _ITEM.BIN and _EN_CODE.BIN to be released and replaced without
any other module manipulation.
Modbin6 v2.04.01
Modbin6 v2.04.01 has the ability to modify the latest BIOS without corruption.
See follow-on posts.I got a chance to play with Modbin6 v2.04.01 dated 2/17/2007.
Everything looks about the same as the previous versions, other then the black background
and the "stars" in the "Setup Screen" Here's some screen shots:
One thing I don't like is you can't tell if a Item is hidden unless you go into it. The coloring never changes with hide/
unhide settings.
When we go to save, we notice the same message that the latest CBROM issues. "-Adding MEMINIT.BIN 100%" This
module has something to do with memory mapping I believe. It is extracted and re-inserted by both CBROM and Modbin
recent versions.
The temp files now include several that CBROM 1.82 generates. The file "P35BA521.bin" is the BIOS I modified during this
session.
If both Modbin 2.04.01 and CBROM 1.82 are going to be used on a BIOS, Modbin must be used first. If CBROM is used
first, Modbin will(may) crash when trying to save the modified BIOS.
Remember you are using these programs entirely at your own risk. The information
presented may not work for you. If you are not comfortable modifying BIOS's and
flashing them, do not attempt to modify them.
Using CBROMxxx(AWARD Only)
The CBROM Discussion thread is here....
CBROM2xx is to be used in the DOS "Real Mode", which means a Win98 Boot disk is required. I successfully use the "Command
Prompt" of Win2000, as CBROM32 will only work in the "Command Prompt" of Win98, Win2K, and XP. This is CBROM v1.40 and
newer.
CBROM32 will fix the BIOS checksum when inserting a module, but it will not fix the checksum of the module. Not all modules
require a checksum.
If the un-zipped BIOS file does not have a ".bin" extension, you can simply edit the file name to end in .bin, but it's not
necessary.... If a ROM module type being operated on has more then in the BIOS, a prompt will appear for you to chose the
desired one.
The latest CBROMxxx versions that work for the latest AWARD BIOS, are linked here:
CBROM215
CBROM217A
CBROM219
CBROM220
CBROM32_140
CBROM32_149
CBROM_155
CBROM_1.55.1
CBROM 1.82
Be aware that CBROM 1.40, 1.49, 1.55, 1.55.1, and 1.82 are all Win32 programs and do not work in pure, real mode DOS, only
a Command Prompt Window.
CBROM32_140 has a slightly different command set as this screen shot shows:
Anyhow, the last few versions all work the same. So operating on a module like "_EN_CODE.BIN" with CBROM32, the switch to
use is /group. Execute at the command prompt the following, depending on what your doing:
Extract rom:
cbrom32 xxxx.bin /group extract
Add rom:
cbrom32 xxxx.bin /group _EN_CODE.BIN
When adding a module to a BIOS, CBROM generates a file called "bios.rom". That is the added module in compressed form. We
will find this file useful later on when modifing the system bios module.
Note that you don't need to perform a "save", as the file being worked on is on the drive and changed immediately. Also open
the newly modded BIOS in Modbin6, make a minor change, and save. Modbin will fix any checksum issues when it saves.
Remember you are using this information entirely at your own risk. The information presented may not
work for you. If you are not comfortable modifying BIOS's and flashing them, do not attempt to modify
them. You must be able to recover from a "bad" flash.
Thanks to our friend "Compiller" we have a new version of the ASUS CBROM!
It is linked here: ASUS CBROM115.zip
For some as yet unknown reason, some BIOS's don't allowing changing an option to "Selectable" in Modbin6. With the cursor highlighting "Non-
Selectable" title, the "Plus(+)" key is pressed, and the status changes to "Selectable". Problem is that after exiting and then re-entering, the
option is back to "Non-Selectable". Here is the Modbin6 window referred to:
This issue, and attempting to "Name" a blank option, has led me into hex-editing the "_EN_CODE.BIN" module contained in all AWARD BIOS.
Notice in the above screen shot that the "150Mhz" option has no title, and Modbin6 doesn't appear to be able to edit a title into that blank space.
First the issue of being "Selectable". At least half the BIOS I ever tried to work with, won't retain the "Selectable" setting when saving and
exiting. But, many do. For those that don't, I found that by setting the bit directly after the setting in the "_EN_CODE.BIN" module, the option
was then always "Selectable". I have highlighted the "offending" bit. When set to 01h the item is "Non-Selectable". When set to 00h the item is
"Selectable". The second screen shot below shows that "trailing" bit on another already selectable option.
The extraction(release) and replacement of the _EN_CODE.BIN BIOS module was performed with Cbrom32. See this topic...
Now to "Naming" the option....
We remember this screen shot from the above post with no "Name" or "Title" for the 150Mhz option:
Looking at the "_EN_CODE.BIN" BIOS module with the Hex-Editor, we find a "space for the "150Mhz" title, but nothing is there. I did try opening
that space by 6 Bits and inserted the "Name", but evidently the BIOS has only just so much room for this option, and it screwed up everything
else. Here's the "Space" highlighted:
The obvious solution to me was to enter the "150Mhz" title and leave something else blank. That way the total space allotment for this option
would remain the same. I chose the 216Mhz(DDR233) as the setting to eliminate. Here's what the new "_EN_CODE.BIN module looks like with
the 150Mhz option now having a title. (Note that the cursor is not on the 300Mhz line, but 4 lines lower then where I'm referring to):
Looking back at the BIOS with Modbin6, the option is now "Selectable" and complete with a title:
Note that the removing and replacing of the "_EN_CODE.BIN" BIOS module requires use of the BIOS Tool "CBROM32.exe"
See Using CBROMxxx. EXE for details....
I looked at 2 different BIOS's. One had the ability to have options to be made "Selectable", and the other would not keep
or "hold" the selectable setting....
Again here are 2 non-selectable settings with the trailing "01" byte(I've switched to Hex Workshop):
Reviewing the "_EN_CODE.BIN" file from each BIOS, there was no obvious differences in the coding used. The "lock" on selectability must be in
some other BIOS module...
In looking at the whole problem of not having enough room to add the 150Mhz nomenclature to the BIOS, it became obvious that with only so
many bits of space available, it was time to save some space.
In the screen shot below of the 1C0 MSI Neo4 Platinum BIOS, I got rid of the "Mhz" after each entry and then had plenty of room to have all
available settings "selectable". I put spaces in front of every entry in an effort to fill the available space, but it now appears that the spaces could
go almost anywhere.....
Here I've highlighted the whole group of bit's that were available for the "Maxmemlock" titles. Note that you must keep the exact same number
of entries. Adding 1 or leaving 1 out will cause the rest of the setup screen to be garbage and render the BIOS corrupt. Also note that the
apparent spaces for titles before "100Mhz" and after "250Mhz" would lead you to believe 66Mhz and 266Mhz are also options. Having tried both,
I can tell you that the "66" setting freezes the system, and the "250" setting isn't visible, no matter what the bits are set to:
In looking at an older MSI BIOS from 2002, I notice that many of the "Naming" and "Selectability" options are in the System BIOS and others
are in the _EN_CODE.BIN file. Newer BIOS apparently have all the names or labels in the _EN_CODE.BIN file.
Here I'm looking at the System BIOS which was generated by running Modbin6 on the target BIOS. It produces a file called "Original.bin" when
running Modbin6. It is the System BIOS available for modification. See Using Modbin6 topic.
I have highlighted a hidden option's trailing byte, that is the tell-tale 01h, immediately after the "name", meaning it's "non-selectable". Directly
above the highlight is another hidden option with 01h trailing the "name".... In trying to modify the Original.Bin file and then saving, the options
are still "non-selectable" because the trailing bytes are still 01h. Modbin6 isn't saving the Original.Bin on this BIOS for some reason, but I'd be
willing to bet it works on some BIOS or with a different Modbin version. I was able to enable the options in Modbin6 by selecting them and
pressing the "+" key..
Adding A Little More Room For The Title or Labels!
In another thread, Hacking The _ITEM.BIN Module, member luk1999 uncovered information about the _EN_CODE.BIN Module which lead us to
be able to add a little space to the labeling in the _EN_CODE.BIN Module. Turns out that the "starts" are defined in the binary data that directly
follows a group.
Here's a segment from the _ITEM.BIN Module that is in a BIOS I've been working with. It's for the Biostar 6100-939. This is the mod BIOS with
the added Memclk settings of 120 and 140Mhz. I'm hoping to get it working. It's the sequence for the Memclk Item in the CU51M811 BIOS:
The top picture shows where the Item label starts. I'm pointing to the location bytes at the end of the group in the _EN_CODE module and Hex
Workshops location of that byte. The bottom picture has all the byte locations for the Items in this group up to the Item of interest highlighted.
There are 19 of them. Then circled in the middle picture is the location # of the Memclk in hex(13h), which is 19. For anyone following along,
the binary/hex files use "Little Endian" notation, meaning least significant bytes are first. So 45B7h is B745 in the file.
From the information learned in the Hacking the _ITEM.BIN topic, we can now clean up our added settings so that they look truly professional.
Here is a screen shot of the business end of the _EN_CODE.BIN module. In the top part, I have highlighted the entire section of code that labels
the Memclock Frequency settings. In the bottom part, is highlighted the address of the 1st letter of the labels, "A" of Auto. The hex entry before
the address for the "A", is the address for the "M" of Memclock Frequency. Remember that BIOS modules use "Little Endian" notation, meaning
least significant bytes are first. So 45B7h is B745 in the picture. The key to a nice BIOS presentation shown below, is the fact that all labels
occupy the same number of places. That is 4 in this case. Be aware that more spaces can not be added. We must use what is available. We
could have abbreviated the "Memclock Frequency" to gain room, just as long as the addresses were corrected. If a space or 2 in front of the "A"
would have helped, just changing the address of the "A" would take care of the spaces.
Here is the finished product. Never before seen BIOS settings in the Max Memclk Frequency Item:
Here is the bottom section of the selections:
Adding More Bytes!
Here's a little trick that may help in the future. For a variety of reasons, we may want different labeling on a Item's option settings, but can't fit
it in the space it's presently occupying.
Let's add the new labels to the end of the _EN_CODE.BIN module. Adding bytes at the end of the module, does not affect any of the addresses
that are already listed in the module. I'm sure at some point adding bytes will cause a problem, but my example added about 80 bytes and the
BIOS works fine. Here we have selected Tras as the test Item. The top of the screen shot shows the first address for the Item's title as 460Ah.
The bottom of the screen shot shows I have already changed the 2 addresses for the Item's title and the settings labels:
Here is the results. I changed many of the numbers to letters so I could see that the technique works. I had finished the row with a series of
nulls(00h) as that is what is between the stock labels. I then added my new labels and finished the task with a few spaces(2020h). Probably
nulls would have be fine also:
And entering the BIOS after flashing the Mod BIOS, we see my test pattern of letters then numbers:
Note that I didn't need to move both Item title and the settings labels. If only one needed to be moved, that would be fine. Also, I did nothing to
correct the checksum of the _EN_CODE.BIN module. From previous work here, it appears to be un-necessary.
Remember you are using this information entirely at your own risk. The information presented may not work for you.
If you are not comfortable modifying BIOS's and flashing them, do not attempt to modify them. You must be able to
recover from a "bad" flash.
"Little Endian" Notation
Intel(IBM Compatible) uses what is called "Little Endian" Notation. That means that the least significant digits are
displayed first. So, the decimal number 1428, which is 0594h in Hex, will be displayed as 9405h in the binary file.
Definitions:
Big Endian
Within a given multi-byte numeric representation, the most significant byte has the lowest address (the word is stored
"big-end-first"). This notation is also referred to as "Motorola type".
Little Endian
A given 16- or 32-bit word, bytes at lower addresses have lower significance (the word is stored "little-end-first"). This
notation is also referred to as "swapped bytes" or "Intel type".
In this _EN_CODE.BIN module is a perfect example of "Little Endian" notation. The very 1st address in the _EN_CODE.
bin main address list is 9405h, but it really points to 0594h in this BIOS module.
Tictac's AMD Athlon 64 DDR ROM Patcher Rev 3.0.1
Any questions, comments, etc on this code should be posted in the:
Building a ISA Option ROM Discussion Thread
Download Source Code
Or:
code:
;---------------------------------------------------------------------------------------------------
; AMD Athlon 64 DDR ROM Patcher Rev 3.0
;---------------------------------------------------------------------------------------------------
;
; Source code writen by tictac
; Website : z6.invisionfree.com/tictac
; Note : Free to be distribute/mod , Use it at your own risk
;
;---------------------------------------------------------------------------------------------------
;------------------------------CODE
DEFINITION------------------------------------------------------
;---------------------------------------------------------------------------------------------------
use16 ; 16bit mode
address equ 0CF8h ; address port
data equ 0CFCh ; data port
;---------------------------------------------------------------------
; DRAM Timing Low Address
;---------------------------------------------------------------------
; CAS Latency(dtl)
tcl equ dtl_add
tcl_data equ 0FFFFFFF8h ; CAS Latency (3bit)
tcl_2 equ 000000001h ; CAS 2
tcl_25 equ 000000005h ; CAS 2.5
tcl_3 equ 000000002h ; CAS 3
;---------------------------------------------------------------------
; DRAM Timing High Address
;---------------------------------------------------------------------
; Write to read delay(dth)
twtr equ dth_add
twtr_data equ 0FFFFFFFEh ; Write to read delay (1bit)
twtr_1 equ 000000001h ; 1 clock
twtr_2 equ 000000002h ; 2 clock
; Refresh Rate(dth)
tref equ dth_add
tref_data equ 0FFFFE0FFh ; Refresh Rate (5bit)
tref_100_156 equ 000000000h ; 100MHz 15.6us
tref_133_156 equ 000000100h ; 133MHz 15.6us
tref_166_156 equ 000000200h ; 166MHz 15.6us
tref_200_156 equ 000000300h ; 200MHz 15.6us
tref_100_78 equ 000000800h ; 100MHz 7.8us
tref_133_78 equ 000000900h ; 133MHz 7.8us
tref_166_78 equ 000000A00h ; 166MHz 7.8us
tref_200_78 equ 000000B00h ; 200MHz 7.8us
tref_100_39 equ 000001000h ; 100MHz 3.9us
tref_133_39 equ 000001100h ; 133MHz 3.9us
tref_166_39 equ 000001200h ; 166MHz 3.9us
tref_200_39 equ 000001300h ; 200MHz 3.9us
;---------------------------------------------------------------------
; DRAM Configuration Low Address
;---------------------------------------------------------------------
; DLL Disabled(dcl)
dll equ dcl_add
dll_data equ 0FFFFFFFEh ; DLL disabled (1bit)
dll_enable equ 000000000h ; Enabled(default)
dll_disable equ 000000001h ; Disabled
; Bypass Max(dcl)
bpm equ dcl_add
bpm_data equ 0F1FFFFFFh ; Bypass Max (3bit)
bpm_0x equ 000000000h ; 0x (Disabled)
bpm_1x equ 002000000h ; 1x
bpm_2x equ 004000000h ; 2x
bpm_3x equ 006000000h ; 3x
bpm_4x equ 008000000h ; 4x
bpm_5x equ 00A000000h ; 5x
bpm_6x equ 00C000000h ; 6x
bpm_7x equ 00E000000h ; 7x
; Command Rate(dcl)
rc equ dcl_add
cr_data equ 0EFFFFFFFh ; Command Rate (1bit)
cr_1t equ 000000000h ; 1T
cr_2t equ 010000000h ; 2T
;---------------------------------------------------------------------
; DRAM Configuration High Address
;---------------------------------------------------------------------
; Maximum Async Latency(dch)
async equ dch_add
async_data equ 0FFFFFFF0h ; Maximum Async Latency (4bit)
async_0 equ 000000000h ; 0 ns
async_1 equ 000000001h ; 1 ns
async_2 equ 000000002h ; 2 ns
async_3 equ 000000003h ; 3 ns
async_4 equ 000000004h ; 4 ns
async_5 equ 000000005h ; 5 ns
async_6 equ 000000006h ; 6 ns
async_7 equ 000000007h ; 7 ns
async_8 equ 000000008h ; 8 ns
async_9 equ 000000009h ; 9 ns
async_10 equ 00000000Ah ; 10ns
async_11 equ 00000000Bh ; 11ns
async_12 equ 00000000Ch ; 12ns
async_13 equ 00000000Dh ; 13ns
async_14 equ 00000000Eh ; 14ns
async_15 equ 00000000Fh ; 15ns
; Read Preamble(dch)
rp equ dch_add
rp_data equ 0FFFFF0FFh ; Read Preamble (4bit)
rp_20 equ 000000000h ; 2.0ns
rp_25 equ 000000100h ; 2.5ns
rp_30 equ 000000200h ; 3.0ns
rp_35 equ 000000300h ; 3.5ns
rp_40 equ 000000400h ; 4.0ns
rp_45 equ 000000500h ; 4.5ns
rp_50 equ 000000600h ; 5.0ns
rp_55 equ 000000700h ; 5.5ns
rp_60 equ 000000800h ; 6.0ns
rp_65 equ 000000900h ; 6.5ns
rp_70 equ 000000A00h ; 7.0ns
rp_75 equ 000000B00h ; 7.5ns
rp_80 equ 000000C00h ; 8.0ns
rp_85 equ 000000D00h ; 8.5ns
rp_90 equ 000000E00h ; 9.0ns
rp_95 equ 000000F00h ; 9.5ns
;---------------------------------------------------------------------
; DRAM DQS Delay Line Register
;---------------------------------------------------------------------
; DQS Slew Value(ddr)
dqs equ ddr_add
dqs_data equ 0FF00FFFFh ; Delay Line Adjust (8bit)
dqs_1 equ 000010000h ; 1
dqs_2 equ 000020000h ; 2
dqs_3 equ 000030000h ; 3
dqs_4 equ 000040000h ; 4
dqs_5 equ 000050000h ; 5
dqs_6 equ 000060000h ; 6
dqs_7 equ 000070000h ; 7
dqs_8 equ 000080000h ; 8
dqs_9 equ 000090000h ; 9
dqs_10 equ 0000A0000h ; 10
dqs_255 equ 000FF0000h ; 255
;---------------------------------------------------------------------------------------------------
;---------------------------ROM
Header--------------------------------------------------------------
;---------------------------------------------------------------------------------------------------
ROMStart:
db 0x055, 0x0AA ; ROM Header 55,AA -> Bootable rom
db (ROMEnd - ROMStart)/512 ; ROM Size in 512byte
jmp MAIN
db 0 ; checksum, to be filled in later
;---------------------------------------------------------------------------------------------------
;---------------------------SUB-
ROUTINE-------------------------------------------------------------
;---------------------------------------------------------------------------------------------------
macro MTT 0,1,2
{
mov eax,0 ; copy register address
mov ebx,1 ; copy register data
mov dx,address ; set port address
out dx,eax ; send address through the port
mov dx,data ; set port data
in eax,dx
and eax,2 ; set data in eax
or eax,ebx ; increase data
out dx,eax ; send data through port data
}
macro SAVE ; Save all register that will be affected by our code
{
pushfd
push eax
push ebx
push bx
push dx
push si
push ds
push bp
}
;---------------------------------------------------------------------------------------------------
;---------------------------------------MAIN-
ROUTINE------------------------------------------------
;---------------------------------------------------------------------------------------------------
times (256)-($-$$) db 0 ; locate Main routine at 100h
MAIN:
SAVE
;----------------------------------------------------------------------------------------------------
; Patch A64 Memory Timing
MTT async,async_7,async_data ; Set max async latency to 7ns
;----------------------------------------------------------------------------------------------------
RETURN
times (ROM_SIZE_IN_BYTE-$) db 0
; The last byte (512th) will be the patch_byte for the checksum
; patch_byte is calculated and automagically inserted below
PREV_CHKSUM = 0
repeat $
load CHKSUM byte from %-1
CHKSUM = (PREV_CHKSUM + CHKSUM) mod 0x100
PREV_CHKSUM = CHKSUM
end repeat
store byte (0x100 - CHKSUM) at ($-1) ; store the patch_byte
ROMEnd:
;---------------------------------------CODE
END-----------------------------------------------------
; How to set you memory timing?
; Just type MTT<space>timing name,timing value,timing data
; Exp : async memory to 7.0ns would be -> MTT async,async_7,async_data
; Press F9 to compile it with flat assembler
;
;----------------------------------------------------------------------------------------------------
code:
EDIT: Note that the 120Mhz divider may not work on all systems and hang at POST.
code:
;---------------------------------------------------------------------------------------------------
;---------------------------PCI ROM
Header----------------------------------------------------------
;---------------------------------------------------------------------------------------------------
ROM_SIZE_IN_BLOCK = 1 ; 1 means ROM size is 1 block (512 bytes)
ROM_SIZE_IN_BYTE = ROM_SIZE_IN_BLOCK * 512
ROMStart:
db 0x055, 0x0AA ; ROM Header 55,AA -> Bootable rom
db (ROMEnd - ROMStart)/512 ; ROM Size in 512byte
jmp MAIN
;---------------------------------------------------------------------------------------------------
Fixed error in Twtr and Command Rate; added ECC Enable.
code:
;---------------------------------------------------------------------------------------------------
; AMD Athlon 64 DDR ROM Patcher Rev 3.0.1 (7/5/2007)
;---------------------------------------------------------------------------------------------------
;
; Source code writen by tictac
; Website : z6.invisionfree.com/tictac
; Note : Free to be distribute/mod , Use it at your own risk
;
;---------------------------------------------------------------------------------------------------
;------------------------------CODE
DEFINITION------------------------------------------------------
;---------------------------------------------------------------------------------------------------
use16 ; 16bit mode
address equ 0CF8h ; address port
data equ 0CFCh ; data port
;---------------------------------------------------------------------
; DRAM Timing Low Address
;---------------------------------------------------------------------
; CAS Latency(dtl)
tcl equ dtl_add
tcl_data equ 0FFFFFFF8h ; CAS Latency (3bit)
tcl_2 equ 000000001h ; CAS 2
tcl_25 equ 000000005h ; CAS 2.5
tcl_3 equ 000000002h ; CAS 3
;---------------------------------------------------------------------
; DRAM Timing High Address
;---------------------------------------------------------------------
; Write to read delay(dth)
twtr equ dth_add
twtr_data equ 0FFFFFFFEh ; Write to read delay (1bit)
twtr_1 equ 000000000h ; 1 clock
twtr_2 equ 000000001h ; 2 clock
; Refresh Rate(dth)
tref equ dth_add
tref_data equ 0FFFFE0FFh ; Refresh Rate (5bit)
tref_100_156 equ 000000000h ; 100MHz 15.6us
tref_133_156 equ 000000100h ; 133MHz 15.6us
tref_166_156 equ 000000200h ; 166MHz 15.6us
tref_200_156 equ 000000300h ; 200MHz 15.6us
tref_100_78 equ 000000800h ; 100MHz 7.8us
tref_133_78 equ 000000900h ; 133MHz 7.8us
tref_166_78 equ 000000A00h ; 166MHz 7.8us
tref_200_78 equ 000000B00h ; 200MHz 7.8us
tref_100_39 equ 000001000h ; 100MHz 3.9us
tref_133_39 equ 000001100h ; 133MHz 3.9us
tref_166_39 equ 000001200h ; 166MHz 3.9us
tref_200_39 equ 000001300h ; 200MHz 3.9us
;---------------------------------------------------------------------
; DRAM Configuration Low Address
;---------------------------------------------------------------------
; DLL Disabled(dcl)
dll equ dcl_add
dll_data equ 0FFFFFFFEh ; DLL disabled (1bit)
dll_enable equ 000000000h ; Enabled(default)
dll_disable equ 000000001h ; Disabled
; Bypass Max(dcl)
bpm equ dcl_add
bpm_data equ 0F1FFFFFFh ; Bypass Max (3bit)
bpm_0x equ 000000000h ; 0x (Disabled)
bpm_1x equ 002000000h ; 1x
bpm_2x equ 004000000h ; 2x
bpm_3x equ 006000000h ; 3x
bpm_4x equ 008000000h ; 4x
bpm_5x equ 00A000000h ; 5x
bpm_6x equ 00C000000h ; 6x
bpm_7x equ 00E000000h ; 7x
; Command Rate(dcl)
cr equ dcl_add
cr_data equ 0EFFFFFFFh ; Command Rate (1bit)
cr_1t equ 000000000h ; 1T
cr_2t equ 010000000h ; 2T
; ECC Enable(dcl)
ecc equ dcl_add
ecc_data equ 0FFFDFFFFh ; Command Rate (1bit)
ecc_d equ 000000000h ; Disable
ecc_e equ 000020000h ; Enable
;---------------------------------------------------------------------
; DRAM Configuration High Address
;---------------------------------------------------------------------
; Maximum Async Latency(dch)
async equ dch_add
async_data equ 0FFFFFFF0h ; Maximum Async Latency (4bit)
async_0 equ 000000000h ; 0 ns
async_1 equ 000000001h ; 1 ns
async_2 equ 000000002h ; 2 ns
async_3 equ 000000003h ; 3 ns
async_4 equ 000000004h ; 4 ns
async_5 equ 000000005h ; 5 ns
async_6 equ 000000006h ; 6 ns
async_7 equ 000000007h ; 7 ns
async_8 equ 000000008h ; 8 ns
async_9 equ 000000009h ; 9 ns
async_10 equ 00000000Ah ; 10ns
async_11 equ 00000000Bh ; 11ns
async_12 equ 00000000Ch ; 12ns
async_13 equ 00000000Dh ; 13ns
async_14 equ 00000000Eh ; 14ns
async_15 equ 00000000Fh ; 15ns
; Read Preamble(dch)
rp equ dch_add
rp_data equ 0FFFFF0FFh ; Read Preamble (4bit)
rp_20 equ 000000000h ; 2.0ns
rp_25 equ 000000100h ; 2.5ns
rp_30 equ 000000200h ; 3.0ns
rp_35 equ 000000300h ; 3.5ns
rp_40 equ 000000400h ; 4.0ns
rp_45 equ 000000500h ; 4.5ns
rp_50 equ 000000600h ; 5.0ns
rp_55 equ 000000700h ; 5.5ns
rp_60 equ 000000800h ; 6.0ns
rp_65 equ 000000900h ; 6.5ns
rp_70 equ 000000A00h ; 7.0ns
rp_75 equ 000000B00h ; 7.5ns
rp_80 equ 000000C00h ; 8.0ns
rp_85 equ 000000D00h ; 8.5ns
rp_90 equ 000000E00h ; 9.0ns
rp_95 equ 000000F00h ; 9.5ns
;---------------------------------------------------------------------
; DRAM DQS Delay Line Register
;---------------------------------------------------------------------
; DQS Slew Value(ddr)
dqs equ ddr_add
dqs_data equ 0FF00FFFFh ; Delay Line Adjust (8bit)
dqs_1 equ 000010000h ; 1
dqs_2 equ 000020000h ; 2
dqs_3 equ 000030000h ; 3
dqs_4 equ 000040000h ; 4
dqs_5 equ 000050000h ; 5
dqs_6 equ 000060000h ; 6
dqs_7 equ 000070000h ; 7
dqs_8 equ 000080000h ; 8
dqs_9 equ 000090000h ; 9
dqs_10 equ 0000A0000h ; 10
dqs_255 equ 000FF0000h ; 255
;---------------------------------------------------------------------------------------------------
;---------------------------ROM
Header--------------------------------------------------------------
;---------------------------------------------------------------------------------------------------
ROMStart:
db 0x055, 0x0AA ; ROM Header 55,AA -> Bootable rom
db (ROMEnd - ROMStart)/512 ; ROM Size in 512byte
jmp MAIN
db 0 ; checksum, to be filled in later
;---------------------------------------------------------------------------------------------------
;---------------------------SUB-
ROUTINE-------------------------------------------------------------
;---------------------------------------------------------------------------------------------------
macro MTT 0,1,2
{
mov eax,0 ; copy register address
mov ebx,1 ; copy register data
mov dx,address ; set port address
out dx,eax ; send address through the port
mov dx,data ; set port data
in eax,dx
and eax,2 ; set data in eax
or eax,ebx ; increase data
out dx,eax ; send data through port data
}
macro SAVE ; Save all register that will be affected by our code
{
pushfd
push eax
push ebx
push bx
push dx
push si
push ds
push bp
}
;---------------------------------------------------------------------------------------------------
;---------------------------------------MAIN-
ROUTINE------------------------------------------------
;---------------------------------------------------------------------------------------------------
times (256)-($-$$) db 0 ; locate Main routine at 100h
MAIN:
SAVE
;----------------------------------------------------------------------------------------------------
; Patch A64 Memory Timing
MTT async,async_7,async_data ; Set max async latency to 7ns
;----------------------------------------------------------------------------------------------------
RETURN
times (ROM_SIZE_IN_BYTE-$) db 0
; The last byte (512th) will be the patch_byte for the checksum
; patch_byte is calculated and automagically inserted below
PREV_CHKSUM = 0
repeat $
load CHKSUM byte from %-1
CHKSUM = (PREV_CHKSUM + CHKSUM) mod 0x100
PREV_CHKSUM = CHKSUM
end repeat
store byte (0x100 - CHKSUM) at ($-1) ; store the patch_byte
ROMEnd:
;---------------------------------------CODE
END-----------------------------------------------------
; How to set you memory timing?
; Just type MTT<space>timing name,timing value,timing data
; Exp : async memory to 7.0ns would be -> MTT async,async_7,async_data
; Press F9 to compile it with flat assembler
;
;----------------------------------------------------------------------------------------------------
In doing a mod BIOS for a A64 system, Tref was not working correctly. This is what I found a while ago
using WPCREdit. This code, while different then the AMD data sheet, works correctly, at least according to
A64 Tweaker. I guess A64 Tweaker could be wrong! But here's what is working:
code:
; Refresh Rate(dth)
tref equ dth_add
tref_data equ 0FFFFE0FFh ; Refresh Rate (5bit)
tref_100_156 equ 000000000h ; 100MHz 15.6us
tref_133_156 equ 000000100h ; 133MHz 15.6us
tref_166_156 equ 000000200h ; 166MHz 15.6us
tref_200_156 equ 000000300h ; 200MHz 15.6us
tref_100_78 equ 000000400h ; 100MHz 7.8us
tref_133_78 equ 000000500h ; 133MHz 7.8us
tref_166_78 equ 000000600h ; 166MHz 7.8us
tref_200_78 equ 000000700h ; 200MHz 7.8us
tref_100_39 equ 000000800h ; 100MHz 3.9us
tref_133_39 equ 000000900h ; 133MHz 3.9us
tref_166_39 equ 000000A00h ; 166MHz 3.9us
tref_200_39 equ 000000B00h ; 200MHz 3.9us
AMD AM2 DDR2 ROM Patcher Version 1.0.5.1
I rewrote the AMD A64 ROM Patcher that tictac wrote to update it for the Socket AM2 processor. Here is
the AMD AM2 DDR2 ROM Patcher Beta Version and it is working well. I'm updating the code as I fix the
register data and configuration data.
The following code is the most up-to-date. The follow-on verbiage after this code describes the steps I
took in re-writing the code and relearning Assembly. That is included for reference only.
code:
;---------------------------------------------------------------------------------------------------
; AMD AM2 DDR2 ROM Patcher Beta 1.0.5.1 09/07/2007
;---------------------------------------------------------------------------------------------------
;
; Source code writen by tictac. Updated for AM2 by Polygon of www.rebelshavenforum.com
; Website : z6.invisionfree.com/tictac
; Note : Free to be distribute/mod , Use it at your own risk
;
;---------------------------------------------------------------------------------------------------
;------------------------------CODE
DEFINITION------------------------------------------------------
;---------------------------------------------------------------------------------------------------
use16 ; 16bit mode
address equ 0CF8h ; address port
data equ 0CFCh ; data port
;---------------------------------------------------------------------
; DRAM Timing Low Address 08000C288h
;---------------------------------------------------------------------
; CAS Latency(dtl)
tcl equ dtl_add
tcl_data equ 0FFFFFFF8h ; CAS Latency (3bit)
tcl_3 equ 000000002h ; CAS 3
tcl_4 equ 000000003h ; CAS 4
tcl_5 equ 000000004h ; CAS 5
tcl_6 equ 000000005h ; CAS 6
;---------------------------------------------------------------------
; DRAM Timing High Address
;---------------------------------------------------------------------
; Twrrd Delay(dth)
tWrrd equ dth_add ;
tWrrd_data equ 0FFFFF3FFh ; Twrrd Delay (2bit)
tWrrd_0 equ 000000000h ; 0 clock
tWrrd_1 equ 000000400h ; 1 clock
tWrrd_2 equ 000000800h ; 2 clock
tWrrd_3 equ 000000C00h ; 3 clock
; Twrwr Delay(dth)
twrwr equ dth_add ;
twrwr_data equ 0FFFFCFFFh ; Twrwr Delay (2bit)
twrwr_1 equ 000000000h ; 1 clock
twrwr_2 equ 000001000h ; 2 clock
twrwr_3 equ 000002000h ; 3 clock
; Trdrd Delay(dth)
trdrd equ dth_add ;
trdrd_data equ 0FFFF3FFFh ; Trdrd Delay (2bit)
trdrd_2 equ 000000000h ; 2 clock
trdrd_3 equ 000004000h ; 3 clock
trdrd_4 equ 000008000h ; 4 clock
trdrd_5 equ 00000C000h ; 5 clock
; Refresh Rate(dth)
tref equ dth_add
tref_data equ 0FFFCFFFFh ; Refresh Rate (2bit)
tref_15.6 equ 000010000h ; 15.6us
tref_7.8 equ 000020000h ; 7.8us
tref_3.9 equ 000030000h ; 3.9us
; Trfc0(dth)
trfc0 equ dch_add
trfc0_data equ 0FF8FFFFFh ; Maximum Async Latency (3bit)
trfc0_75 equ 000000000h ; 75 ns
trfc0_105 equ 000100000h ; 105 ns
trfc0_127.5 equ 000200000h ; 127.5 ns
trfc0_195 equ 000300000h ; 195 ns
trfc0_327.5 equ 000400000h ; 327.5 ns
; Trfc1(dth)
trfc1 equ dch_add
trfc1_data equ 0FC7FFFFFh ; Maximum Async Latency (3bit)
trfc1_75 equ 000000000h ; 75 ns
trfc1_105 equ 000800000h ; 105 ns
trfc1_127.5 equ 001000000h ; 127.5 ns
trfc1_195 equ 001800000h ; 195 ns
trfc1_327.5 equ 002000000h ; 327.5 ns
; Trfc2(dth)
trfc2 equ dch_add
trfc2_data equ 0E3FFFFFFh ; Maximum Async Latency (3bit)
trfc2_75 equ 000000000h ; 75 ns
trfc2_105 equ 004000000h ; 105 ns
trfc2_127.5 equ 008000000h ; 127.5 ns
trfc2_195 equ 00C000000h ; 195 ns
trfc2_327.5 equ 010000000h ; 327.5 ns
; Trfc3(dth)
trfc3 equ dch_add
trfc3_data equ 01FFFFFFFh ; Maximum Async Latency (3bit)
trfc3_75 equ 000000000h ; 75 ns
trfc3_105 equ 020000000h ; 105 ns
trfc3_127.5 equ 040000000h ; 127.5 ns
trfc3_195 equ 060000000h ; 195 ns
trfc3_327.5 equ 080000000h ; 327.5 ns
;---------------------------------------------------------------------
; DRAM Configuration Low Address
;---------------------------------------------------------------------
;---------------------------------------------------------------------
; DRAM Configuration High Address
;---------------------------------------------------------------------
; Memory Clock Frequency(dch)
mcf equ dch_add
mcf_data equ 0FFFFFFF8h ; Memory Clock Frequency (3bit)
mcf_200 equ 000000000h ; 400MHz
mcf_266 equ 000000001h ; 533MHz
mcf_333 equ 000000002h ; 667MHz
mcf_400 equ 000000003h ; 800MHz
; Command Rate(dch)
cr equ dch_add
cr_data equ 0FFEFFFFFh ; Command Rate (1bit)
cr_1t equ 000000000h ; 1T
cr_2t equ 000100000h ; 2T
; Queue Bypass Max(dch)
qbp equ dch_add
qbp_data equ 0F0FFFFFFh ; Queue Bypass Max (4bit)
qbp_0 equ 000000000h ; 0 memclk cycles
qbp_1 equ 001000000h ; 1 memclk cycles
qbp_2 equ 002000000h ; 2 memclk cycles
qbp_3 equ 003000000h ; 3 memclk cycles
qbp_4 equ 004000000h ; 4 memclk cycles
qbp_5 equ 005000000h ; 5 memclk cycles
qbp_6 equ 006000000h ; 6 memclk cycles
qbp_7 equ 007000000h ; 7 memclk cycles
qbp_8 equ 008000000h ; 8 memclk cycles
qbp_9 equ 009000000h ; 9 memclk cycles
qbp_10 equ 00A000000h ; 10 memclk cycles
qbp_11 equ 00B000000h ; 11 memclk cycles
qbp_12 equ 00C000000h ; 12 memclk cycles
qbp_13 equ 00D000000h ; 13 memclk cycles
qbp_14 equ 00E000000h ; 14 memclk cycles
qbp_15 equ 00F000000h ; 15 memclk cycles
;---------------------------------------------------------------------
; DRAM Controller Miscellaneous Data address
;---------------------------------------------------------------------
;---------------------------------------------------------------------------------------------------
;---------------------------ROM
Header--------------------------------------------------------------
;---------------------------------------------------------------------------------------------------
ROMStart:
db 0x055, 0x0AA ; ROM Header 55,AA -> Bootable rom
db (ROMEnd - ROMStart)/512 ; ROM Size in 512byte
jmp MAIN
db 0 ; checksum, to be filled in later
;---------------------------------------------------------------------------------------------------
;---------------------------SUB-
ROUTINE-------------------------------------------------------------
;---------------------------------------------------------------------------------------------------
macro MTT 0,1,2
{
mov eax,0 ; copy register address
mov ebx,1 ; copy register data
mov dx,address ; set port address
out dx,eax ; send address through the port
mov dx,data ; set port data
in eax,dx
and eax,2 ; set data in eax
or eax,ebx ; increase data
out dx,eax ; send data through port data
}
macro SAVE ; Save all register that will be affected by our code
{
pushfd
push eax
push ebx
push bx
push dx
push si
push ds
push bp
}
;---------------------------------------------------------------------------------------------------
;---------------------------------------MAIN-
ROUTINE------------------------------------------------
;---------------------------------------------------------------------------------------------------
times (256)-($-$$) db 0 ; locate Main routine at 100h
MAIN:
SAVE
;----------------------------------------------------------------------------------------------------
; Patch AM2 Memory Timing
MTT async,async_7,async_data ; Set max async latency to 7ns
;----------------------------------------------------------------------------------------------------
RETURN
times (ROM_SIZE_IN_BYTE-$) db 0
; The last byte (512th) will be the patch_byte for the checksum
; patch_byte is calculated and automagically inserted below
PREV_CHKSUM = 0
repeat $
load CHKSUM byte from %-1
CHKSUM = (PREV_CHKSUM + CHKSUM) mod 0x100
PREV_CHKSUM = CHKSUM
end repeat
store byte (0x100 - CHKSUM) at ($-1) ; store the patch_byte
ROMEnd:
;---------------------------------------CODE
END-----------------------------------------------------
; How to set you memory timing?
; Just type MTT<space>timing name,timing value,timing data
; Exp : async memory to 7.0ns would be -> MTT async,async_7,async_data
; Press F9 to compile it with flat assembler
;
;----------------------------------------------------------------------------------------------------
I've have now generated a working PCI Substitute ROM for the ABIT AM2 board NF-M2 nView to set the
Async Latency. I used a version of the above code with the PCI header code that tictac posted in another
thread...
Many Memory Timing Registers and Data are correct, while a few others are as yet to be defined
correctly... The above Code has been revised and commented several times, incorporating updates...
One of the problems I'm running into with writing the AM2 code, is shown in this map of the x88h "DRAM
Timing Low Register". Trp and Trtp are both set with the 3ed hex byte which is fine.
The question is, the 3ed bit of the 3ed byte, is "reserved". Can I change it? Must it stay what it was? Can
it be 0h or 1h? Actually it looks to be "read-only", so it won't change anyhow. Will trying to write to it
cause a problem? I guess I'll have to test it. This situation occurs in about 3-4 registers in the AM2 CPU
and needs to be understood....
The immediate solution is to combine the 2 settings(Trp & Trtp) so the desired combination can be
selected. The "Reserved" bit position in the code is zero(0) for all selections. Here's what it looks like:
code:
The next combo "problem" is Twr and Trrd both being set by the 6th byte:
Again, the immediate solution is to combine them in the option chart:
code:
The code in the lead topic has been updated with the combination codes.
I've have now generated a working PCI Substitute ROM for the ABIT AM2 board NF-M2 nView, to set the
Async Latency to 8ns, Twr to 5T, and Trrd to 4T. Settings were verified using Systool. This verifies the
"combo" code works....
My brief code for this test. Note the Vendor and Device ID are for the ABIT NF-M2 nView only:
code:
;---------------------------------------------------------------------------------
;---------------------------PCI ROM Header----------------------------------------
;---------------------------------------------------------------------------------
VENDOR_ID equ 10DEh ; PCI Vendor ID (must match your ethernet vendor id)
; exp: 10DE = nVidia
DEVICE_ID equ 0269h ; PCI Device ID (must match your ethernet devicie id)
; exp: 0269h = NF-M2 NIC
ROMStart:
db 0x055, 0x0AA ; ROM Header 55,AA -> Bootable rom
db (ROMEnd - ROMStart)/512 ; ROM Size in 512byte
jmp MAIN
MAIN:
pushfd
push eax
push ebx
push bx
push dx
push si
push ds
push bp
pop bp
pop ds
pop si
pop dx
pop bx
pop ebx
pop eax
popfd
retf ; return far to system bios routine
times (ROM_SIZE_IN_BYTE-$) db 0 ; use 00h as the padding bytes until we reach the ROM
size
; The last byte (512th) will be the patch_byte for the checksum
; patch_byte is calculated and automagically inserted below
PREV_CHKSUM = 0
repeat $
load CHKSUM byte from %-1
CHKSUM = (PREV_CHKSUM + CHKSUM) mod 0x100
PREV_CHKSUM = CHKSUM
end repeat
store byte (0x100 - CHKSUM) at ($-1) ; store the patch_byte
ROMEnd:
The PCI Option ROM has the very nice feature of being able to be disabled/enabled in the BIOS.
The 2 most common PCI BIOS Modules are the "RAID" module and the "Boot Agent" module. While most
folks do not want to loose the "RAID", I'll concentrate on using the "Boot Agent" module....
All newer boards today have at least 1 LAN onboard. In most BIOS, there is a option to disable or enable
that LAN.... Many BIOS also have a 2nd option that allows the system to boot from the LAN. This is called
the "Boot Agent", and is normally set to "Disable"....
In the BIOS itself, the ROM that is loosely referred to as the "LAN Module", is actually the "Boot Agent"
module and is not needed for the LAN to function properly. It can be removed and the LAN functions
perfectly. So because of this, the "Boot Agent" module is the perfect module to "release" with Cbrom32,
and replace with our PCI Substitution ROM.
The reasoning behind this is, if we created a PCI ROM that sets memory timings that hang the system, a
simple CMOS clear will return the system to "normal" operation. This of course assumes the "Boot Agent"
is set to disable as the default. If it is not, a simple Modbin6 session fixes that.
The only AMI BIOS I tried the PCI Substitution ROM on, disabled both the normal LAN and the "Boot
Agent" with a single BIOS option. But, if the PCI Option ROM works and it is what you want, the LAN
would be turned on anyhow....
The AM2 Patcher code has been updated to split the combined timing codes.... As I test, fix and rewrite
the Code, I'll keep the lead topic updated. Here's the new code in the simplified form for Async Latency
and the split Twr and Trrd:
Here's the code for the PCI Substitute Option ROM used on the DFI Infinity UltraII-M2. This is the code
that went into the 8UM2D7_8.bin BIOS:
code:
;---------------------------------------------------------------------------------
;---------------------------PCI ROM Header----------------------------------------
;---------------------------------------------------------------------------------
VENDOR_ID equ 10DEh ; PCI Vendor ID (must match your ethernet vendor id)
; exp: 10DE = nVidia
DEVICE_ID equ 0057h ; PCI Device ID (must match your ethernet devicie id)
; exp: 0057h = DFI UltraII-M2 NIC
ROMStart:
db 0x055, 0x0AA ; ROM Header 55,AA -> Bootable rom
db (ROMEnd - ROMStart)/512 ; ROM Size in 512byte
jmp MAIN
MAIN:
pushfd
push eax
push ebx
push bx
push dx
push si
push ds
push bp
mov eax,08000C28Ch ; DRAM Timing High address
mov ebx,000000C00h ; copy register data for twrrd: 3clks
mov dx,0CF8h ; set port address
out dx,eax ; send address through the port
mov dx,0CFCh ; set port data
in eax,dx ; fetch data
and eax,0FFFFF3FFh ; set data byte to zero
or eax,ebx ; increase data by new setting
out dx,eax ; send data through port data
;-------------------------------------------------------------------------------------
;-------------------------------------------------------------------------------------
pop bp
pop ds
pop si
pop dx
pop bx
pop ebx
pop eax
popfd
retf ; return far to system bios routine
times (ROM_SIZE_IN_BYTE-$) db 0 ; use 00h as the padding bytes until we reach the ROM
size
; The last byte (512th) will be the patch_byte for the checksum
; patch_byte is calculated and automagically inserted below
PREV_CHKSUM = 0
repeat $
load CHKSUM byte from %-1
CHKSUM = (PREV_CHKSUM + CHKSUM) mod 0x100
PREV_CHKSUM = CHKSUM
end repeat
store byte (0x100 - CHKSUM) at ($-1) ; store the patch_byte
ROMEnd:
This update adds Trfc0, Trfc1, Trfc2, Trfc3, Read/Write Queue Bypass, and Dynamic Idle Cycle Limit
Enable.
This update came out of work where we made a PCI Code-Injection ROM that changed 20 memory
timings. I wrote Dwords to each of the 5 register that control the memory timings. The Dwords contained
all the necessary data changes for the required timings. Here's the source code without sub-routines. And
the timings it sets:
CAS: 5T
tRCD: 5T
tRP: 5T
tRAS: 15T
tRC: 24T
Command Rate: 2T
tRRD: 5T
tWR: 5T
tWTR: 3T
tREF: 7.9us
Drive Strength: Normal
Max Async Latency: 9ns
Idle Cycle Limit: 32
Dynamic Idle Cycle: Enable
Queue Bypass: 15
Read/Write Queue Bypass: 16
Trfc0: 195ns
Trfc1: 195ns
Trfc2: 195ns
Trfc3: 195ns
Here's the code that would be put into either a PCI ROM or a ISA ROM:
Download Source Code here.
Updated code 9/7/07: Trcd and Trtp masks were not exactly correct.
Remember, the information presented may not work for you. If you are not
comfortable modifying BIOS's and flashing them, do not attempt to modify
them.
--------------------
Building Your Own AWARD ISA Option ROM
The information presented here is the product of several weeks of trial, error, and
brushing up on Assembly Language programming. A huge thanks must go out mainly to
Master Pinczakko and tictac for their articles, help, and review of assembly source code
posted in the Building an AWARD ISA ROM Discussion Thread. While there is a tendency
by Internet BIOS modders to keep what they know a deep dark secret, both Pinczakko
and Tictac are more then willing to share their knowledge.
Also unknowingly providing help from their mod BIOS, programs, and articles, are
Sideeffect, Borg Number One, H.Oda, and the authors of FASM, A64Tweaker, CBID, CPU-
Z, Systool, and the many other free programs that are available on the internet. Their
unpaid work effort is truly appreciated
Questions, comments, etc, should be posted in Building an AWARD ISA ROM Discussion
Thread.
Note that while the process seems relatively simple, one needs to know the registers,
ports, and data for each option the ROM is going to modify upon bootup. That
information can be gotten from the code posted in Tictac's AMD Athlon 64 DDR ROM
Patcher Rev 3.0 topic or in the AMD AM2 DDR2 ROM Patcher Version 1.0.4 topic. Also in
that topic are more sophisticated source code examples that may be better to use after
understanding this presentation. Source code for the 3 working versions is here....
The first thing that must be known about a ISA Option ROM is it's format. From
Pinczakko's endless articles on the subject of BIOS modding, a ISA Option ROM must
follow the following format:
It should be noted that the ISA, PCI, VGA, and GV3 ROM modules also have the same
basic format.
Also note that a ISA Option ROM configured for the same register as a PCI Option ROM,
will override the PCI Option ROM. The ISA Option ROM is executed last.
Thanks to Tictac, here is simple working source code that can be assembled with FASM
and inserted in a BIOS and addresses the memory registers accessible on the PCI bus. As
shown, the example sets Tref to 200Mhz 15.6usec and Async Latency to 8nsec, but can
be modified for any timing setting available. All ISA ROM format conditions above are
satisfied:
code:
ROMStart:
db 0x055, 0x0AA ; ROM Header 55,AA -> Bootable rom
db (ROMEnd - ROMStart)/512 ; ROM Size in 512byte
jmp MAIN ; jump to main routine
db 0 ; checksum, to be filled in later
pop bp
pop ds
pop si
pop dx
pop bx
pop ebx
pop eax
popfd ; clear the registers and return data
as we are finished
retf ; return far to system bios routine
; The last byte (512th) will be the patch_byte for the checksum
; patch_byte is calculated and automagically inserted below
PREV_CHKSUM = 0
repeat $
load CHKSUM byte from %-1
CHKSUM = (PREV_CHKSUM + CHKSUM) mod 0x100
PREV_CHKSUM = CHKSUM
end repeat
store byte (0x100 - CHKSUM) at ($-1) ; store the patch_byte
ROMEnd:
While the above code is fairly straight forward, I found that to completely understand
what is taking place, this simpler code was easier to understand for a Assembly novice.
To use this code, the checksum must be patched after being compiled with FASM, but is
presented for information only. The above code is the complete code that should be used:
code:
use16 ; compile in 16 bit mode
ROMStart: ; start our code
db 55h ; fulfill header requirements
db 0AAh ; fulfill header requirements
db 01h ; ROM will be 1 block of 512 bytes
call main ; go to main routine
retf ; return far to system bios routine
xchg ax, bp ; exchange data
; ******************** MAIN R O U T I N E ***************************
times (256)-($-$$) db 0 ; locate Main routine at 100h
main:
pushad ; push data on stack down
;
***********************************************************************************
popad ; pop data from top of stack
retn ; return near
times (512-$) db 0 ; pad rom with 0h to end
ROMEnd: ; end our code
Remember you are using this information entirely at your own risk. The
information presented may not work for you. If you are not comfortable
modifying BIOS's and flashing them, do not attempt to modify them. You
must be able to recover from a "bad" flash.
Building Your Own AWARD Substitute PCI Option ROM
The information presented here is the product of several weeks of trial, error with both
the PCI and ISA Option ROM projects, and brushing up on Assembly Language
programming. Again, a huge thanks must go out mainly to Master Pinczakko and tictac
for their articles, help, and review of assembly source code posted in the Building an
AWARD PCI ROM Discussion Thread. While there is a tendency by Internet BIOS modders
to keep what they know a deep dark secret, both Pinczakko and Tictac are more then
willing to share their knowledge.
Also unknowingly providing help from their mod BIOS, programs, and articles, are
Sideeffect, Borg Number One, H.Oda, and the authors of FASM, A64Tweaker, CBID, CPU-
Z, Systool, and the many other free programs that are available on the internet. Their
unpaid work effort is truly appreciated
Questions, comments, etc, should be posted in Building an AWARD PCI ROM Discussion
Thread. In addition, some work has been performed on a Substitute PCI Option ROM for
an AMI BIOS. That discussion is here...
Note that while the process seems relatively simple, one needs to know the registers,
ports, and data for each option the ROM is going to modify upon bootup. That
information can be gotten from the code posted in Tictac's AMD Athlon 64 DDR ROM
Patcher Rev 3.0 topic or in the AMD AM2 DDR2 ROM Patcher Version 1.0.4 topic. Also in
that topic are more sophisticated source code examples that may be better to use after
understanding this presentation along with the PCI Header code. Source code for the 3
working versions is here....
It appears that the best PCI ROM module to substitute a PCI Option ROM for, is the LAN
module. My experience in generating mod BIOS's with PCI Option ROM's added, has
shown that the LAN module in the BIOS is the Network Boot Agent and in many cases,
does not control the LAN at all. Replacing the LAN module does not seem to render the
onboard Ethernet inoperative in most cases. The other PCI Module that could be a target
of the PCI Option ROM is the RAID module, but many users are using RAID and would
not want to give up that feature. Tictac has released a few mod BIOS's where he added
the code to the LAN module, so that no features were lost. The details of that technique
are discussed in the Building an AWARD PCI ROM Using Code Injection.
The first thing that must be known about a PCI Option ROM is it's format. From
Pinczakko's endless articles on the subject of BIOS modding, a PCI Option ROM must
follow the same format as the ISA Option ROM. Here's the required format:
It should be noted the PCI, ISA, VGA, and GV3 ROM modules all have the same basic
format requirements of items 1-4.
Note that a ISA Option ROM configured for the same register as a PCI Option ROM, will
override the PCI Option ROM. The ISA Option ROM is executed last.
Thanks to Tictac, here is simple working source code that can be assembled with FASM
and inserted into a BIOS. The code is the PCI substitution method for the ABIT AN8-Ultra.
This example will set Tref to 15.6us and Async Latency to 7ns, but can be modified to
preset any timing available. The NIC ROM module will be removed and the compiled code
will be inserted in place of the NIC ROM. This code is combination of Tictac's PCI ROM
Header and my really brief ISA ROM code and addresses the memory registers accessible
on the PCI bus. All PCI ROM format conditions above are satisfied:
code:
;---------------------------------------------------------------------------------
;---------------------------PCI ROM
Header----------------------------------------
;---------------------------------------------------------------------------------
ROMStart:
db 0x055, 0x0AA ; ROM Header 55,AA -> Bootable rom
db (ROMEnd - ROMStart)/512 ; ROM Size in 512byte
jmp MAIN
MAIN:
pushfd
push eax
push ebx
push bx
push dx
push si
push ds
push bp
pop bp
pop ds
pop si
pop dx
pop bx
pop ebx
pop eax
popfd
retf ; return far to system bios routine
; The last byte (512th) will be the patch_byte for the checksum
; patch_byte is calculated and automagically inserted below
PREV_CHKSUM = 0
repeat $
load CHKSUM byte from %-1
CHKSUM = (PREV_CHKSUM + CHKSUM) mod 0x100
PREV_CHKSUM = CHKSUM
end repeat
store byte (0x100 - CHKSUM) at ($-1) ; store the patch_byte
ROMEnd:
Questions, comments, etc, should be posted in Building an AWARD PCI ROM Discussion Thread.
Note that while the process seems relatively simple, one needs to know the registers, ports, and data for each option
the ROM is going to modify upon bootup. That information can be gotten from the code posted in Tictac's AMD Athlon
64 DDR ROM Patcher Rev 3.0 topic or in the AMD AM2 DDR2 ROM Patcher Version 1.0.4 topic. Also in that topic are
more sophisticated source code examples that may be better to use after understanding this presentation along with the
PCI Header code.
As with the PCI Substitute Option ROM, it appears that the best PCI ROM module to inject code into is the LAN module.
My experience in generating mod BIOS's with PCI Option ROM's added, has shown that the LAN module in the BIOS is
the Network Boot Agent and in most cases, does not control the LAN at all. Injecting code into the LAN module does not
render the onboard Ethernet inoperative at all. The other PCI Module that could be a target of a injected PCI Option
ROM is the RAID module, but many users are using RAID and would not want that feature fiddled with. Tictac has
released a few mod BIOS's where he added the code to the LAN module, so that no features were lost. We will use one
of those BIOS as a template and approach this project from a mechanical standpoint. In other words, we'll show you
what to do with a minimum of theory. Remember Intel(IBM Compatible) uses what is called "Little Endian" Notation.
That means that the least significant digits are displayed first. So, the decimal number 65172, which is FE94h in Hex,
will be displayed as 94FE in the binary file.
The first thing that must be known about any PCI Option ROM is it's format. From Pinczakko's priceless articles on the
subject of BIOS modding, a PCI Option ROM must follow the same format as the ISA Option ROM. Here's the required
format:
Here is a flow diagram of the original PCI ROM along side the modified PCI ROM:
The BIOS we're working with is for the ABIT AN8 Ultra, a S939 system. In the top window, we see the 55AAh that is the
signature of the PCI ROM. The 80h indicates that the ROM has 128 blocks of 512 bytes. After the 80h byte, in the
middle window, we see the new jump instruction(E9h). This jump instruction is telling the system to start executing
code at 1D5Ah(7514) lines after this instruction. That works out to be code line 1D60h. The next Hex Byte, CBh, is a far
return instruction, to return the system to the next line of code the called this PCI ROM. The code in the bottom window
allows the PCI LAN Boot ROM to function normally and was not changed from the originally code. All we are changing is
the jump instruction that previously was a call(E8) instruction, and the destination of the instruction to be our new code.
In the top window, we see the 55AAh that is the signature of the PCI ROM, plus the size byte, and the jump instruction
which is highlighted. In the middle window, we see a jump instruction to 0126h lines of code after the instruction. The
exact reason for this stop and jump again, is not known, but will be used for now. In the next day or 2, I'll try this
method without this step. I'm sure the reason will become apparent.
Edit: Jumping right to the added code works just fine. No need to stop and jump again. The follow-on instructions will
jump right to the added code.
The bottom window shows the destination of the last jump command. Calculating the exact number of lines to jump, is
easy. Subtract the next byte address after the jump instruction, from the required destination. That gives us the hex
value for the jump instruction.
Example: 1D60h-6h=1D5Ah and 1E89h-1D63h=126h
Note that the above block diagram and 2 screen shots and their code/values, are for reference only, and are not to be
viewed as usable code. They are posted for information and reference only. The next post below, will show how to
generate usable code.
Building Your Own AWARD PCI Option ROM Using Code Injection: Brief Method
To successfully generate a PCI ROM using "Code Injection", we really need to start at the beginning and do some
groundwork first. To begin with, we must look at the call instruction code that is in the header of the unmodded LAN
Boot ROM, to see where it's directing the system to. Note that on some BIOS, this is a jump instruction. I'll detail what
that means to the added code a little later:
Using IDA Disassembler, we see that the code E83B0Fh is a call to 0F41h. What this means to our added code is, at the
end of our code, we must call 0F41h to allow the system to continue on normally after executing our added code. Had
this been a jump instruction, then we would add a jump to 0F41h at the end of our added code. Remember Intel(IBM
Compatible) uses what is called "Little Endian" Notation. That means that the least significant digits are displayed first.
So, the decimal number 3899, which is 0F3Bh in Hex, will be displayed as 3B0F in the binary file. IDA tries to
disassemble the first 2 bytes 55AAh, but doesn't know that they are only a signature. Ignore this.
This is the Source Code for the Hex Code I added to the LAN Boot ROM. It sets the Tref to 15.6usec @ 200Mhz, and sets
the Async Latency to 8nsec. I chose these 2 memory timings for testing purposes only. I know my system at default
sets these 2 timings to other settings, so when the LAN Boot is Enabled, I can check to see that my modified ROM is
working. Note that this code is not "complete enough" to be used for any thing other then PCI Code Injection. Also,
there are many ways to write the source code that may be smaller, or more sophisticated, but that is not the intent of
this thread, and will not be pursued. I chose the most straight forward, simple approach that works for me.
Here in the top window, we have compiled the Source Code using FASM. The only thing missing is the call to 0F41h, and
the far return, CBh. The method to calculate the value for the call instruction to get to 0F41h, is a little different then
what we did in the lead topic. We need an address that is beyond the file size, so that it wraps around and becomes
0F41h. To do this, we simply subtract the next address after the instruction, from 10F41h. So we get 10F41h-
1EE2h=F05Fh. The bottom window shows the code copied and pasted into the ROM. The call, it's address, and the far
return, have been typed in manually after the highlighted code. It's: E85FF0CBh.
Here I've changed the 4 bytes of our header to jump to the added code that was injected at 1F89h. This will always be a
jump instruction regardless of what it was originally. The bottom window shows the code added into the ROM and the
address where it starts. Calculating the exact number of lines to jump, is easy. Subtract the next byte address after the
jump instruction, from the required destination. That gives us the hex value for the jump instruction. In this case:
1E89h-0006h=1E83h
Here we see the new code added in, starting at 1E89h. Note that Hex Workshop displays the starting location of the
code at the bottom left. 1E89h is the destination of the header jump instruction that is shown in the top window of the
previous picture. The code could have been added any place there is room, just as long as the jump and call instruction
addresses, were calculated based on the new location.
Here I have disassembled the modded LAN Boot ROM to ensure that everything has the correct addresses. All that is left
to do is put the LAN Boot ROM back into my BIOS, and fire her up!
The code injected into the BIOS worked as expected and testing verified that everything was working just fine. I will
update this thread as I find out any additional or new information.
Here's code for changing several AM2 memory timings using DWords containing several memory data sets. This code
was injected into the LAN Boot module of a AM2 motherboard BIOS. Note that using subroutines for common code,
could reduce the size of the binary code, probably 2:1.....
code:
pushfd
push eax
push ebx
push bx
push dx
push si
push ds
push bp
pop bp
pop ds
pop si
pop dx
pop bx
pop ebx
pop eax
popfd
Remember, the information presented may not work for you. If you are not
comfortable modifying BIOS's and flashing them, do not attempt to modify them.
The _ITEM.BIN Module And It's Interaction With _EN_CODE.BIN
This topic's purpose is to bring together all the information learned in the Hacking The _ITEM.BIN Module And It's Interaction With
_EN_CODE.BIN topic. While much was discussed in that topic that makes the subject appear very complex, the interaction between
the 2 subject BIOS modules is quite straightforward. That original thread should be read and re-read to fully understand what is being
presented. A huge thanks must go out to luk1999 for his initial work on this subject.....
Background:
The Biostar 965PT BIOS has gross errors in the settings of Twr, Twtr, Trrd, and Trtp. The actual memory timing does not agree with
the BIOS setting. This error is in all released 965PT BIOS to date.
Problem:
Not being able to fix the timings in the system bios module, I could just re-label the timings. But in the _EN_CODE.BIN module, all 4
memory settings in question, use only 2 set of timing labels, so it was impossible to re-label the settings, as the amount of error was
different for each option.
Solution:
I created 2 new sets of labels at the end of the _EN_CODE.BIN module, and added the addresses of those labels to a new address list:
0000 0200 E05F 3060
At the beginning of the _EN_CODE.BIN module, I added the address, 6082h, of the new address list, to the main address list.(In the
follow up post, I had found something pointing to this address and had to move it.)
Then in the _ITEM.BIN module, I changed the addresses, that the addresses of the corrected labels exist at.
This is a breakdown of a typical _ITEM.BIN module sequence and what the entries mean:
This is a little block diagram or flowchart showing how the addresses of the labels are defined. Remember 00h is the 1st address:
Here is something that can drive you bonkers! After modding 4-5 BIOS the exact same way, a mod of a older version, works, but has
"[v_]" or "[t_]" scattered about when entering the BIOS! The BIOS works, but the display is all fouled up. I checked the addresses
several times and I finally noticed this:
The very 1st address in the _EN_CODE.bin main address list, points to 0594h in this BIOS module. And the 1st address in that
address list, points back to 0030h. 0030h is empty right now, but not for long
Turns out that 0030h is where I need to add an address, that points to a new address list!
Solution is to change the 3000h that is in address 0594h, to a higher number. I used 4000h as that was in the newer BIOS modules....
Evidently, the 1st address in the 1st address list, points to a address where the data in the _EN_CODE.bin module can start to be
read. If there is data in that address, visual junk is displayed throughout the BIOS. This is only noticed when entering the BIOS
running on a system. It's not noticed in Modbin...
BIOS Without _ITEM.BIN
Some BIOS do not have a setup0 module, named "_ITEM.BIN" The BIOS GUI information is in the system bios
module. It appears that these BIOS do not open with the latest Modbin6 program, even though they are AWARD
BIOS.
In the screen shot below of a Gigabyte P965 BIOS, I highlighted in yellow all the FFFFh bytes which are the 5th and
6th byte in a _ITEM.BIN sequence. I have highlighted in black, a typical 25 byte sequence that appears to follow
the standard _ITEM.BIN sequence format:
Modifying any sequence in the system bios module is a little different then when the data in in the _ITEM.BIN
module. While the system bios module can be extracted several ways and modified quite easily, it is near
impossible to replace. See How to Change Original.tmp in Award6.0 bios, Quick Guide from tictac for a technique to
replace/modify the system bios module.
In doing a mod, I just noticed that "0Bh" in front of a word, causes a "line break" to the verbiage. Here's a screenie of an example.
The verbiage starts at 6393h, the "line breaks" are highlighted in yellow. The address pointer, 9363h, is also circled:
[Press Enter]
From our work outlined in the Hacking The _ITEM.BIN Module And It's Interaction With _EN_CODE.BIN topic, I have found a way to
add the [Press Enter] on new branches!
One of the issues we run into when adding new Items to a BIOS, is having enough blank or unused Items to use for the new Items we
want to add. Most all BIOS I have looked at have 5 unused Items directly under "Maximum Payload Size", which in turn is under "PNP/PCI
Configuration". But some BIOS do not have 5 and/or we need more then that. I have been using "Full Screen Logo" and if necessary "EPA
Logo", but only after removing their modules from the BIOS so they don't randomly come on. luk1999 has found that adding one of the
unused sequences to the area shown below, adds a new unused Item under directly under "Maximum Payload Size":
Most of the BIOS I looked at only have 1 sequence before the end of the _item.bin module, but still, adding the code in
the same place, adds 1 more new unused Item. Here I've added the new sequence in:
Original BIOS:
Here I've copy and pasted the 5 unused Item sequences into Notepad so that I can visualize them easier. Note that all have
the same "Position Code" of C603h:
Simply changing those "Position Codes" will move the Item to the desired area and this can be done after the mod is in, or at
the very beginning of the mod process. I suggest moving the Item(s) early on just in case there is some issue.
For this test, I selected the top unused branch:
Pressing "alt+C" inserts the 4 Items under that branch, but without a heading label:
I've gone in and labeled it "Spread Spectrums" and enabled it as it was disabled by default:
Now for the [Press Enter] I found an existing branch and disabled it to be able to locate it's sequence. I've found some very
interesting things in it's sequence. First off. it only has 1 mask. Secondly, it has 00h for the number of selections, but has a selection
label address that ultimately points to the "Press Enter" label in it's _EN_CODE.BIN module:
I edited the new "Spread Spectrums" branch sequence to have 00h selections and have it's label address pointer point to where "Press
Enter" is located in the _en_code.bin module.
Success! We now can make an unused branch look just like every other branch The branch can be moved to a logical place at this
point, if desired.
Remember you are using this information entirely at your own risk. The information presented may not work
for you. If you are not comfortable modifying BIOS's and flashing them, do not attempt to modify them. You
must be able to recover from a "bad" flash.
How to Change Original.tmp in Award6.0 bios, Quick Guide from tictac...
tictac:
This hack had been done to ABIT AN7 bios version 15... which is not possible to hack it with Modbin/Modhack
Pinczakko:
Just a little bit clarifications to remove the "myths" regarding this method.
code:
says to compress system.bin into LZH format and decompress it to segment 5000h during the decompression stage of the BIOS
code execution. In unmodified Award BIOS binary, segment 5000h is also the destination of the system BIOS's decompression
process. Examine the LZH header if you're still confused. - You should understand what I'm saying if you have read my BIOS
reverse engineering article -
quote:
These steps compress the modified system BIOS. Probably the same as using LHA compressor with modified header. I'll check it
later
quote:
This hack had been done to ABIT AN7 bios version 15... which was not possible to hack with Modbin/Modhack
-then open the AN7.bin (which is injected with the modified system_bios file) with hex editor
-copy the new compressed system_bios in the injected AN7.bin and save it to blank binary file, named system.bin.
-copy the hacked system.bin file (note: this file is compressed in the previous steps) and paste it ON the original_tmp/
system_bios file in Abit.bin
offtopic: Hei tictac I thought you're joining an English course in Bali . I'm just kidding man. Good work, as always
Polygon:
The first thing I'll try is putting all the modules back in to see if the process can even be done. Note that while I have deleted
(released) all the modules with CBRom155, I used BIOS Information Tool(Bit) to extract them all at once.
I put all the modules back in the same order until I got to the Logo. I realized I had installed the Logo.bmp for the EPA bitmap. So
I release the EPA Logo and reinserted both at the end. Here's what it looks like now. Notice my file names are slightly different
then the original. Saves typing time :
As a test I opened the BIOS in Modbin6 and it seems perfectly normal. I'll flash it tonight when I get home just as a sanity check,
but it should be fine.
Remember CBRom fixes the checksum, and I used CBRom155. I recently ran into a BIOS mod that required all the modules to be
in the original order or it would not boot. So I figured this would work....
Next is to see what I can do with the shell that I had made a copy of....
I tried following the steps outlined and ran into some minor trouble. I'll outline what happened, step-by-step, with the solutions I
used:
quote:
This hack had been done to ABIT AN7 bios version 15... which was not possible to hack with Modbin/Modhack OK
-now re-open back an7.bin the bios file with hex editor OK
-copy the hacked system.bin file (note: this file is compressed in the previous steps) and paste it ON the original_tmp/
system_bios file in Abit.bin OK, but I would add: Make sure the exact number of bytes is pasted over, that is copied, or
there may be problems. Also if the new system bios is smaller, and there is code remaining from the old system bios,
change those bytes to FFh bytes. If the new system bios is bigger, no problem. I check the block size of the bios.rom,
and go to 10000h in the shell BIOS. I then select a block size from 10000h to the bios.rom size+1, and paste. The
block size+1 takes care of 00h not being counted in the block size of bios.rom
-then re-install back all bios module with Cbrom OK, we removed all the modules before copying the compressed
modified system.bin to the main BIOS. Reinstalling them all not only fixes the checksum, but takes care of the fact
that the system bios is usually not the exact same size as the original, and puts everything in the correct place.
Post any questions on this technique in the How to Change Original.tmp in Award6 bios, Quick Guide from tictac: Discussion Topic
For a step-by-step tutorial, see: Adding a New Item to a BIOS Without _ITEM.BIN
Remember, the information presented may not work for you. If you are not comfortable
modifing BIOS's and flashing them, do not attempt to modify them.
Adding a New Item To an AWARD BIOS
Credits:
This project could not have been accomplished without the help and knowledge of Pinczakko , tictac, luk1999! Thanks guy's!
Limitations:
It must be noted that as of this posting, only AMD powered boards, with AWARD BIOS, have been successfully modified by
the following technique. Intel Options ROMs are not working at this time. Also, due to the nature of BIOS from ASUS,
Gigabyte, and MSI, this technique may not be possible with those boards.
Post questions about this technique in the: Adding a New Item To an AWARD BIOS Discussion Thread
Prerequisites:
To be able to understand and perform this technique, you must have a total understanding of the interaction between the
_ITEM.BIN and _EN_CODE.BIN BIOS modules. The _ITEM.BIN Module And It's Interaction With _EN_CODE.BIN topic must be
studied and understood by making some changes to test mods BIOS. Without the 110% understanding of these 2 BIOS
modules, a new Item cannot be generated successfully.
The ability to write source code for an ISA Option ROM is also a must. This means you must be familiar with Assembly
Language and AMD data sheets for A64 and AM2 processors. See Building Your Own AWARD ISA Option ROM Write some
code, compile it, and make sure it works in your BIOS.
The 2 requirements above, assume that you are adept at using Modbin6, CBROM32, Hex Editor, IDA Disassembler, and FASM
or another compiler, at a minimum.
Basics:
To add a brand new Item, we will use 1 of these 5 unused branches. Almost every BIOS I have looked at has at least 3 and in
this exact position. Later on in this topic, we will look at how to add a Item if your BIOS has no unused branch available.
Here I have gone into the top blank branch and changed the visibility from "Disable" to "Normal" This will allow me to find the
25 Byte sequence in the _ITEM.BIN module for this branch using the compare tool of Hex Workshop.
Here's the detailed definition of a typical _ITEM.BIN 25 byte sequence. Note the 1st byte and it's possible values. Our branch
went from "Disable"(08h) to "Normal"(00h):
I found that coping the sequences of interest to notepad, and separating the bytes with spaces, the work effort was much
easier. Especially with the address of the 1st byte, labeled in front of the sequence:
Here's a screen shot of the 25 byte sequence in the _ITEM.BIN of interest. I'm using the compare tool of Hex Workshop, on a
unmodded _ITEM.BIN module(top) and a modified _ITEM.BIN module(bottom). In the top window the highlighted byte is the
08h indicating a "Disabled" branch or Item. Note in the bottom window, that byte is now 00h due to the modification by
Modbin6:
In this screen shot, I have edited the _ITEM.BIN module sequence for a theoretical BIOS that has no CAS Item. In red are
the changed bytes that correspond to the added Item label and settings labels, shown in the edited _EN_CODE.BIN module
below this. I chose CMOS register 20h, after a search for 0020h revealed 20h was not being used as a index register. The
mask of 0Fh just sets everything in 20h to 0000b, other then the bit that is of interest. To enable the new Item to work
correctly, the 1st mask, 0Fh, must also be added.
To understand what I'm doing here, you must understand the material presented in the topic:
The _ITEM.BIN Module And It's Interaction With _EN_CODE.BIN: Adding a Little More Space
Here's the _EN_CODE.BIN module before adding the labels needed:
Here's the _EN_CODE.BIN module after adding the labels needed along with their addresses in "Little Endian" notation:
Here is the finished BIOS less the Option ROM. I believe the pictures speak for themselves. All that's left to do is Insert the
Option ROM, and move the Item to where we want it.
Now that we have the BIOS set up for the new Item "CAS", we will look at the code for the ISA Option ROM that will read the
CMOS settings and set the CAS register as we desire.
Here's the heart of the code to read the CMOS register and set the correct CAS timing. It is heavily commented and has no
constants, or subroutines for ease of review. Be aware that the code while technically correct, is for a theoretical system and
not for a current system as AM2 does not have Cas 2 or 2.5 and does have several more timing options. The code is for
reference only and intended to be used as a starting point or template for your code...
This is copy and pasteable complete code that can be used as a starting point or template for your code.
code:
ROMStart:
db 0x055, 0x0AA ; ROM Header 55,AA -> Bootable rom
db (ROMEnd - ROMStart)/512 ; ROM Size in 512byte
jmp MAIN ; jump to main routine
db 0 ; checksum, to be filled in later
MAIN:
pushfd
push eax
push ebx
push bx
push dx
push si
push ds
push bp ; clear the registers for use by pushing the data down
;
==========================================================================================================================
;
; Set Memory Cas Biostar 6100-550 N5TAA207 BIOS
; _ITEM.BIN sequence: 0380h
; CMOS: 020h, mask: 0Fh
;
;
==========================================================================================================================
;read CMOS
mov eax, 0h ;set eax=0h
mov al, 20h ;enter 20h in al
out 072h, al ;set 72h port with 20h address
in al, 073h ;get data in 20h register
and al, 0Fh ;mask 0000.1111b data
mov bl, al ;move data to bl
cmp bl, 03h ;compare data to 03h
jne cas2 ;jump if not equal 0000.0011b
jmp codend ;Auto selected, got to end
cas2:
;read CMOS
mov eax, 0h ;set eax=0h
mov al, 20h ;enter 20h in al
out 072h, al ;set 72h port with 20h address
in al, 073h ;get data in 20h register
and al, 0Fh ;mask 0000.1111b data
mov bl, al ;move data to bl
cmp bl, 00h ;compare data to 00h
jne cas25 ;jump if not equal 0000.0000b
;set CAS=2
mov eax,08000C288h ;copy register address DRAM Timing Low Register
mov ebx,000000000h ;copy register data for CAS 2T
mov dx,0CF8h ;set port address
out dx,eax ;send address through the port
mov dx,0CFCh ;set port data
in eax,dx ;get data
and eax,0FFFFFFF8h ;mask data
or eax,ebx ;increase data
out dx,eax ;send data through port data
;
==========================================================================================================================
cas25:
;read CMOS
mov eax, 0h ;set eax=0h
mov al, 20h ;enter 20h in al
out 072h, al ;set 72h port with 20h address
in al, 073h ;get data in 20h register
and al, 0Fh ;mask 0000.1111b data
mov bl, al ;move data to bl
cmp bl, 01h ;compare data to 01h
jne cas3 ;jump if not equal 0000.0001b
;set CAS=2.5
mov eax,08000C288h ;copy register address DRAM Timing Low Register
mov ebx,000000001h ;copy register data for CAS 2.5T
mov dx,0CF8h ;set port address
out dx,eax ;send address through the port
mov dx,0CFCh ;set port data
in eax,dx ;get data
and eax,0FFFFFFF8h ;mask data
or eax,ebx ;increase data
out dx,eax ;send data through port data
;
==========================================================================================================================
cas3:
;read CMOS
mov eax, 0h ;set eax=0h
mov al, 20h ;enter 20h in al
out 072h, al ;set 72h port with 20h address
in al, 073h ;get data in 20h register
and al, 0Fh ;mask 0000.1111b data
mov bl, al ;move data to bl
cmp bl, 02h ;compare data to 02h
jne cas25 ;jump if not equal 0000.0010b
;set CAS=3
mov eax,08000C288h ;copy register address DRAM Timing Low Register
mov ebx,000000002h ;copy register data for CAS 3T
mov dx,0CF8h ;set port address
out dx,eax ;send address through the port
mov dx,0CFCh ;set port data
in eax,dx ;get data
and eax,0FFFFFFF8h ;mask data
or eax,ebx ;increase data
out dx,eax ;send data through port data
;
==========================================================================================================================
codend:
pop bp
pop ds
pop si
pop dx
pop bx
pop ebx
pop eax
popfd ; clear the registers and return data as we are finished
retf ; return far to system bios routine
times (ROM_SIZE_IN_BYTE-$) db 0 ; use 00h as the padding bytes until we reach the ROM size
; The last byte (512th) will be the patch_byte for the checksum
PREV_CHKSUM = 0
repeat $
load CHKSUM byte from %-1
CHKSUM = (PREV_CHKSUM + CHKSUM) mod 0x100
PREV_CHKSUM = CHKSUM
end repeat
store byte (0x100 - CHKSUM) at ($-1) ; store the patch_byte
ROMEnd:
Here's the disassembled code that gives it a check that everything is reasonably correct:
If we did everything correctly, we now have a brand new Item added to our BIOS I didn't bother to move it so it can be
seen to still be under "Maximum Payload", which is where our unused branch was located. And again, even though I actually
did every step to create a new Item, this instructional topic is/was not intended to be a actually mod. It is for reference only.
Be aware that to become accomplished at this technique, has taken me more then a year of intensive BIOS study, literally
hundreds of lesser BIOS modifications, and at least 50 hot flashes. It is something that will not be learned overnight as every
BIOS modification discipline there is, is required to be understood 110%.....
I'm working on a Mod BIOS that will add 2 new Items. I might as well photo document the steps, as 2 or more items require
some special considerations
I located the 2 sequences for the 2 branches I'll use by making them visable by using Modbin, and then doing a compare
using Hex Workshop.
This is the last address group in the _EN_CODE.BIN module. It has 35h entries. It is after this code, I will add our Item and
Setting labels.
Here I've added the labels for 2 new Items and their settings. Address list number 35h, changes to 39h. The 4 addresses of
the new labels are added. The address of a label is the Hex position, in "Little Endian" notation, of the 1st letter. The address
of the settings is the 1st letter of the 1st setting label only.
Back to the _ITEM.BIN module to add all the required addresses, defaults, and mask/index/mask. Note that our original 25
byte sequences only had 1 mask, but 2 are needed. 1 for the Setup defaults and 1 for the BIOS defaults. Also note that the
2nd 25 byte sequence has the mask 70h, while the 1st 25 byte sequence uses 07h. The 1st 25 byte sequence will write to the
1st 4 bits of the 20h register, and the 2nd 25 byte sequence will write to the 2nd 4 bits of the 20h register. I did a search of
the _ITEM.BIN module for Hex sequence 0020h, to make sure 20h was not being used already.
A quick test in Modbin shows the 2 new Items now labeled, and in the original location right now.
The first new Item is Read/Write Queue Bypass. I set the defaults to 16x:
The 2nd new Item is Tref. I've set the defaults to [email protected].
And a quick flash shows the new Items and settings.
The BIOS has no ISA Option ROM at this point, so the settings don't do anything.
Here I have moved the 2 new Items to the Advanced Chipset Features window. I can't put them under the "DRAM
Configuration" heading because everything in there can be disabled. Adding an Item into a linked window corrupts the BIOS.
So above the "DRAM Configuration" is going to have to do.
And now the source code for the ISA Option ROM that reads the CMOS register and sets the timings accordingly. The code
could be written with constants, and subroutines, but for me it's easier to trouble shoot like this.(8-12-07 Code Updated: Tref
data in AMD data sheet may be incorrect! Source code fixed.)(10-22-07 Source Code Updated: Add jump over all code if
DDRII Timing Item in BIOS is disabled and add Idle Cycle Limit code to fix non-working Item):
code:
ROMStart:
db 0x055, 0x0AA ; ROM Header 55,AA -> Bootable rom
db (ROMEnd - ROMStart)/512 ; ROM Size in 512byte
jmp MAIN ; jump to main routine
db 0 ; checksum, to be filled in later
MAIN:
pushfd
push eax
push ebx
push ecx
push dx
;====================================================================
; R/W Queue Bypass & Tref AN8_21.RH BIOS
; _ITEM.BIN: 031Ch CMOS: 021h mask: 07h R/W Queue Bypass
; CMOS: 021h mask: F0h Tref
; CMOS: 088H mask: E0h Idle Cycle Limit
; _ITEM.BIN: 0F92h CMOS: 81h mask: 30h DRAM Config(Auto, SPD, Manual)
;====================================================================
;====================================================================
TREF:
mov al, cl ;use saved data
and al,0F0h ;mask 1111.0000
cmp al, 00h
je ICL ;jump if equal 0000.0000, AUTO SELECTED
cmp al, 10h
je [email protected] ;jump if equal 0001.0000
cmp al, 20h
je [email protected] ;jump if equal 0010.0000
cmp al, 30h
je [email protected] ;jump if equal 0011.0000
cmp al, 40h
je [email protected] ;jump if equal 0100.0000
cmp al, 50h
je [email protected] ;jump if equal 0101.0000
cmp al, 60h
je [email protected] ;jump if equal 0110.0000
cmp al, 70h
je [email protected] ;jump if equal 0111.0000
cmp al, 80h
je [email protected] ;jump if equal 1000.0000
cmp al, 90h
je [email protected] ;jump if equal 1001.0000
cmp al, 0A0h
je [email protected] ;jump if equal 1010.0000
cmp al, 0B0h
je [email protected] ;jump if equal 1011.0000
cmp al, 0C0h
je [email protected] ;jump if equal 1100.0000
jmp ICL
[email protected]:
;set [email protected]
mov eax,08000C28Ch ; DRAM Timing High Address
mov ebx,000000000h ; [email protected]
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFFFE0FFh ;
or eax,ebx ;
out dx,eax ;
jmp ICL
[email protected]:
;set [email protected]
mov eax,08000C28Ch ; DRAM Timing High Address
mov ebx,000000100h ; [email protected]
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFFFE0FFh ; mask data
or eax,ebx ;
out dx,eax ;
jmp ICL
[email protected]:
;set [email protected]
mov eax,08000C28Ch ; DRAM Timing High Address
mov ebx,000000200h ; [email protected]
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFFFE0FFh ; mask data
or eax,ebx ;
out dx,eax ;
jmp ICL
[email protected]:
;set [email protected]
mov eax,08000C28Ch ; DRAM Timing High Address
mov ebx,000000300h ; [email protected]
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFFFE0FFh ; mask data
or eax,ebx ;
out dx,eax ;
jmp ICL
;===============================================================================
[email protected]:
;set [email protected]
mov eax,08000C28Ch ; DRAM Timing High Address
mov ebx,000000400h ; [email protected]
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFFFE0FFh ;
or eax,ebx ;
out dx,eax ;
jmp ICL
[email protected]:
;set [email protected]
mov eax,08000C28Ch ; DRAM Timing High Address
mov ebx,000000500h ; [email protected]
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFFFE0FFh ; mask data
or eax,ebx ;
out dx,eax ;
jmp ICL
[email protected]:
;set [email protected]
mov eax,08000C28Ch ; DRAM Timing High Address
mov ebx,000000600h ; [email protected]
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFFFE0FFh ; mask data
or eax,ebx ;
out dx,eax ;
jmp ICL
[email protected]:
;set [email protected]
mov eax,08000C28Ch ; DRAM Timing High Address
mov ebx,000000700h ; [email protected]
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFFFE0FFh ; mask data
or eax,ebx ;
out dx,eax ;
jmp ICL
;===============================================================================
[email protected]:
;set [email protected]
mov eax,08000C28Ch ; DRAM Timing High Address
mov ebx,000000800h ; [email protected]
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFFFE0FFh ;
or eax,ebx ;
out dx,eax ;
jmp ICL
[email protected]:
;set [email protected]
mov eax,08000C28Ch ; DRAM Timing High Address
mov ebx,000000900h ; [email protected]
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFFFE0FFh ; mask data
or eax,ebx ;
out dx,eax ;
jmp ICL
[email protected]:
;set [email protected]
mov eax,08000C28Ch ; DRAM Timing High Address
mov ebx,000000A00h ; [email protected]
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFFFE0FFh ; mask data
or eax,ebx ;
out dx,eax ;
jmp ICL
[email protected]:
;set [email protected]
mov eax,08000C28Ch ; DRAM Timing High Address
mov ebx,000000B00h ; [email protected]
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFFFE0FFh ; mask data
or eax,ebx ;
out dx,eax ;
ICL:
;reading from cmos
mov al, 088h ;index - 0??h
out 072h, al ;send register offset
in al, 073h ;fetch data
and al, 0E0h ;mask 1110.0000
ICL0:
;set Idle Cycle Limit 0X
mov eax,08000C294h ; DRAM Configuration High Address
mov ebx,000000000h ; 0X
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFF8FFFFh ;
or eax,ebx ;
out dx,eax ;
jmp codend
ICL4:
;set Idle Cycle Limit 4X
mov eax,08000C294h ; DRAM Configuration High Address
mov ebx,000010000h ; 4X
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFF8FFFFh ;
or eax,ebx ;
out dx,eax ;
jmp codend
ICL8:
;set Idle Cycle Limit 8X
mov eax,08000C294h ; DRAM Configuration High Address
mov ebx,000020000h ; 8X
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFF8FFFFh ;
or eax,ebx ;
out dx,eax ;
jmp codend
ICL16:
;set Idle Cycle Limit 16X
mov eax,08000C294h ; DRAM Configuration High Address
mov ebx,000030000h ; 16X
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFF8FFFFh ;
or eax,ebx ;
out dx,eax ;
jmp codend
ICL32:
;set Idle Cycle Limit 32X
mov eax,08000C294h ; DRAM Configuration High Address
mov ebx,000040000h ; 32X
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFF8FFFFh ;
or eax,ebx ;
out dx,eax ;
jmp codend
ICL64:
;set Idle Cycle Limit 64X
mov eax,08000C294h ; DRAM Configuration High Address
mov ebx,000050000h ; 64X
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFF8FFFFh ;
or eax,ebx ;
out dx,eax ;
jmp codend
ICL128:
;set Idle Cycle Limit 128X
mov eax,08000C294h ; DRAM Configuration High Address
mov ebx,000060000h ; 128X
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFF8FFFFh ;
or eax,ebx ;
out dx,eax ;
jmp codend
ICL256:
;set Idle Cycle Limit 256X
mov eax,08000C294h ; DRAM Configuration High Address
mov ebx,000070000h ; 256X
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFF8FFFFh ;
or eax,ebx ;
out dx,eax ;
codend:
pop dx
pop ecx
pop ebx
pop eax
popfd
retf ; return far to system bios routine
times (ROM_SIZE_IN_BYTE-$) db 0 ; use 00h as the padding bytes until we reach the ROM size
; The last byte (512th) will be the patch_byte for the checksum
PREV_CHKSUM = 0
repeat $
load CHKSUM byte from %-1
CHKSUM = (PREV_CHKSUM + CHKSUM) mod 0x100
PREV_CHKSUM = CHKSUM
end repeat
store byte (0x100 - CHKSUM) at ($-1) ; store the patch_byte
ROMEnd:
The Mod BIOS adding new Items Tref and R/W Queue Bypass, is working perfectly. The BIOS is released publicly:
2 New Items Added: RHCF Advanced Mod AN821RHX Bios for AN8 Series!
--------------------
One last set of tweaks and this mod BIOS is finished! I increased the number of settings by 1 each, and added "Auto" as the
first setting/label in the list. The 00h Hex number in the CMOS register 20h, will be read by the ISA ROM, and just bypass all
comparators and not change what the original BIOS set for these 2 memory settings. I also added the right hand pane Item
descriptions for both newly added Items.
Here's another use for this advanced technique...
An AM2 BIOS that overclocks well, has the Async Latency apparently not working. It is always 6ns no matter what the BIOS
is set for. We find the Async Latency sequence in the _ITEM.BIN module and note that the index is A3h and the mask is
0Fh.....
We then write the code for an ISA Option ROM that reads the A3h CMOS register and sets the Async Latency accordingly.
Testing of the mod BIOS finds the Async Latency now working. Some issues about clearing the CMOS were discovered later
on, but the basic concept for this fix is valid. Here is the source code for that ROM:
code:
ROMStart:
db 0x055, 0x0AA ; ROM Header 55,AA -> Bootable rom
db (ROMEnd - ROMStart)/512 ; ROM Size in 512byte
jmp MAIN ; jump to main routine
db 0 ; checksum, to be filled in later
MAIN:
pushfd
push eax
push ebx
push ecx
push dx
;====================================================================
; Async Latency Fix CR51A505.RHx BIOS
; _ITEM.BIN: 1168h
; CMOS: 0A3h
; mask: 0Fh
;====================================================================
jmp codend
AUTO:
;set Async Lat 6T
mov eax,08000C294h ; DRAM Config High Address
mov ebx,000000060h ; Async Lat 6T
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFFFFF0Fh ;
or eax,ebx ;
out dx,eax ;
jmp codend
ASL1:
;set Async Lat 1T
mov eax,08000C294h ; DRAM Config High Address
mov ebx,000000010h ; Async Lat 1T
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFFFFF0Fh ;
or eax,ebx ;
out dx,eax ;
jmp codend
ASL2:
;set Async Lat 2T
mov eax,08000C294h ; DRAM Config High Address
mov ebx,000000020h ; Async Lat 2T
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFFFFF0Fh ;
or eax,ebx ;
out dx,eax ;
jmp codend
ASL3:
;set Async Lat 3T
mov eax,08000C294h ; DRAM Config High Address
mov ebx,000000030h ; Async Lat 3T
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFFFFF0Fh ;
or eax,ebx ;
out dx,eax ;
jmp codend
ASL4:
;set Async Lat 4T
mov eax,08000C294h ; DRAM Config High Address
mov ebx,000000040h ; Async Lat 4T
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFFFFF0Fh ;
or eax,ebx ;
out dx,eax ;
jmp codend
ASL5:
;set Async Lat 5T
mov eax,08000C294h ; DRAM Config High Address
mov ebx,000000050h ; Async Lat 5T
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFFFFF0Fh ;
or eax,ebx ;
out dx,eax ;
jmp codend
ASL6:
;set Async Lat 6T
mov eax,08000C294h ; DRAM Config High Address
mov ebx,000000060h ; Async Lat 6T
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFFFFF0Fh ;
or eax,ebx ;
out dx,eax ;
jmp codend
ASL7:
;set Async Lat 7T
mov eax,08000C294h ; DRAM Config High Address
mov ebx,000000070h ; Async Lat 7T
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFFFFF0Fh ;
or eax,ebx ;
out dx,eax ;
jmp codend
ASL8:
;set Async Lat 8T
mov eax,08000C294h ; DRAM Config High Address
mov ebx,000000080h ; Async Lat 8T
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFFFFF0Fh ;
or eax,ebx ;
out dx,eax ;
jmp codend
ASL9:
;set Async Lat 9T
mov eax,08000C294h ; DRAM Config High Address
mov ebx,000000090h ; Async Lat 9T
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFFFFF0Fh ;
or eax,ebx ;
out dx,eax ;
jmp codend
ASL10:
;set Async Lat 10T
mov eax,08000C294h ; DRAM Config High Address
mov ebx,0000000A0h ; Async Lat 10T
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFFFFF0Fh ;
or eax,ebx ;
out dx,eax ;
jmp codend
ASL11:
;set Async Lat 11T
mov eax,08000C294h ; DRAM Config High Address
mov ebx,0000000B0h ; Async Lat 11T
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFFFFF0Fh ;
or eax,ebx ;
out dx,eax ;
jmp codend
ASL12:
;set Async Lat 12T
mov eax,08000C294h ; DRAM Config High Address
mov ebx,0000000C0h ; Async Lat 12T
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFFFFF0Fh ;
or eax,ebx ;
out dx,eax ;
jmp codend
ASL13:
;set Async Lat 13T
mov eax,08000C294h ; DRAM Config High Address
mov ebx,0000000D0h ; Async Lat 13T
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFFFFF0Fh ;
or eax,ebx ;
out dx,eax ;
jmp codend
ASL14:
;set Async Lat 14T
mov eax,08000C294h ; DRAM Config High Address
mov ebx,0000000E0h ; Async Lat 14T
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFFFFF0Fh ;
or eax,ebx ;
out dx,eax ;
jmp codend
ASL15:
;set Async Lat 15T
mov eax,08000C294h ; DRAM Config High Address
mov ebx,0000000F0h ; Async Lat 15T
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFFFFF0Fh ;
or eax,ebx ;
out dx,eax ;
jmp codend
codend:
pop dx
pop ecx
pop ebx
pop eax
popfd
retf ; return far to system bios routine
times (ROM_SIZE_IN_BYTE-$) db 0 ; use 00h as the padding bytes until we reach the ROM size
; The last byte (512th) will be the patch_byte for the checksum
PREV_CHKSUM = 0
repeat $
load CHKSUM byte from %-1
CHKSUM = (PREV_CHKSUM + CHKSUM) mod 0x100
PREV_CHKSUM = CHKSUM
end repeat
store byte (0x100 - CHKSUM) at ($-1) ; store the patch_byte
ROMEnd:
The Mod BIOS fixing the Async Latency Item is working perfectly, and is released publicly.
See: Rebels Haven Releases CR51A505RX Advanced Mod BIOS Series for 6100-AM2!
Here's the screen shots I made for adding 3 new Items to the Biostar 6100-AM2 BIOS. I also grouped 4 Spread Spectrum
Items under 1 new heading. The finished BIOS was released publicly in this topic: Rebels Haven Releases CR51A316.RHX
Advanced Mod BIOS: 6100-AM2: 3 New items Added!
First thing was to locate the 5 Sequences in _ITEM.BIN module. The grouping and moving was done with Modbin6 before any
mods went in. Top window is before, bottom is after the changes:
All the address pointers, labels, settings, and right hand information pane data was added. I could have added the address
pointers to the list directly in front of where I added a new list starting with the highlighted 08h byte. BTW, no checksum
correction needed:
And finally the source code for the ISA Option ROM that will read the CMOS data and set the 3 new memory Items:
code:
ROMStart:
db 0x055, 0x0AA ; ROM Header 55,AA -> Bootable rom
db (ROMEnd - ROMStart)/512 ; ROM Size in 512byte
jmp MAIN ; jump to main routine
db 0 ; checksum, to be filled in later
MAIN:
pushfd
push eax
push ebx
push ecx
push dx
;====================================================================
; Trtw, Tref, Async Latency CR51A316.RHx BIOS
; _ITEM.BIN: 0352h
; index: 20h mask: 0Fh Trwt
; index: 20h mask: F0h Tref
; index: 21h mask: 0Fh Async Latency
;====================================================================
TRTW2:
;set Trtw 2T
mov eax,08000C28Ch ; DRAM Timing High Address
mov ebx,000000000h ; 2T
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFFFFF8Fh ;
or eax,ebx ;
out dx,eax ;
jmp TREF
TRTW3:
;set Trtw 3T
mov eax,08000C28Ch ; DRAM Timing High Address
mov ebx,000000010h ; 3T
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFFFFF8Fh ;
or eax,ebx ;
out dx,eax ;
jmp TREF
TRTW4:
;set Trtw 4T
mov eax,08000C28Ch ; DRAM Timing High Address
mov ebx,000000020h ; 4T
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFFFFF8Fh ;
or eax,ebx ;
out dx,eax ;
jmp TREF
TRTW5:
;set Trtw 5T
mov eax,08000C28Ch ; DRAM Timing High Address
mov ebx,000000030h ; 5T
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFFFFF8Fh ;
or eax,ebx ;
out dx,eax ;
jmp TREF
TRTW6:
;set Trtw 6T
mov eax,08000C28Ch ; DRAM Timing High Address
mov ebx,000000040h ; 6T
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFFFFF8Fh ;
or eax,ebx ;
out dx,eax ;
jmp TREF
TRTW7:
;set Trtw 7T
mov eax,08000C28Ch ; DRAM Timing High Address
mov ebx,000000050h ; 7T
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFFFFF8Fh ;
or eax,ebx ;
out dx,eax ;
jmp TREF
TRTW8:
;set Trtw 8T
mov eax,08000C28Ch ; DRAM Timing High Address
mov ebx,000000060h ; 8T
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFFFFF8Fh ;
or eax,ebx ;
out dx,eax ;
jmp TREF
TRTW9:
;set Trtw 9T
mov eax,08000C28Ch ; DRAM Timing High Address
mov ebx,000000070h ; 9T
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFFFFF8Fh ;
or eax,ebx ;
out dx,eax ;
;==========================================================
TREF:
;reading from cmos
mov al, 020h ;index - 020h
out 072h, al ;send register offset
in al, 073h ;fetch data
and al, 0F0h ;mask 1111.0000
TREF1:
;set Tref 15.6usec
mov eax,08000C28Ch ; DRAM Timing High Address
mov ebx,000010000h ; Tref 15.6usec
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFFCFFFFh ;
or eax,ebx ;
out dx,eax ;
jmp ASL
TREF2:
;set Tref 7.8usec
mov eax,08000C28Ch ; DRAM Timing High Address
mov ebx,000020000h ; Tref 7.8usec
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFFCFFFFh ;
or eax,ebx ;
out dx,eax ;
jmp ASL
TREF3:
;set Tref 3.9usec
mov eax,08000C28Ch ; DRAM Timing High Address
mov ebx,000030000h ; Tref 3.9usec
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFFCFFFFh ;
or eax,ebx ;
out dx,eax ;
ASL:
;reading from cmos
mov al, 021h ;index - 021h
out 072h, al ;send register offset
in al, 073h ;fetch data
and al, 0Fh ;mask 0000.1111
jmp codend
ASL5:
;set Async Lat 5T
mov eax,08000C294h ; DRAM Config High Address
mov ebx,000000050h ; Async Lat 5T
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFFFFF0Fh ;
or eax,ebx ;
out dx,eax ;
jmp codend
ASL6:
;set Async Lat 6T
mov eax,08000C294h ; DRAM Config High Address
mov ebx,000000060h ; Async Lat 6T
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFFFFF0Fh ;
or eax,ebx ;
out dx,eax ;
jmp codend
ASL7:
;set Async Lat 7T
mov eax,08000C294h ; DRAM Config High Address
mov ebx,000000070h ; Async Lat 7T
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFFFFF0Fh ;
or eax,ebx ;
out dx,eax ;
jmp codend
ASL8:
;set Async Lat 8T
mov eax,08000C294h ; DRAM Config High Address
mov ebx,000000080h ; Async Lat 8T
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFFFFF0Fh ;
or eax,ebx ;
out dx,eax ;
jmp codend
ASL9:
;set Async Lat 9T
mov eax,08000C294h ; DRAM Config High Address
mov ebx,000000090h ; Async Lat 9T
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFFFFF0Fh ;
or eax,ebx ;
out dx,eax ;
jmp codend
ASL10:
;set Async Lat 10T
mov eax,08000C294h ; DRAM Config High Address
mov ebx,0000000A0h ; Async Lat 10T
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFFFFF0Fh ;
or eax,ebx ;
out dx,eax ;
jmp codend
ASL11:
;set Async Lat 11T
mov eax,08000C294h ; DRAM Config High Address
mov ebx,0000000B0h ; Async Lat 11T
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFFFFF0Fh ;
or eax,ebx ;
out dx,eax ;
jmp codend
ASL12:
;set Async Lat 12T
mov eax,08000C294h ; DRAM Config High Address
mov ebx,0000000C0h ; Async Lat 12T
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFFFFF0Fh ;
or eax,ebx ;
out dx,eax ;
jmp codend
ASL13:
;set Async Lat 13T
mov eax,08000C294h ; DRAM Config High Address
mov ebx,0000000D0h ; Async Lat 13T
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFFFFF0Fh ;
or eax,ebx ;
out dx,eax ;
jmp codend
ASL14:
;set Async Lat 14T
mov eax,08000C294h ; DRAM Config High Address
mov ebx,0000000E0h ; Async Lat 14T
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFFFFF0Fh ;
or eax,ebx ;
out dx,eax ;
jmp codend
ASL15:
;set Async Lat 15T
mov eax,08000C294h ; DRAM Config High Address
mov ebx,0000000F0h ; Async Lat 15T
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFFFFF0Fh ;
or eax,ebx ;
out dx,eax ;
codend:
pop dx
pop ecx
pop ebx
pop eax
popfd
retf ; return far to system bios routine
times (ROM_SIZE_IN_BYTE-$) db 0 ; use 00h as the padding bytes until we reach the ROM size
; The last byte (512th) will be the patch_byte for the checksum
PREV_CHKSUM = 0
repeat $
load CHKSUM byte from %-1
CHKSUM = (PREV_CHKSUM + CHKSUM) mod 0x100
PREV_CHKSUM = CHKSUM
end repeat
store byte (0x100 - CHKSUM) at ($-1) ; store the patch_byte
ROMEnd:
After doing over 15 or more Mods, where 1 or more Items were added to a BIOS, the most noticeable issue with the new
BIOS has to do with resetting defaults. This would be accomplished by a CMOS Clear or simply loading Optimized Defaults.
Some BIOS work fine, while other fail to reboot which renders the system dead. There is no question that the CMOS index(s)
used for the new Item(s) contributes to the issue. A while back luk1999 suggested a relatively simple fix. I'm finding that not
only is this a good idea, but should be included as a matter-of-fact in the ISA Option ROM code.
code:
mov eax, 0h
mov al, 50h
out 072h, al
in al, 073h
and al, 01h
mov bl, al
cmp bl, 01h
jne @code_end
;
; here's a place for code
; we can place here what we want :)
;
@code_end:
Remember, the information presented may not work for you. If you are not comfortable
modifying BIOS's and flashing them, do not attempt to modify them.
--------------------
Adding a New Item to a BIOS Without _ITEM.BIN
This topic will describe how to add new Items to a BIOS that has no _ITEM.BIN module. The BIOS being modified is for the
MSI Neo2 Platinum. It is 7025v1D0 and was released 1/29/07....
It is assumed that you are familiar with the topic: Adding a New Item To an AWARD BIOS
And you are familiar with this topic: How to Change Original.tmp in Award6.0 bios, Quick Guide from tictac
Post questions about this technique in the: Adding a New Item To an AWARD BIOS Discussion Thread
The first thing that needs to be done is find the blank branches, label them, and move them into the desired position using
Modbin6. Then using CBROM, release all the modules so that only the system bios is present in a shell BIOS. I make
several copies of this shell, as a few things later on, turn out to be trial and error:
One of the tougher tasks is to find unused CMOS Indexes that can be used for our new Items. I chose 6Ah and 6Bh as they
are surrounded by what appears to be other unused Indexes. Only testing of the BIOS will tell for sure if choosing these
was the right decision. I did scan the sequences for instances of these 2 bytes, and it came back as not being used. Edit:
6Ah and 6Bh were being used, so I switched to 20h and 21h.
To find the location of the 25 byte sequences for our 5 new Items, we compared the unmodded system bios with the
modified version that has the new Items made visible. I then make a notepad version of the sequences, labeling as
necessary, so I don't have to go back and look anything up. I then add in the mods as necessary:
We need the exact, compressed, system bios so that it can be pasted over the unmodded compressed version that resides
in our shell BIOS. A little trick I noticed is that when adding a module to a BIOS, CBROM generates a file called bios.rom.
This file is the compressed module that was just added. So adding the system.bin file generates a compressed version. I
use this file as that way, there is no question as to where my new system.bin module starts and ends.
To add the modded system.bin to the shell BIOS, I execute: CBROM shell.bin /other 5000:0 system.bin
I had renamed CBROM155 to CB155 for ease of typing:
Here I'm looking at both the beginning and end of the bios.rom file. I need the ending address to create the block in the
shell BIOS that will be pasted over. The ending byte is actually 13831h as the last offset shown is really the next-to-last:
Here I'm going to select the block to be pasted over in a new copy of the shell BIOS I had saved earlier. We enter 13832h
bytes for the block size, as the last offset of the mod system.bios being 13831h does not include the 00h byte:
Here I'm looking at both the beginning of the block to be pasted over and the end. Note that the ending is longer the
original. This is fine and will not require any additional changing of unused bytes. Had the block shown up as shorter, FFh
bytes would need to be entered for the unused leftover bytes:
As a sanity check, I look at the ending bytes of the BIOS before and after pasting the new compressed code. In this case
the unmodded BIOS had 4 words in the last row. So I want there to be only 4 words in the last row after the paste is
performed. Any more or any less is an indication that my blocks were not identical sizes, and the BIOS will be useless:
The _EN_CODE.BIN module had the settings' labels added at the end.
See The _ITEM.BIN Module And It's Interaction With _EN_CODE.BIN topic for the technique:
The last thing to do is write the ISA Option ROM that takes the CMOS data and sets the memory items as set by the new
Items in the BIOS....
When finished and tested, this BIOS will be released to the public.....
The ISA ROM is in the BIOS, but 2 of the new settings are being reset to "Auto" after saving. The index(s) I picked must be
being used for other things.
Edit: Indexes 6Ah and 6Bh were being used by other functions. Once Indexes BCh and BDh were swapped in, the BIOS is
working perfectly. A jump over the code was also implemented to allow CMOS Clear to disable the ISA ROM. The BIOS is
released in this topic: Rebels Haven Releases MSI Neo2 Advanced Mod BIOS: 5 New Items Added!
Here's BIOS screen shots of the MSI Neo2 7025v1D0.RXX in action:
The updated code:
code:
ROMStart:
db 0x055, 0x0AA ; ROM Header 55,AA -> Bootable rom
db (ROMEnd - ROMStart)/512 ; ROM Size in 512byte
jmp MAIN ; jump to main routine
db 0 ; checksum, to be filled in later
;====================================================================
; 7025v1D0.RXx BIOS ISA ROM 10/24/07 2:40pm
; index: BCh mask: 0Fh Idle Cycle Limit
; index: BCh mask: F0h Async Latency
; index: BDh mask: E0h R/W Queue
; index: BDh mask: 1Ch Bypass Max
; index: BDh mask: 03h DQS Slew
; Timing Mode index: 81h mask: 20h
;====================================================================
MAIN:
pushfd
push eax
push ebx
push ecx
push dx
;R/W QUEUE
;reading from cmos
mov al, 0BDh ;index - 0BDh
out 072h, al ;send register offset
in al, 073h ;fetch data
and al, 0E0h ;mask 1110.0000
mov cl, al ;save for later
;Bypass Max
;reading from cmos
mov al, 0BDh ;index - 0BDh
out 072h, al ;send register offset
in al, 073h ;fetch data
and al, 01Ch ;mask 0001.1100
mov cl, al ;save for later
;Async Latency
;reading from cmos
mov al, 0BCh ;index - 0BCh
out 072h, al ;send register offset
in al, 073h ;fetch data
and al, 0F0h ;mask 1111.0000
mov cl, al ;save for later
times (ROM_SIZE_IN_BYTE-$) db 0 ; use 00h as the padding bytes until we reach the ROM size
; The last byte (512th) will be the patch_byte for the checksum
PREV_CHKSUM = 0
repeat $
load CHKSUM byte from %-1
CHKSUM = (PREV_CHKSUM + CHKSUM) mod 0x100
PREV_CHKSUM = CHKSUM
end repeat
store byte (0x100 - CHKSUM) at ($-1) ; store the patch_byte
ROMEnd:
Remember, the information presented may not work for you. If you are not comfortable
modifying BIOS's and flashing them, do not attempt to modify them.
Adding an Item Back in That is Hidden due to CPU Type
Background:
Many times over the years since A64 was released, we have seen BIOS Items disappear when a certain CPU is installed. I
remember installing a San Diego 3700 in my DFI Ultra-D only to find the Command Rate Item was no longer visible.
Eventually a BIOS was released that left it visible, but annoying it was until the BIOS release.
With the recent breakthrough, here at Rebels Haven, of adding a new Item to a BIOS, came the technology to fix non-
working Items, correct settings that were wrong, and now I can show how to get that much needed Item back from the
invisible world!
I was asked to look at the BIOS for the Biostar TF560A2+ that loses "NPT Fid Control"(better known as CPU Multiplier) when
a Phenom CPU is installed. After trying a few things, it dawned on me how to do it, and the technique is almost lame! But
110% understanding of The _ITEM.BIN Module And It's Interaction With _EN_CODE.BIN was what made it very easy!
Anyone that wants to mod BIOS's, must learn the in's and out's of that subject or Modbin/CBROM edits will be the extent of
your capability.
Technique:
The first thing to do is find the Item.Bin Sequence that belongs to the invisible "NPT Fid Control". How to do that is outlined
in above topic link. Next we select a unused Item or select a Item to sacrifice for the cause! I always turn off the "Full Screen
Logo" anyhow, so for this mod, I will use that for my new "CPU Multiplier Control". I then go into the "Full Screen Logo"
sequence and change the bytes such that it will now control the CPU multiplier. The values are taken right from the "NPT Fid
Control" sequence. I then found a unused CMOS Index and changed the "NPT Fid Control" original index to the unused one.
CKCMOS.EXE was used to find the unused index. If we did everything correctly, we now have "CPU Multiplier Setting". I
understand from a member testing the Mod BIOS, that the Phenom was still not adjusting at all. The Technique did work on
a AM2 CPU on the same board, different BIOS, and should work on a A64. The Phenom is either locked or just may be
too complex for this relatively simple mod. Below are the Sequences before and after the mod:
Original Location-->Sequence:
057Dh-->0000 0204 87F8 8000 3E80 0001 0000 0001 0083 0200 0000 0000 00 "Full Screen Logo"
10C4h-->0000 0008 FFFF 3F00 4A3F 0001 0800 002B 0081 0200 0000 0000 00 "NPT Fid Control"
Please post any questions in the Hacking The _ITEM.BIN Module and It's Interaction With _EN_CODE.BIN Thread
Updating the Integrated Memtest Module
As the technology rapidly advances, new chipsets are only supported by newer versions of Memtest. The current version,
1.70, is already known to have some flaws with certain chipsets and will be revised shortly. In the meantime, there is
nothing to stop us from updating our BIOS with the latest version. Be aware that for the following information to work,
your BIOS must already have the memtest program integrated into it.
The Instructions:
The first thing we must do is prepare the memtest binary we are going to use in our BIOS. Into a temp directory, copy
the BIOS to be operated on, the 1.70 binary, and the latest version of CBROM. Here is a hex editor screenshot of the
beginning of a memtest.rom BIOS module compared to the beginning of the Memtest 1.70 Binary. There are hex bytes at
the beginning of the Binary that initializes the program, and then a group of zeros. We must get rid of the hex bytes and
zeros at the beginning of the binary in order to be able to use it in a BIOS. The BIOS has another module called
memsetup.rom and it contains the code needed to initialize Memtest. Delete everything before the FCFAh byte, including
the large group of zeros. After all hex bytes before FCFAh are deleted and the binary is saved, rename the modified
binary: memtest.rom
The next thing to do is using Cbrom, check to see where the memtest binary is located. At the command prompt, we
execute Cbrom yourbios.bin /D. In this BIOS memtest.rom is resident as "OEM4" In your BIOS, Memtest may be named
something different:
So to remove the existing memtest rom, at the command prompt, we execute Cbrom yourbios.bin /oem4 release. Then
we insert the new Memtest rom into the BIOS by executing Cbrom yourbios.bin /oem4 memtest.rom. In my screenshot,
I'm using Cbrom 1.55 which I renamed CB155 for ease of typing. Substitute the name of the BIOS to be operated on, for
"yourbios.bin". Flash the BIOS and your done.
If we're successful, enabling the integrated memory testing program option in the BIOS, gives us: (Note the 965 chipset
and the memory timings are blank in 1.70)
Updating the memsetup.rom Module
Generally, Memtest 1.70 can be updated into a BIOS that has version 1.55, 1.60 or 1.65, without issue.
Probably updating an older version will require updating the memsetup.rom module also. I recently
updated the memtest.rom module of a BIOS only to find it didn't work. When enabled, the internal
Memtest program never ran. Only thing left to do was update the memsetup.rom module with the setup
binary portion from the Memtest 1.70 binary.
The Instructions:
The first thing we must do is prepare the memsetup.rom binary we are going to use in our BIOS. Into a
temp directory, copy the BIOS to be operated on, the Memtest 1.70 binary, and latest Cbrom. Here is a
hex editor screenshot of the beginning of the Memtest 1.70 Binary. There are hex bytes at the beginning
of the Binary that initializes the program, and then the 55AAh signature. We must get rid of the hex bits
before and after the highlighted bytes in order to be able to use it in a BIOS. The easiest way to do this
is copy the highlighted bytes into a new binary file. This is a easy task with the Hex Editor. Save this file
as: memsetup.rom
The next thing to do is using Cbrom, check to see where the memsetup binary is located. At the command prompt, we
execute Cbrom yourbios.bin /D. In this BIOS memsetup.rom is resident as "OEM3" In your BIOS, Memsetup may be
named something different:
In my screenshot, I'm using Cbrom 1.55 which I renamed Cb155 for ease of typing. Substitute the name of the BIOS to
be operated on, for "yourbios.bin". Flash the BIOS and your done.
Remember you are using this information entirely at your own risk. The information presented may
not work for you. If you are not comfortable modifying BIOS's and flashing them, do not attempt to
modify them. You must be able to recover from a "bad" flash.
Using AMIBCP8 for Windows. American Megatrends BIOS Only!
AMIBCP8 for Windows allows changing at a minimum:
1) The POST screen message.
2) Hide/Unhide options.
3) Rename options.
4) Simulate the BIOS similar to BIOSView
Discuss this program in the Performing AMI BIOS Mods Discussion Thread
A newer version of AMIBCP 3.13(Windows) for Windows is available thanks to our member Dutchcheese!
The 1st window that opens, shows the major categories of the BIOS:
Clicking the "+", opens the subcategories. In here we can re-name options and change defaults of most options:
The "Register Edit" tab had no entires in it, so was of little use. The "PCI IRQ Routing" has entries, but still of little use:
The "BIOS Features" tab displays the version of the BIOS and this is where we can modify the "Sign On Message":
The "BIOS Strings" tab, allows us to edit the option name, if desired:
The "Simulation" option is rather interesting:
This "Simulation" mode looks exactly like the real BIOS mode:
Remember you are using these programs entirely at your own risk. The information
presented may not work for you. If you are not comfortable modifing BIOS's and
flashing them, do not attempt to modify them.
Using MMTool(AMI BIOS)
MMTool is another Windows based program that displays a wealth of information about an
AMI BIOS.
The link is here: MMTool(AMI)
The programs opens up with a basic window that requires the user to know the name
of the BIOS module to be added/deleted.
Going to "Power MMTool" opens a more advanced window that shows the capabilities of the
program.
Loading a AMI BIOS displays the modules contained in the BIOS. They can then be
extracted, deleted or replaced using MMTool.
Note that only .rom extensions can be opened. Simply change the extension to .rom
Once a BIOS Module has been extracted, it can be manipulated using a Hex Editor or IDA
Disassembler 4.3.
Note that a file name has to be entered for the module before it can be extracted. Note that
you want to extract the module in uncompressed form.
Also note that the PCI Option ROM's display the much needed "Device ID" and "Vendor ID".
The above screen shot has Windows Explorer opened under MMTool.
Thanks to our new member Freelancer, we have a list of the Module ID's for AMI BIOS'S:
Here's bottom part of the chart:
Remember you are using these programs entirely at your own risk.
The information presented may not work for you. If you are not
comfortable modifing BIOS's and flashing them, do not attempt to
modify them.
Using The AMIBIOS BIOS Module Manipulation Utility
Work that member "Twobombs" is doing on a AMI BIOS has brought to light a program called
"AMIBIOS BIOS Module Manipulation Utility". It is a AMI developed program that certainly will aid in
modifing AMI BIOS. I'm just starting to look at this program and will try to document it's usage.
Discussion on this program is taking place in the Performing AMI BIOS Mods Discussion Thread
Executing "amimmwin" in the command prompt, displays the lengthy usage and switch information:
The program is here The download includes MMTool 3.12:
AMIBIOS BIOS Module Manipulation Utility
I will add to this topic as time permits, but not having a AMI powered board will limit my research.
The first and most interesting use right now, is replacing the "1B" module with a modded "1B"
module. The "1B" module is called the "System BIOS" module in the world of AWARD BIOS. It is
typically difficult to replace, but it appears that this program does it with just a simple command.
The following is from member "Twobombs" thread on modifing a AMI BIOS, with a little more
explanation.
First extract the "1B" module with MMTOOL 3.12. I'm sure some older versions will also work, but
3.12 is included in the download.
Mod the "1B" module the way you would like. (This is a complex subject by itself, see Updated Guide
to Award BIOS Reverse Engineering.) Then replace the "1B" module with AMIMMWIN.exe by typing
in the following, at the command prompt. "BIOS.ROM" is your BIOS of interest. "1B.rom" is the "1B"
module that has been modified.
Enter: AMIMMWIN BIOS.ROM /R 1B 1B.rom
The result will be a BIOS that can be flashed in. Even with the exact same code compression might
be a little different then the original and size of the compressed source can be different then the
original:
Remember you are using this information entirely at your own risk. The information
presented may not work for you. If you are not comfortable modifying BIOS's and
flashing them, do not attempt to modify them. You must be able to recover from a
"bad" flash.
A AMI PCI Substitute Option ROM on the ASRock 939Dual SATAII 2.20 BIOS
In the BIOS are 2 PCI ROM's already. One probably is the LAN Boot Agent or maybe the LAN itself.
I'll remove that one, as the Network Boot is Disabled by default, and put in a substitute. Here's the modules in that BIOS:
Here's the PCI Option ROM code I used to set Tref to 15.6usec@200:
code:
;---------------------------------------------------------------------------------
;---------------------------PCI ROM Header----------------------------------------
;---------------------------------------------------------------------------------
VENDOR_ID equ 10B9h ; PCI Vendor ID (must match your ethernet vendor id)
; exp: 10B9 = ALI or Intel
DEVICE_ID equ 5263h ; PCI Device ID (must match your ethernet devicie id)
; exp: 5263h = ALI 5263
ROMStart:
db 0x055, 0x0AA ; ROM Header 55,AA -> Bootable rom
db (ROMEnd - ROMStart)/512 ; ROM Size in 512byte
jmp MAIN
MAIN:
pushfd
push eax
push ebx
push bx
push dx
push si
push ds
push bp
pop bp
pop ds
pop si
pop dx
pop bx
pop ebx
pop eax
popfd
retf ; return far to system bios routine
times (ROM_SIZE_IN_BYTE-$) db 0 ; use 00h as the padding bytes until we reach the ROM size
; The last byte (512th) will be the patch_byte for the checksum
; patch_byte is calculated and automagically inserted below
PREV_CHKSUM = 0
repeat $
load CHKSUM byte from %-1
CHKSUM = (PREV_CHKSUM + CHKSUM) mod 0x100
PREV_CHKSUM = CHKSUM
end repeat
store byte (0x100 - CHKSUM) at ($-1) ; store the patch_byte
ROMEnd:
Well, the BIOS flashed and booted fine...
Only problem is I really can't decide if it's working or not... The Dual SATAII BIOS comes up with a different Tref when I change settings, but
15.6Usec@200 is one I never see, so it must not be working...
http://www.lejabeach.com/ASRock/939dual/939DM2220RH.zip
While I have tested the Mod BIOS, you are flashing entirely at your own risk!
Hacking the uATX VGA BIOS ROM
Discussion of this topic is taking place in the Hacking the uATX VGA BIOS ROM Module
Discussion Thread.
Introduction:
The VGA module for both AWARD and AMI, both follow the basic PCI format which is
described in this topic. It is not necessary to change the Vendor or Device ID as they are
already correct for your system.
One of our newer members had modded the BIOS for the Biostar 6100-939, which has
on-board Video... He generated several different versions for different GPU 3D
Overclocks.... And they worked great and it was a fine job.... It turns out that there are 3
different speeds, I guess depending on what is being displayed, for each VGA BIOS.
There is 2D, 3D, and Performance 3D modes... On the next 3 pages are the screen shots
for some of his early mods, increasing Performance 3D mode:
I have 2 different VGA modules extracted from their BIOS and I'm comparing them. The top
screen is the 575Mhz module version and the bottom is the 525Mhz module version. Highlighted
in red is one of the only 2 differences between the files. Remembering that the least significant
bit is displayed first(due to "little-endian" notation), a check of the decimal equivalent of 023Fh,
will revel that it equals 575. And 020Dh equals 525. Pretty neat, right?
Being the files were changed, the checksum had to also be corrected. That is done in the last hex 2 bits of the file. The
VGA ROM follows the ISA format where 55AAh are the 1st 2 hex bits, the 3ed bit is the number of 512 bit blocks, and
finally the checksum must be 00h. The BIOS will not boot if the VGA module checksum is not corrected. This is the only
other difference between the 2 VGA Mod files:
The "NiBiTor":
I just started playing with the "NiBiTor" program, which appears to work on nVidia VGA
BIOS modules when they are extracted from the BIOS of a uAtx motherboard. The
program is here: NiBiTor.v3.4a.zip And here is the NiBiTor Home Page
This is a powerful editor, and because of this, danger and dead boards are a reality that
lurks around every modification.... Keep in mind that this Editor was written for Video
Card BIOS and not motherboard VGA BIOS modules, so many things should not be used.
This thread will only address using the program on a BIOS VGA module. Here's what you
see when you run the program:
Under "File", we can open a file, save(save as) a file,
save without fixing the checksum(!) or just exit. Never save
without fixing the checksum or your system probably will not boot.
Under "Tools", we have "hex view" and some other things that
I will get back to. The label "hex view" does not do this
option justice! It is a full screen hex editor that allows manual
modification, or displays the change real-time, that we have made
in the left screen.
Here I have loaded a Biostar 6100-AM2 VGA ROM module that I had
modified by hand for 500Mhz GPU speed. Note that the vendor is
unknown because the VGA module has a slightly different format
then a Video Card BIOS:
I have the VGA ROM loaded and the "Hex View" option opened:
I changed the Vendor to nVidia and used Hex Workshop to see what changed. The vendor code required by all PCI type ROMs was updated. The
only problem is it's not in the correct place and this option should not be used:
Here we can find 10DEh Vendor code that was added in the wrong place:
Here I edited the Vendor Code to AAAAh just to see if I could:
Here I have selected the Voltage tab and a warning pop's up with a well founded warning:
Clicking the Question Mark, opened a little help window:
Jumping to the Boot Settings, we have the ability to edit the VGA BIOS Sign-on message:
Selecting the Advanced Sign-on tab, once again opens a warning message:
Here we have opened the Hex View window to see the Advanced Sign-on message location:
While I have not tested each and every editing feature of the nifty little program, it appears that with respect to a BIOS VGA module, the Sign-on
message and the displayed GPU speed are the only things that can be changed without problems......
There is options to make the Sign-on message larger size and select colors for it. The larger text is quite big and the color does not work on all
VGA BIOS modules. There is a timing select to display the Sign-on verbiage longer, but then who wants that. Shorter also works.
I will update this thread if other options are working on the BIOS VGA module, but be aware that different VGA BIOS modules react differently
with this program....
Remember you are using this information entirely at your own risk. The information presented may not work for you. If
you are not comfortable modifying BIOS's and flashing them, do not attempt to modify them. You must be able to
recover from a "bad" flash.
Intel Conroe DDR2 ROM Patcher: 965P Chipset
This thread will hopefully lead to the generation of a DDR2 ROM Patcher for the Intel Conroe
Motherboards utilizing the 965P chipset. Both 965 and 975 systems will be analyzed, as do not have the
same memory timing registers and functions, we will start with the 965.
To start with, I already see that the Configuration Address and Configuration Data registers have the
exact same addressing scheme as the AMD A64 and AM2 systems. Here is the AM2 pages from the BIOS
and Kernel Developers Guide, which has a better representation of the information then the Intel
datasheets:
--------------------
A question to "FELIX", the author of Memset and Mchbaredit about the "Configuration Address",
FED14XXX, shown in Mchbaredit...
His reply:
quote:
Yes it's the memory configuration registers or MCHBAR (Memory Controler Hub Base Address
Register) You can find the address in B:00 D:00 F:00 at offset 48h for 965 chipset and 44h
for 975 chipset.
Some more conversations with "FELIX":
quote:
For access mchbar, first you need to unlocked it (see page 74 of 965
datasheet) so you need to write 1 at B:00 D:00 F:00 offset 48h(32bits value)
bit 0.
quote:
...if you want to use only 2 hex bit addresses, you must to enter the address
0xFED14200, and use offset 50h;it's the only way...
More to follow as we close in on the problem.... Also note that the 975 chipset is
different, but may be easier to write patches for...
--------------------
I believe the "MCH Base Address" is 0xFED14000 but I can't figure out how to address
the registers 250h thru 25Ah that are offset from the Base Address. Here is a screenie of
the 48h register showing the 01h in the LSB, that Enables the MCHBAR:
Picture Download
And the MCHBAR register 48h datasheet:
The address for the memory registers is not 0xFED14250, 0xFED14251, etc, because that doesn't fit the
configuration shown below, plus it didn't work in the code posted earlier... There-in lies the problem....
Intel Conroe DDR2 ROM Patcher
--------------------
Thanks to a Internet Assembly Language friend, we're closing in on the problem that is really just me
understanding the Intel system. AMD was a snap compared to the Intel..
Ed has forwarded source code to me that I have complied and will test tomorrow.... Thanks Ed!
--------------------
I guess I'm not sure 0xFED14000 is the correct MCH Base Address....
This datasheet below, shows the Base Address is bits 35:14, so how can 0xFED14000 be the Base
Address???
Here's something I hoped would work, but it did not.....
I pulled out bits 35:14 from register 48h, added enough 0h on the upper end to be able to represent the
address as 8 Hex bits. I then added 250h to it. That turns the MCHBAR address into 0003FD95h. The
code looks like:
code:
ROMStart:
db 0x055, 0x0AA ; ROM Header 55,AA -> Bootable rom
db (ROMEnd - ROMStart)/512 ; ROM Size in 512byte
jmp MAIN ;<------------ jump to main (Bug Fixed)
db 0 ; checksum, to be filled in later
times (256)-($-$$) db 0
MAIN:
pushfd ; Push Flags Register onto the Stack (use 32)
push eax
push ebx
push dx
pop dx
pop ebx
pop eax
popfd ; Pop Stack into Eflags Register
retf ; Return Far from Procedure
; The last byte (512th) will be the patch_byte for the checksum
; patch_byte is calculated and automagically inserted below
PREV_CHKSUM = 0
repeat $
load CHKSUM byte from %-1
CHKSUM = (PREV_CHKSUM + CHKSUM) mod 0x100
PREV_CHKSUM = CHKSUM
end repeat
store byte (0x100 - CHKSUM) at ($-1) ; store the patch_byte
ROMEnd:
Well, I'm at a loss as to why I can't get this to work. 7 months and we're no closer to success then at the
start. I'm missing something simple
While I can enable and disable the Mchbar base address register, 00000048h, with a ISA Option Rom,
writing to the memory mapped registers is not working.....
I think you might have forgotten to initialize the segment register to the right value and moreover the
code is 16-bit code which implies that the maximum address you can reach is 1MB minus 1.
So, to address the entire 32-bit (4GB) address space (which is needed to reach the MCH BAR), you have
to switch the processor to "voodoo mode"/"flat real mode".If you don't do that, you won't get pass
through the 1MB "barrier". Yeah, reminding of the old DOS days . Compatibility for more than 2
decades bites us now
Anyway, if you are using esi as the "pointer" register, it would point to address ds:esi. Therefore,
remember to initialize (don't forget to save ds register contents first) ds register to the correct value. The
easiest way would be to initialize ds contents to 0.
Below is a code example (taken from my Award BIOS Reverse Engineering guide):
code:
The processor mode switching code would get complex so prepare to read your Intel Software Developer
Manual (Especially Volume 3). My advice is to test your mode switching code in DOS before trying to do it
in expansion ROM. That way you will save time and will be sure the code successfully switches the
processor to 32-bit "Voodoo mode" and goes back to 16-bit afterwards before returning to the main BIOS
code.
Switching the processor operating mode is one of the hardest task in assembly because everything can
get wrong and the processor gets into the so-called triple-fault which will reset the machine instantly.
Lot's of hobbyist OS developer caught by it. I was once one of them too . I think I have the the
"voodoo mode" switching code somewhere. But, I forgot where it is. I'll post it here when I got it.
Maybe a better approach would be "borrowing" the mode-switching code from the reverse-engineered
i975X motherboard BIOS. But , be careful, read the code closely and be aware of the assumption that the
code made regarding the segment registers, all of them.
Anyway, you are absolutely not missing something simple in this BIOS modification journey. It's
something complex. I assure you
Cheers,
Pinczakko
Hmmm... OK, thanks!
A few months ago, I had someone helping me with this by e-mail. This is where we ended up just as he
lost interest in the project. It did not set Tras as it should have, but it sounds like something that your
talking about:
code:
ROMStart:
db 0x055, 0x0AA ; ROM Header 55,AA -> Bootable rom
db (ROMEnd - ROMStart)/512 ; ROM Size in 512byte
jmp MAIN ;<------------ jump to main (Bug Fixed)
db 0 ; checksum, to be filled in later
times (256)-($-$$) db 0
MAIN:
pushfd ; Push Flags Register onto the Stack (use 32)
push eax
push ebx
push edx
call flatmode ; first, set up FS to access all 4G
pop edx
pop ebx
pop eax
popfd ; Pop Stack into Eflags Register
retf ; Return Far from Procedure
;----------------------------------------------------------------------
flatmode:
; first, calculate the linear address of GDT
xor edx,edx ; clear edx
xor eax,eax ; clear edx
mov dx,ds ; get the data segment
shl edx,4 ; shift it over a bit
add [cs:dword GDT+2],edx ; store as GDT linear base addr
; now load the GDT into the GDTR
lgdt fword ptr cs:GDT ; load GDT base (286-style 24-bit load)
mov bx,8 ;1 * size DESC386 ; point to first descriptor
mov eax,cr0 ; prepare to enter protected mode
or al,1 ; flip the PE bit
cli ; turn off interrupts
mov cr0,eax ; we're now in protected mode
mov fs,bx ; load the FS segment register
mov ds,bx
mov es,bx
mov gs,bx
and al,0FEh ; clear the PE bit again
mov cr0,eax ; back to real mode
sti ; resume handling interrupts
ret ;
;----------------------------------------------------------------------
GDT:
dw 000fh ; limit low
dw GDT ; base lo
db 0 ; base mid
db 0 ; dpltype
db 0 ; lim hi
db 0 ; base hi
times (ROM_SIZE_IN_BYTE-$) db 0 ; use 00h as the padding bytes until we reach the ROM
size
; The last byte (512th) will be the patch_byte for the checksum
; patch_byte is calculated and automagically inserted below
PREV_CHKSUM = 0
repeat $
load CHKSUM byte from %-1
CHKSUM = (PREV_CHKSUM + CHKSUM) mod 0x100
PREV_CHKSUM = CHKSUM
end repeat
store byte (0x100 - CHKSUM) at ($-1) ; store the patch_byte
ROMEnd:
I see.
Anyway, when you try the expansion ROM code above, does the machine can boot into Windows (or
whatever OS you are using)?
It's been quite a while I'm not using Fasm. I'll have a look at Fasm community and user manual to find
out how to that because last time I play around with "flat real mode" a.k.a "voodoo mode" , I was using
GNU AS assembler (for 16-bit code) and GNU C (for the 32-bit code).
Well, I'll try helping out with this as I can (I'm so busy atm)
Cheers,
Pinczakko
Thanks, my friend! Any help is much appreciated
In all fairness to the fellow that was helping me, he wrote the Flatmode and the Read-Modify-Write code,
I put it in the ISA and PCI format to try....
--------------------
hmm... first time looking at the code above makes me think everything is right. But, how come it's not
working .
After thinking for a while I finally realized that the code is not working as expected maybe because the so-
called Gate A20 is not enabled prior to the switch to protected mode. That will cause a bit of trouble
accessing the entire address space. Well, I hope in the next few weeks we'll have time to experiment with
refined code.
Here's my latest attempt(that does not work) to set Tras to 18T on a Biostar TF965PT. The problem seem
to be addressing 4Gig address space. No one seems to be interested enough in this to help and I'm sure
I'm close. I just don't know enough about switching modes to figure it out. Yet !:
code:
ROMStart:
db 0x055, 0x0AA ; ROM Header 55,AA -> Bootable rom
db (ROMEnd - ROMStart)/512 ; ROM Size in 512byte
jmp MAIN ;<------------ jump to main (Bug Fixed)
db 0 ; checksum, to be filled in later
times (256)-($-$$) db 0
MAIN:
pushfd ; Push Flags Register onto the Stack (use 32)
push eax
push ebx
push edx
push fs
push ds
push es
push gs
push si
push bp
call flatmode ; first, set up FS to access all 4G
pop bp
pop si
pop gs
pop es
pop ds
pop fs
pop edx
pop ebx
pop eax
popfd ; Pop Stack into Eflags Register
retf ; Return Far from Procedure
;----------------------------------------------------------------------
flatmode:
; first, calculate the linear address of GDT
xor edx,edx ; clear edx
xor eax,eax ; clear edx
mov dx,ds ; get the data segment
shl edx,4 ; shift it over a bit
add [cs:dword GDT+2],edx ; store as GDT linear base addr
; now load the GDT into the GDTR
lgdt fword ptr cs:GDT ; load GDT base (286-style 24-bit load)
mov bx,8 ;1 * size DESC386 ; point to first descriptor
mov eax,cr0 ; prepare to enter protected mode
or al,1 ; flip the PE bit
cli ; turn off interrupts
mov cr0,eax ; we're now in protected mode
mov fs,bx ; load the FS segment register
mov ds,bx
mov es,bx
mov gs,bx
and al,0FEh ; clear the PE bit again
mov cr0,eax ; back to real mode
sti ; resume handling interrupts
ret ;
;----------------------------------------------------------------------
GDT:
dw 000fh ; limit low
dw GDT ; base lo
db 0 ; base mid
db 0 ; dpltype
db 0 ; lim hi
db 0 ; base hi
times (ROM_SIZE_IN_BYTE-$) db 0 ; use 00h as the padding bytes until we reach the ROM
size
; The last byte (512th) will be the patch_byte for the checksum
; patch_byte is calculated and automagically inserted below
PREV_CHKSUM = 0
repeat $
load CHKSUM byte from %-1
CHKSUM = (PREV_CHKSUM + CHKSUM) mod 0x100
PREV_CHKSUM = CHKSUM
end repeat
store byte (0x100 - CHKSUM) at ($-1) ; store the patch_byte
ROMEnd:
--------------------
The ROM version with the code that looks at the MCH Base Address Register(48h) to see what the Base
Address is, re-boots the system at the 2nd POST screen. That version had this code after returning from
the "flatmode" routine:
code:
The code below sets the memory address to FED14250h, which FELIX clams is correct. I changed it from
the snippet above... I must be getting close to success as now the BIOS is hanging(or rebooting) the
system at the 2nd POST screen rather then doing absolutely nothing!
code:
ROMStart:
db 0x055, 0x0AA ; ROM Header 55,AA -> Bootable rom
db (ROMEnd - ROMStart)/512 ; ROM Size in 512byte
jmp MAIN ;<------------ jump to main (Bug Fixed)
db 0 ; checksum, to be filled in later
times (256)-($-$$) db 0
MAIN:
pushfd ; Push Flags Register onto the Stack (use 32)
push eax
push ebx
push edx
push fs
push ds
push es
push cs
push gs
push si
push bp
pop bp
pop si
pop gs
pop cs
pop es
pop ds
pop fs
pop edx
pop ebx
pop eax
popfd ; Pop Stack into Eflags Register
retf ; Return Far from Procedure
;----------------------------------------------------------------------
flatmode:
; first, calculate the linear address of GDT
xor edx,edx ; clear edx
xor eax,eax ; clear edx
mov dx,ds ; get the data segment
shl edx,4 ; shift it over a bit
add [cs:dword GDT+2],edx ; store as GDT linear base addr
; now load the GDT into the GDTR
lgdt fword ptr cs:GDT ; load GDT base (286-style 24-bit load)
mov bx,8 ;1 * size DESC386 ; point to first descriptor
mov eax,cr0 ; prepare to enter protected mode
or al,1 ; flip the PE bit
cli ; turn off interrupts
mov cr0,eax ; we're now in protected mode
mov fs,bx ; load the FS segment register
mov ds,bx
mov es,bx
mov gs,bx
and al,0FEh ; clear the PE bit again
mov cr0,eax ; back to real mode
sti ; resume handling interrupts
ret ;
;----------------------------------------------------------------------
GDT:
dw 000fh ; limit low
dw GDT ; base lo
db 0 ; base mid
db 0 ; dpltype
db 0 ; lim hi
db 0 ; base hi
times (ROM_SIZE_IN_BYTE-$) db 0 ; use 00h as the padding bytes until we reach the ROM
size
; The last byte (512th) will be the patch_byte for the checksum
; patch_byte is calculated and automagically inserted below
PREV_CHKSUM = 0
repeat $
load CHKSUM byte from %-1
CHKSUM = (PREV_CHKSUM + CHKSUM) mod 0x100
PREV_CHKSUM = CHKSUM
end repeat
store byte (0x100 - CHKSUM) at ($-1) ; store the patch_byte
ROMEnd:
I tried removing "DS" from the Push/Pop statements because when "Flatmode" is called,
one of the 1st things it does, is read data segment, DS. The system is still hanging at the
2nd POST screen
I downloaded MASM "flatmode code" from a online source, compiled it in MASM and
injected it into my binary. The system does not hang at the 2nd POST screen any more,
but it also does not set Tras to 18T as the Option ROM dictates.
For the MCH Base Address I did try 0FED14000h, but I don't really know if that's correct.
I'll go back and try reading register 48h and masking out the address that is present at
the time my ROM is executed.
Here's the MASM Flatmode code. MASM has some higher structure capabilities and it's
quite possible FASM just isn't up to the job:
code:
;----------------------------------------------------------------------
.model tiny
.code
.586P
DESC386 STRUC
limlo dw ?
baselo dw ?
basemid db ?
dpltype db ? ; p(1) dpl(2) s(1) type(4)
limhi db ? ; g(1) d/b(1) 0(1) avl(1) lim(4)
basehi db ?
DESC386 ENDS
;----------------------------------------------------------------------
; ORG 100h
start:
call flatmode ; go into flat real mode (fs reg only)
retf
;----------------------------------------------------------------------
flatmode proc
; first, calculate the linear address of GDT
xor edx,edx ; clear edx
xor eax,eax ; clear edx
mov dx,ds ; get the data segment
shl edx,4 ; shift it over a bit
add dword ptr [gdt+2],edx ; store as GDT linear base addr
A few minor changes and now the system is coming up dead at the 2nd POST screen with
no display. I must be in the right area....
The problem I'm having is that I'm not familiar enough with code to know what is correct
and what is wrong. Example: The Intel Handbook 3A, states that a far jump must be
performed after going into protected mode by setting the PE bit high, in the cr0 register.
This clears and sets all the segment registers. I can't do a far jump easily, so I manually
clears and set the segment registers. Is this OK? I have no idea. There are about 5-6 of
these kind of unknowns in the code, anyone of which could be keeping the code from
working.
But a thought occurred to me. Changing any memory timing triggers a Global Reset
normally. How or what is going to happen if my code happens to work(!)?
Edit: A couple of quick tests finds that the system does not do a Global Reset when
changing just Tras.
ROMStart:
db 0x055, 0x0AA ; ROM Header 55,AA -> Bootable rom
db (ROMEnd - ROMStart)/512 ; ROM Size in 512byte
jmp MAIN ;<------------ jump to main (Bug Fixed)
db 0 ; checksum, to be filled in later
times (256)-($-$$) db 0
MAIN:
pushfd ; Push Flags Register onto the Stack (use 32)
push eax
push ebx
push edx
call flatmode ; first, set up FS to access all 4G
pop edx
pop ebx
pop eax
popfd ; Pop Stack into Eflags Register
retf ; Return Far from Procedure
;----------------------------------------------------------------------
flatmode:
; first, calculate the linear address of GDT
xor edx,edx ; clear edx
xor eax,eax ; clear edx
mov dx,ds ; get the data segment
shl edx,4 ; shift it over a bit
cli ; turn off interrupts
add [cs:dword GDT+2],edx ; store as GDT linear base addr
; now load the GDT into the GDTR
lgdt fword ptr cs:GDT ; load GDT base (286-style 24-bit load)
mov bx,8 ;1 * size DESC386 ; point to first
descriptor
mov eax,cr0 ; prepare to enter protected mode
or al,1 ; flip the PE bit
mov cr0,eax ; we're now in protected mode
jmp next
next:
mov fs,bx ; load the FS segment register
mov ds,bx ;
mov es,bx ;
mov gs,bx ;
mov ss,bx ; load the SS segment register
and al,0FEh ; clear the PE bit again
mov cr0,eax ; back to real mode
sti ; resume handling interrupts
ret ;
;----------------------------------------------------------------------
GDT:
dw 000fh ; limit low
dw GDT ; base lo
db 0 ; base mid
db 0 ; dpltype
db 0 ; lim hi
db 0 ; base hi
; this is the setup for the 4G segment
dw 0ffffh ; limit low
dw 0 ; base lo
db 0 ; base mid
db 092h ; dpltype
db 0cfh ; lim hi
db 0 ; base hi
GDT_END:
times (ROM_SIZE_IN_BYTE-$) db 0 ; use 00h as the padding bytes until
we reach the ROM size
; The last byte (512th) will be the patch_byte for the checksum
; patch_byte is calculated and automagically inserted below
PREV_CHKSUM = 0
repeat $
load CHKSUM byte from %-1
CHKSUM = (PREV_CHKSUM + CHKSUM) mod 0x100
PREV_CHKSUM = CHKSUM
end repeat
store byte (0x100 - CHKSUM) at ($-1) ; store the patch_byte
ROMEnd:
Final Words.....