Sei sulla pagina 1di 294

Practical BIOS Editing

by Polygon
of
Rebels Haven Computer Forum

December 31, 2007


Table of Contents
1) Where do I Start?
● What do I Need to Mod a BIOS?-Award
● Here's What's Needed for AMI BIOS
2) "Hot Flashing"
3) Is My Mod BIOS Good to Flash?
4) Using Modbin6
● Moving Items With Modbin6
● Creating a New Item Group
● Modbin6 Actual Results
● [Press Enter]
● Modbin6 as a ROM Editor
● Modbin6 2.04.01
5) Using CBROMxxx
6) Making BIOS Items Selectable
● Adding a Little More Room for Labels
● Adding More Bytes!
7) "Little Endian" Notation
8) AMD Athlon 64 DDR ROM Patcher
9) AMD AM2 DDR2 ROM Patcher
10) Building Your Own Award ISA Option ROM
11) Building Your Own Award Substitute PCI Option ROM
12) Building Your Own Award PCI Opton ROM Using Code Injection
● Code Injection: Brief Method
13) The _item.bin Module and it's Interaction with _en_code.bin
● BIOS Without _Item.bin
● Item Help
● [Press Enter]
14) Editing System.Bin)Original.tmp)
15) Adding a New Item to an Award BIOS
● Another Use for Advanced Technique
● Adding a New Item to a BIOS with no _item.bin Module
16) Updating the Integrated Memtest Module
● Updating memsetup.rom Module
17) Using AMIBCP8 for Windows
18) Using MMTool for AMI BIOS
19) The AMIBIOS BIOS Module Manipulation Utility
20) A AMI PCI Substitute ROM
21) Hacking the uATX VGA BIOS ROM Module
● The "NiBiTor"
22) Intel Conroe DDR2 ROM Patcher
23) Final Words....
Where do I start? What do I need to Mod a BIOS?
Start by understanding what a BIOS is, and what is in a BIOS.

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.

Here's what's needed for AWARD BIOS:

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.

2) Anything serious is going to require a Hex Editor program. I use HexWorkshop4.2.


Later on, Flat Assembler(FASM) and IDA Pro 4.3 Disassembler will be needed for more
sophisticated modifications. All programs are linked in the BIOS Editing Tools Collection.

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....

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.
Hot Flashing a BIOS
You modded a BIOS, flashed it, and now the system is dead..... You've cleared the CMOS several times, let the
system sit for a while, but it's still a dead duck. "Hot Flashing" may be the only way to get the system back up
and running.....

"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:

c:\ awdflash xxxxx.bin /F

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.

Modbin6 allows you, at a minimum, to:


1) Unhide(or hide) BIOS Items.
2) Edit the POST Screen message.
3) Edit the names of BIOS Items and settings.
4) Move any Item or multiple Items.
5) Change the Defaults of any Item.
6) Create a new group and move a Item(s) to it.
Upon saving a modified BIOS, Modbin6 will take care of fixing the BIOS checksum if 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

The command set can be displayed using the /? switch.


The 1st example is how a BIOS file is normally opened.
The 2nd example of "-d" usage, is unknown at this time.
The 3ed example of using "-m" followed by a string, is a way to change the BIOS message. The string must be in
quotations if it is more then 1 word:
If more then 1 binary bios file is in the working directory, or you didn't specify a file name
at the command line, a prompt will come up asking you to select one:

The main window of Modbin6, shows 8 choices:


Selecting "File" and pressing "enter", brings up the Load/Save dialog box:

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":

Update: Notes About Moving Items Around With Modbin6


Having performed many Mods that involve moving Items around, I'm noticing several oddities with this process.
1) First, there seems to be no fool-proof sequence that does not corrupt the BIOS or at the very least, screw-up the BIOS
display. This can be seen in Modbin6. Items will be moved to odd-ball areas, all by themselves, or Modbin6 will not open
the BIOS anymore!
2) A sequence of "moves" that works on one BIOS, may not work on another BIOS. I'm even having trouble repeating a
series of 4-6 moves on the same BIOS!
3) Sometimes a whole branch and the sub-items can be moved all at once, and sometimes they can't. And it depends on
where your moving them to!
4) Usually a group of Items that can be disabled by another Item, will not tolerate any Item movement or any additional
Items being placed amongst them. Even under a heading that has both linked and un-linked, if a new Item is added to the
group of un-linked, there is no assurance that the BIOS won't corrupt.
5) In creating a new heading with "alt-C", once those Items are in place, there is no coming back, so be sure they are
where you want them to be.

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.

More as I investigate this new issue...


Using Modbin6: Creating a New Item Group
Another useful operation that can be performed with Modbin, is moving BIOS Items around to
produce a better layout of the BIOS. Grouping of common usage items, makes a easier BIOS to
use. Many BIOS Items control other BIOS Items' ability to be used by allowing them to be
selected or not. Moving a BIOS Item that is linked to another, usually corrupts the BIOS. Also,
moving a BIOS "Branch" may corrupt the BIOS. A "Branch" is a Item that has 1 or more Items
under it. To move all the Items under a Branch, we move them 1-at-a-time, adding and/or
subtracting Items until we achieve the desired layout.

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:

Update: Actual Results With Modbin6

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.

I'll update this as I continue to try different things.

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:

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:
[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.

Here's the way to do those tough BIOS Mods:

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.

CBROMxxx allows you to change:


1) Extract ROM Modules(Extract).
2) Delete ROM Modules(Release).
3) Insert ROM Modules(ROMFile).

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.

The command set can be displayed using the /? switch:


The ROMs contained in the BIOS can be displayed using the /D switch:

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:

Delete rom or "release":


cbrom32 xxxx.bin /group release

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.

Latest CBROMxxx Versions

The version of CBROM32 1.49, add's "/CALS" and "/NVMM" support.


The version of CBROM 1.55.1, and add's "/CALS", "/efi0-9", "/minit" and "/NVMM" support.
Latest CBROMxxx Versions
Thanks to member JP, we have what has to be the very latest CBROM!

Discuss the use of CBROM 1.82 in the CBROMxxx Discussion Thread.

Here's the link: CBROM 1.82

Executing CBROM182 /? shows the command set:

Every switch below is added:


One of the things this version does that I have never seen before is, extract a certain module to a temp file and then add it back
in. It only seems to do it once even though we use CBROM182 several times on a particular BIOS. The modules name that is re-
installed(?) is slightly different from BIOS to BIOS, but it seems to have to do with the "memory module" module.

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

I'm not sure if this will work on non-ASUS BIOS.


Making BIOS Options "Selectable" and "Naming" Options
In order to keep this technique clear and easy to review, the thread is closed and discussion is taking place in this thread...

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...

The Final Solution!


Note that I have switched to Hex Workshop as it's better suited for BIOS and Hex Editing, IMHO...

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:

Building a PCI Option ROM Discussion Thread


Download Source Code

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

dtl_add equ 08000C288h ; DRAM Timing Low address


dth_add equ 08000C28Ch ; DRAM Timing High address
dcl_add equ 08000C290h ; DRAM Configuration Low address
dch_add equ 08000C294h ; DRAM Configuration High address
ddr_add equ 08000C298h ; DRAM Delay Line Register address

ROM_SIZE_IN_BLOCK = 1 ; 1 means ROM size is 1 block (512 bytes)


ROM_SIZE_IN_BYTE = ROM_SIZE_IN_BLOCK * 512

;---------------------------------------------------------------------
; 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

; Row Cycle Time(dtl)


trc equ dtl_add
trc_data equ 0FFFFFF0Fh ; Row Cycle Time (4bit)
trc_7 equ 000000000h ; 7 clock
trc_8 equ 000000010h ; 8 clock
trc_9 equ 000000020h ; 9 clock
trc_10 equ 000000030h ; 10clock
trc_11 equ 000000040h ; 11clock
trc_12 equ 000000050h ; 12clock
trc_13 equ 000000060h ; 13clock
trc_14 equ 000000070h ; 14clock
trc_15 equ 000000080h ; 15clock
trc_16 equ 000000090h ; 16clock
trc_17 equ 0000000A0h ; 17clock
trc_18 equ 0000000B0h ; 18clock
trc_19 equ 0000000C0h ; 19clock
trc_20 equ 0000000D0h ; 20clock
trc_21 equ 0000000E0h ; 21clock
trc_22 equ 0000000F0h ; 22clock

; Row Refresh Cycle Time(dtl)


trfc equ dtl_add
trfc_data equ 0FFFFF0FFh ; Row Refresh Cycle Time (4bit)
trfc_9 equ 000000000h ; 9 clock
trfc_10 equ 000000100h ; 10clock
trfc_11 equ 000000200h ; 11clock
trfc_12 equ 000000300h ; 12clock
trfc_13 equ 000000400h ; 13clock
trfc_14 equ 000000500h ; 14clock
trfc_15 equ 000000600h ; 15clock
trfc_16 equ 000000700h ; 16clock
trfc_17 equ 000000800h ; 17clock
trfc_18 equ 000000900h ; 18clock
trfc_19 equ 000000A00h ; 19clock
trfc_20 equ 000000B00h ; 20clock
trfc_21 equ 000000C00h ; 21clock
trfc_22 equ 000000D00h ; 22clock
trfc_23 equ 000000E00h ; 23clock
trfc_24 equ 000000F00h ; 24clock

; RAS to CAS Delay(dtl)


trcd equ dtl_add
trcd_data equ 0FFFF8FFFh ; RAS to CAS Delay (3bit)
trcd_2 equ 000002000h ; 2 clock
trcd_3 equ 000003000h ; 3 clock
trcd_4 equ 000004000h ; 4 clock
trcd_5 equ 000005000h ; 5 clock
trcd_6 equ 000006000h ; 6 clock

; RAS to RAS Delay(dtl)


trrd equ dtl_add
trrd_data equ 0FFF8FFFFh ; RAS to RAS Delay (3bit)
trrd_2 equ 000020000h ; 2 clock
trrd_3 equ 000030000h ; 3 clock
trrd_4 equ 000040000h ; 4 clock

; Min. RAS active time(dtl)


tras equ dtl_add
tras_data equ 0FF0FFFFFh ; Min. RAS active time (4bit)
tras_5 equ 000500000h ; 5 clock
tras_6 equ 000600000h ; 6 clock
tras_7 equ 000700000h ; 7 clock
tras_8 equ 000800000h ; 8 clock
tras_9 equ 000900000h ; 9 clock
tras_10 equ 000A00000h ; 10clock
tras_11 equ 000B00000h ; 11clock
tras_12 equ 000C00000h ; 12clock
tras_13 equ 000D00000h ; 13clock
tras_14 equ 000E00000h ; 14clock
tras_15 equ 000F00000h ; 15clock

; Row Precharge Time(dtl)


trp equ dtl_add
trp_data equ 0F8FFFFFFh ; Row Precharge Time (3bit)
trp_2 equ 002000000h ; 2 clock
trp_3 equ 003000000h ; 3 clock
trp_4 equ 004000000h ; 4 clock
trp_5 equ 005000000h ; 5 clock
trp_6 equ 006000000h ; 6 clock

; Write Recovery Time(dtl)


twr equ dtl_add
twr_data equ 0EFFFFFFFh ; Write Recovery Time (1bit)
twr_2 equ 000000000h ; 2 clock
twr_3 equ 010000000h ; 3 clock

;---------------------------------------------------------------------
; 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

; Read to write delay(dth)


trwt equ dth_add
trwt_data equ 0FFFFFF8Fh ; Read to write delay (3bit)
trwt_1 equ 000000000h ; 1 clock
trwt_2 equ 000000010h ; 2 clock
trwt_3 equ 000000020h ; 3 clock
trwt_4 equ 000000030h ; 4 clock
trwt_5 equ 000000040h ; 5 clock
trwt_6 equ 000000050h ; 6 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

; Write CAS latency(dth)


twcl equ dth_add
twcl_data equ 0FF8FFFFFh ; Write CAS latency (3bit)
twcl_1 equ 000000000h ; 1 clock
twcl_2 equ 000100000h ; 2 clock

;---------------------------------------------------------------------
; 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

; Dimm Drive Strength(dcl)


dds equ dcl_add
dds_data equ 0FFFFFFFDh ; Dimm Drive Strength (1bit)
dds_normal equ 000000000h ; Normal(Default)
dds_weak equ 000000002h ; Weak (Beware)

; Read/Write Qued Bypass(dcl)


rwqbp equ dcl_add
rwqbp_data equ 0FFFF3FFFh ; Read/Write Qued Bypass (2bit)
rwqbp_2x equ 000000000h ; 2x
rwqbp_4x equ 000004000h ; 4x
rwqbp_8x equ 000008000h ; 8x
rwqbp_16x equ 00000C000h ; 16x

; 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

; Idle Cycle Limit(dch)


icl equ dch_add
icl_data equ 0FFF8FFFFh ; Idle Cycle Limit (3bit)
icl_0 equ 000000000h ; 0 clock
icl_4 equ 000010000h ; 4 clock
icl_8 equ 000020000h ; 8 clock
icl_16 equ 000030000h ; 16clock
icl_32 equ 000040000h ; 32clock
icl_64 equ 000050000h ; 64clock
icl_128 equ 000060000h ; 128clock
icl_256 equ 000070000h ; 256clock

; Dynamic idle cycle counter enable(dch)


dicc equ dch_add
dicc_data equ 0FFF7FFFFh ; Dynamic idle cycle limit (1bit)
dicc_disable equ 000000000h ; disabled
dicc_enable equ 000080000h ; enabled

; Memory Clock Frequency(dch)


mcf equ dch_add
mcf_data equ 0FF8FFFFFh ; Memory Clock Frequency (3bit)
mcf_100 equ 000000000h ; 100MHz
mcf_133 equ 000200000h ; 133MHz
mcf_166 equ 000500000h ; 166MHz
mcf_200 equ 000700000h ; 200MHz (1:1)

;---------------------------------------------------------------------
; 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

; DQS Slew Control(ddr)


dqsc equ ddr_add
dqsc_data equ 0FCFFFFFFh ; Adjust DQS (1bit) & (1bit)
dqsc_slow equ 001000000h ; Slower DQS
dqsc_fast equ 002000000h ; Faster DQS

;---------------------------------------------------------------------------------------------------
;---------------------------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
}

macro RETURN ; Restore register contents


{
pop bp
pop ds
pop si
pop dx
pop bx
pop ebx
pop eax
popfd
retf ; return far to system bios routine
}

;---------------------------------------------------------------------------------------------------
;---------------------------------------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
;
;----------------------------------------------------------------------------------------------------

All available Memory Clock settings:

code:

; Memory Clock Frequency(dch)


mcf equ dch_add
mcf_data equ 0FF8FFFFFh ; Memory Clock Frequency (3bit)
mcf_100 equ 000000000h ; 100MHz
mcf_120 equ 000100000h ; 120MHz
mcf_133 equ 000200000h ; 133MHz
mcf_140 equ 000300000h ; 140MHz
mcf_150 equ 000400000h ; 150MHz
mcf_166 equ 000500000h ; 166MHz
mcf_180 equ 000600000h ; 180MHz
mcf_200 equ 000700000h ; 200MHz (1:1)

EDIT: Note that the 120Mhz divider may not work on all systems and hang at POST.

Sometimes it is ok to inject it on ethernet PCI ROM but ethernet wont be useable...


Just change the ROM header with PCI
Device & Vendor ID must match available ethernet device

PCI ROM Header


example : nForce2 NIC

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

VENDOR_ID equ 10DEh ; PCI Vendor ID (must match yout


ethernet vendor id)
; exp: 10DE = nVidia
DEVICE_ID equ 01E0h ; PCI Device ID (must match yout
ethernet devicie id)
; exp: 01E0h = nforce2 NIC

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


TIMES 18h-($-$$) DB 0 ; padding zeros to offset 18h
DW PCIHDR ; pointer to PCI Header
DW PNPHDR ; pointer to PnP Expansion Header

PCIHDR: DB 'PCIR' ; PCI data structure signature


DW VENDOR_ID ; vendor ID (must match real PCI
device)
DW DEVICE_ID ; device ID (must match real PCI
device)
DW 0 ; pointer to vital product data (0=none)
DW 24 ; PCI data structure length [B]
DB 0 ; PCI data structure revision (0=PCI 2.1)
DB 2,0,0 ; PCI device class code (2=network ctrlr,
0=eth.)
DW ROM_SIZE_IN_BLOCK ; ROM size in 512B blocks
DW 0 ; revision level of code
DB 0 ; code type (0=x86 compitable)
DB 80h ; last image indicator
DW 0 ; reserved

PNPHDR: DB '$PnP' ; PnP data structure signature


DB 1 ; PnP structure revision
DB 2 ; PnP structure length (in 16B blocks)
DW 0 ; offset to next header (0-none)
DB 0 ; reserved
DB 33h ; PnP structure checksum
DD 0 ; device identifier
DW 0 ; pointer to manufacturer string
DW 0 ; pointer to productname string
DB 2,0,0 ; device class code (2=network ctrlr,
0=eth.)
DB 64h ; device indicators (64h - shadowable,cacheable,not
only for boot,IPL device)
DW 0 ; boot connection vector (0-none)
DW 0 ; disconnect vector (0-none)
DW 0 ; bootstrap entry vector (0-none)
DW 0 ; reserved
DW 0 ; static resource info vector (0-none)

;---------------------------------------------------------------------------------------------------
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

dtl_add equ 08000C288h ; DRAM Timing Low address


dth_add equ 08000C28Ch ; DRAM Timing High address
dcl_add equ 08000C290h ; DRAM Configuration Low address
dch_add equ 08000C294h ; DRAM Configuration High address
ddr_add equ 08000C298h ; DRAM Delay Line Register address

ROM_SIZE_IN_BLOCK = 1 ; 1 means ROM size is 1 block (512 bytes)


ROM_SIZE_IN_BYTE = ROM_SIZE_IN_BLOCK * 512

;---------------------------------------------------------------------
; 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

; Row Cycle Time(dtl)


trc equ dtl_add
trc_data equ 0FFFFFF0Fh ; Row Cycle Time (4bit)
trc_7 equ 000000000h ; 7 clock
trc_8 equ 000000010h ; 8 clock
trc_9 equ 000000020h ; 9 clock
trc_10 equ 000000030h ; 10clock
trc_11 equ 000000040h ; 11clock
trc_12 equ 000000050h ; 12clock
trc_13 equ 000000060h ; 13clock
trc_14 equ 000000070h ; 14clock
trc_15 equ 000000080h ; 15clock
trc_16 equ 000000090h ; 16clock
trc_17 equ 0000000A0h ; 17clock
trc_18 equ 0000000B0h ; 18clock
trc_19 equ 0000000C0h ; 19clock
trc_20 equ 0000000D0h ; 20clock
trc_21 equ 0000000E0h ; 21clock
trc_22 equ 0000000F0h ; 22clock

; Row Refresh Cycle Time(dtl)


trfc equ dtl_add
trfc_data equ 0FFFFF0FFh ; Row Refresh Cycle Time (4bit)
trfc_9 equ 000000000h ; 9 clock
trfc_10 equ 000000100h ; 10clock
trfc_11 equ 000000200h ; 11clock
trfc_12 equ 000000300h ; 12clock
trfc_13 equ 000000400h ; 13clock
trfc_14 equ 000000500h ; 14clock
trfc_15 equ 000000600h ; 15clock
trfc_16 equ 000000700h ; 16clock
trfc_17 equ 000000800h ; 17clock
trfc_18 equ 000000900h ; 18clock
trfc_19 equ 000000A00h ; 19clock
trfc_20 equ 000000B00h ; 20clock
trfc_21 equ 000000C00h ; 21clock
trfc_22 equ 000000D00h ; 22clock
trfc_23 equ 000000E00h ; 23clock
trfc_24 equ 000000F00h ; 24clock

; RAS to CAS Delay(dtl)


trcd equ dtl_add
trcd_data equ 0FFFF8FFFh ; RAS to CAS Delay (3bit)
trcd_2 equ 000002000h ; 2 clock
trcd_3 equ 000003000h ; 3 clock
trcd_4 equ 000004000h ; 4 clock
trcd_5 equ 000005000h ; 5 clock
trcd_6 equ 000006000h ; 6 clock

; RAS to RAS Delay(dtl)


trrd equ dtl_add
trrd_data equ 0FFF8FFFFh ; RAS to RAS Delay (3bit)
trrd_2 equ 000020000h ; 2 clock
trrd_3 equ 000030000h ; 3 clock
trrd_4 equ 000040000h ; 4 clock

; Min. RAS active time(dtl)


tras equ dtl_add
tras_data equ 0FF0FFFFFh ; Min. RAS active time (4bit)
tras_5 equ 000500000h ; 5 clock
tras_6 equ 000600000h ; 6 clock
tras_7 equ 000700000h ; 7 clock
tras_8 equ 000800000h ; 8 clock
tras_9 equ 000900000h ; 9 clock
tras_10 equ 000A00000h ; 10clock
tras_11 equ 000B00000h ; 11clock
tras_12 equ 000C00000h ; 12clock
tras_13 equ 000D00000h ; 13clock
tras_14 equ 000E00000h ; 14clock
tras_15 equ 000F00000h ; 15clock

; Row Precharge Time(dtl)


trp equ dtl_add
trp_data equ 0F8FFFFFFh ; Row Precharge Time (3bit)
trp_2 equ 002000000h ; 2 clock
trp_3 equ 003000000h ; 3 clock
trp_4 equ 004000000h ; 4 clock
trp_5 equ 005000000h ; 5 clock
trp_6 equ 006000000h ; 6 clock

; Write Recovery Time(dtl)


twr equ dtl_add
twr_data equ 0EFFFFFFFh ; Write Recovery Time (1bit)
twr_2 equ 000000000h ; 2 clock
twr_3 equ 010000000h ; 3 clock

;---------------------------------------------------------------------
; 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

; Read to write delay(dth)


trwt equ dth_add
trwt_data equ 0FFFFFF8Fh ; Read to write delay (3bit)
trwt_1 equ 000000000h ; 1 clock
trwt_2 equ 000000010h ; 2 clock
trwt_3 equ 000000020h ; 3 clock
trwt_4 equ 000000030h ; 4 clock
trwt_5 equ 000000040h ; 5 clock
trwt_6 equ 000000050h ; 6 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

; Write CAS latency(dth)


twcl equ dth_add
twcl_data equ 0FF8FFFFFh ; Write CAS latency (3bit)
twcl_1 equ 000000000h ; 1 clock
twcl_2 equ 000100000h ; 2 clock

;---------------------------------------------------------------------
; 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

; Dimm Drive Strength(dcl)


dds equ dcl_add
dds_data equ 0FFFFFFFDh ; Dimm Drive Strength (1bit)
dds_normal equ 000000000h ; Normal(Default)
dds_weak equ 000000002h ; Weak (Beware)

; Read/Write Qued Bypass(dcl)


rwqbp equ dcl_add
rwqbp_data equ 0FFFF3FFFh ; Read/Write Qued Bypass (2bit)
rwqbp_2x equ 000000000h ; 2x
rwqbp_4x equ 000004000h ; 4x
rwqbp_8x equ 000008000h ; 8x
rwqbp_16x equ 00000C000h ; 16x

; 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

; Idle Cycle Limit(dch)


icl equ dch_add
icl_data equ 0FFF8FFFFh ; Idle Cycle Limit (3bit)
icl_0 equ 000000000h ; 0 clock
icl_4 equ 000010000h ; 4 clock
icl_8 equ 000020000h ; 8 clock
icl_16 equ 000030000h ; 16clock
icl_32 equ 000040000h ; 32clock
icl_64 equ 000050000h ; 64clock
icl_128 equ 000060000h ; 128clock
icl_256 equ 000070000h ; 256clock

; Dynamic idle cycle counter enable(dch)


dicc equ dch_add
dicc_data equ 0FFF7FFFFh ; Dynamic idle cycle limit (1bit)
dicc_disable equ 000000000h ; disabled
dicc_enable equ 000080000h ; enabled

; Memory Clock Frequency(dch)


mcf equ dch_add
mcf_data equ 0FF8FFFFFh ; Memory Clock Frequency (3bit)
mcf_100 equ 000000000h ; 100MHz
mcf_120 equ 000100000h ; 120MHz
mcf_133 equ 000200000h ; 133MHz
mcf_140 equ 000300000h ; 140MHz
mcf_150 equ 000400000h ; 150MHz
mcf_166 equ 000500000h ; 166MHz
mcf_180 equ 000600000h ; 180MHz
mcf_200 equ 000700000h ; 200MHz (1:1)

;---------------------------------------------------------------------
; 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

; DQS Slew Control(ddr)


dqsc equ ddr_add
dqsc_data equ 0FCFFFFFFh ; Adjust DQS (1bit) & (1bit)
dqsc_slow equ 001000000h ; Slower DQS
dqsc_fast equ 002000000h ; Faster DQS

;---------------------------------------------------------------------------------------------------
;---------------------------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
}

macro RETURN ; Restore register contents


{
pop bp
pop ds
pop si
pop dx
pop bx
pop ebx
pop eax
popfd
retf ; return far to system bios routine
}

;---------------------------------------------------------------------------------------------------
;---------------------------------------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

Download Source Code.

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 register data is here starting at page 101:


BIOS and Kernal Developer's Guide for AMD NPT Family 0Fh Processors(pdf file)

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

dtl_add equ 08000C288h ; DRAM Timing Low address


dth_add equ 08000C28Ch ; DRAM Timing High address
dcl_add equ 08000C290h ; DRAM Configuration Low address
dch_add equ 08000C294h ; DRAM Configuration High address
dcm_add equ 08000C2A0h ; DRAM Controller Miscellaneous Data address

ROM_SIZE_IN_BLOCK = 1 ; 1 means ROM size is 1 block (512 bytes)


ROM_SIZE_IN_BYTE = ROM_SIZE_IN_BLOCK * 512

;---------------------------------------------------------------------
; 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

; RAS to CAS Delay(dtl)


trcd equ dtl_add
trcd_data equ 0FFFFFFCFh ; RAS to CAS Delay (2bit)
trcd_3 equ 000000000h ; 3 clock
trcd_4 equ 000000010h ; 4 clock
trcd_5 equ 000000020h ; 5 clock
trcd_6 equ 000000030h ; 6 clock

; Row Precharge Time(dtl)


trp equ dtl_add ;
trp_data equ 0FFFFFCFFh ; Row Precharge Time (2bit)
trp_3 equ 000000000h ; 3 clock
trp_4 equ 000000100h ; 4 clock
trp_5 equ 000000200h ; 5 clock
trp_6 equ 000000300h ; 6 clock

; Read Precharge Time(dtl)


trtp equ dtl_add ;
trtp_data equ 0FFFFF7FFh ; Read Precharge Time (1bit)
trtp_2 equ 000000000h ; 2/4 clock
trtp_3 equ 000000800h ; 3/5 clock

; Min. RAS active time(dtl)


tras equ dtl_add
tras_data equ 0FFFF0FFFh ; Min. RAS active time (4bit)
tras_5 equ 000002000h ; 5 clock
tras_6 equ 000003000h ; 6 clock
tras_7 equ 000004000h ; 7 clock
tras_8 equ 000005000h ; 8 clock
tras_9 equ 000006000h ; 9 clock
tras_10 equ 000007000h ; 10 clock
tras_11 equ 000008000h ; 11 clock
tras_12 equ 000009000h ; 12 clock
tras_13 equ 00000A000h ; 13 clock
tras_14 equ 00000B000h ; 14 clock
tras_15 equ 00000C000h ; 15 clock
tras_16 equ 00000D000h ; 16 clock
tras_17 equ 00000E000h ; 17 clock
tras_18 equ 00000F000h ; 18 clock

; Row Cycle Time(dtl)


trc equ dtl_add
trc_data equ 0FFF0FFFFh ; Row Cycle Time (4bit)
trc_11 equ 000000000h ; 11 clock
trc_12 equ 000010000h ; 12 clock
trc_13 equ 000020000h ; 13 clock
trc_14 equ 000030000h ; 14 clock
trc_15 equ 000040000h ; 15 clock
trc_16 equ 000050000h ; 16 clock
trc_17 equ 000060000h ; 17 clock
trc_18 equ 000070000h ; 18 clock
trc_19 equ 000080000h ; 19 clock
trc_20 equ 000090000h ; 20 clock
trc_21 equ 0000A0000h ; 21 clock
trc_22 equ 0000B0000h ; 22 clock
trc_23 equ 0000C0000h ; 23 clock
trc_24 equ 0000D0000h ; 24 clock
trc_25 equ 0000E0000h ; 25 clock
trc_26 equ 0000F0000h ; 26 clock

; Write Recovery Time(dtl)


twr equ dtl_add ;
twr_data equ 0FFCFFFFFh ; Write Recovery Time (2bit)
twr_3 equ 000000000h ; 3 clock
twr_4 equ 000100000h ; 4 clock
twr_5 equ 000200000h ; 5 clock
twr_6 equ 000300000h ; 6 clock

; RAS to RAS Delay Time(dtl)


trrd equ dtl_add ;
trrd_data equ 0FF3FFFFFh ; RAS to RAS Delay Time (2bit)
trrd_2 equ 000000000h ; 2 clock
trrd_3 equ 000400000h ; 3 clock
trrd_4 equ 000800000h ; 4 clock
trrd_5 equ 000C00000h ; 5 clock

;---------------------------------------------------------------------
; DRAM Timing High Address
;---------------------------------------------------------------------

; Write to read delay(dth)


twtr equ dth_add ;
twtr_data equ 0FFFFFCFFh ; Write to read delay (2bit)
twtr_1 equ 000000100h ; 1 clock
twtr_2 equ 000000200h ; 2 clock
twtr_3 equ 000000300h ; 3 clock

; 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
;---------------------------------------------------------------------

; Dimm Drive Strength(dcl)


dds equ dcl_add
dds_data equ 0FFFFFF7Fh ; Dimm Drive Strength (1bit)
dds_normal equ 000000000h ; NORMAL
dds_weak equ 000000080h ; WEAK

;---------------------------------------------------------------------
; 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

; Maximum Async Latency(dch)


async equ dch_add
async_data equ 0FFFFFF0Fh ; Maximum Async Latency (4bit)
async_0 equ 000000000h ; 0 ns
async_1 equ 000000010h ; 1 ns
async_2 equ 000000020h ; 2 ns
async_3 equ 000000030h ; 3 ns
async_4 equ 000000040h ; 4 ns
async_5 equ 000000050h ; 5 ns
async_6 equ 000000060h ; 6 ns
async_7 equ 000000070h ; 7 ns
async_8 equ 000000080h ; 8 ns
async_9 equ 000000090h ; 9 ns
async_10 equ 0000000A0h ; 10ns
async_11 equ 0000000B0h ; 11ns
async_12 equ 0000000C0h ; 12ns
async_13 equ 0000000D0h ; 13ns
async_14 equ 0000000E0h ; 14ns
async_15 equ 0000000F0h ; 15ns

; 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

; Four Act Window(dch)


faw equ dch_add
faw_data equ 00FFFFFFFh ; Four Act Window (4bit)
faw_0x equ 000000000h ; No Tfaw Window Restriction
faw_8x equ 010000000h ; 8x
faw_9x equ 020000000h ; 9x
faw_10x equ 030000000h ; 10x
faw_11x equ 040000000h ; 11x
faw_12x equ 050000000h ; 12x
faw_13x equ 060000000h ; 13x
faw_14x equ 070000000h ; 14x
faw_15x equ 080000000h ; 15x
faw_16x equ 090000000h ; 16x
faw_17x equ 0A0000000h ; 17x
faw_18x equ 0B0000000h ; 18x
faw_19x equ 0C0000000h ; 19x
faw_20x equ 0D0000000h ; 20x

;---------------------------------------------------------------------
; DRAM Controller Miscellaneous Data address
;---------------------------------------------------------------------

; R/W Queue Bypass Max(dcm)


rwqbp equ dch_add
rwqbp_data equ 0FFFFFFF3h ; R/W Queue Bypass Max (2bit)
rwqbp_0 equ 000000000h ; 2 memclk cycles
rwqbp_1 equ 000000004h ; 4 memclk cycles
rwqbp_2 equ 000000008h ; 8 memclk cycles
rwqbp_3 equ 00000000Ch ; 16 memclk cycles

; Dynamic Idle Cycle Enable(dcm)


dicl equ dcm_add
dicl_data equ 0FFFFFFDFh ; Dynamic Idle Cycle Enable (1bit)
dicl_0 equ 000000000h ; Disable
dicl_0 equ 000000020h ; Enable

; Idle Cycle Limit(dcm)


icl equ dcm_add
icl_data equ 0FFFFFE3Fh ; Idle Cycle Limit (3bit)
icl_0 equ 000000000h ; 0 clock
icl_4 equ 000000040h ; 4 clock
icl_8 equ 000000080h ; 8 clock
icl_16 equ 0000000C0h ; 16clock
icl_32 equ 000000100h ; 32clock
icl_64 equ 000000140h ; 64clock
icl_128 equ 000000180h ; 128clock
icl_256 equ 0000001C0h ; 256clock

;---------------------------------------------------------------------------------------------------
;---------------------------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
}

macro RETURN ; Restore register contents


{
pop bp
pop ds
pop si
pop dx
pop bx
pop ebx
pop eax
popfd
retf ; return far to system bios routine
}

;---------------------------------------------------------------------------------------------------
;---------------------------------------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:

; Row Precharge Time/Read Precharge Time Combined


combo1 equ dtl_add ;
combo1_data equ 0FFFFF0FFh ; Trp / Trtp (4bit)
combo1_1 equ 000000000h ; 3 clock / 2/4 clock
combo1_2 equ 000000100h ; 4 clock / 2/4 clock
combo1_3 equ 000000200h ; 5 clock / 2/4 clock
combo1_4 equ 000000300h ; 6 clock / 2/4 clock
combo1_5 equ 000000800h ; 3 clock / 3/5 clock
combo1_6 equ 000000900h ; 4 clock / 3/5 clock
combo1_7 equ 000000A00h ; 5 clock / 3/5 clock
combo1_8 equ 000000B00h ; 6 clock / 3/5 clock

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:

; Write Recovery Time/RAS to RAS Delay Combined


combo2 equ dtl_add ;
combo2_data equ 0FF0FFFFFh ; Twr / Trrd (4bit)
combo2_1 equ 000000000h ; 3 clock / 2 clock
combo2_2 equ 000100000h ; 4 clock / 2 clock
combo2_3 equ 000200000h ; 5 clock / 2 clock
combo2_4 equ 000300000h ; 6 clock / 2 clock
combo2_5 equ 000400000h ; 3 clock / 3 clock
combo2_6 equ 000500000h ; 4 clock / 3 clock
combo2_7 equ 000600000h ; 5 clock / 3 clock
combo2_8 equ 000700000h ; 6 clock / 3 clock
combo2_9 equ 000800000h ; 3 clock / 4 clock
combo2_10 equ 000900000h ; 4 clock / 4 clock
combo2_11 equ 000A00000h ; 5 clock / 4 clock
combo2_12 equ 000B00000h ; 6 clock / 4 clock
combo2_13 equ 000C00000h ; 3 clock / 5 clock
combo2_14 equ 000D00000h ; 4 clock / 5 clock
combo2_15 equ 000E00000h ; 5 clock / 5 clock
combo2_16 equ 000F00000h ; 6 clock / 5 clock

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....

The "combo" code again:

My brief code for this test. Note the Vendor and Device ID are for the ABIT NF-M2 nView only:

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

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

db 0 ; checksum, to be filled in later


TIMES 18h-($-$$) DB 0 ; padding zeros to offset 18h
DW PCIHDR ; pointer to PCI Header
DW PNPHDR ; pointer to PnP Expansion Header

PCIHDR: DB 'PCIR' ; PCI data structure signature


DW VENDOR_ID ; vendor ID (must match real PCI
device)
DW DEVICE_ID ; device ID (must match real PCI
device)
DW 0 ; pointer to vital product data (0=none)
DW 24 ; PCI data structure length [B]
DB 0 ; PCI data structure revision (0=PCI 2.1)
DB 2,0,0 ; PCI device class code (2=network
ctrlr,0=eth.)
DW ROM_SIZE_IN_BLOCK ; ROM size in 512B blocks
DW 0 ; revision level of code
DB 0 ; code type (0=x86 compitable)
DB 80h ; last image indicator
DW 0 ; reserved

PNPHDR: DB '$PnP' ; PnP data structure signature


DB 1 ; PnP structure revision
DB 2 ; PnP structure length (in 16B blocks)
DW 0 ; offset to next header (0-none)
DB 0 ; reserved
DB 33h ; PnP structure checksum
DD 0 ; device identifier
DW 0 ; pointer to manufacturer string
DW 0 ; pointer to productname string
DB 2,0,0 ; device class code (2=network ctrlr,0=eth.)
DB 64h ; device indicators (64h - shadowable,cacheable,not
; only for boot,IPL device)
DW 0 ; boot connection vector (0-none)
DW 0 ; disconnect vector (0-none)
DW 0 ; bootstrap entry vector (0-none)
DW 0 ; reserved
DW 0 ; static resource info vector (0-none)

MAIN:
pushfd
push eax
push ebx
push bx
push dx
push si
push ds
push bp

mov eax,08000C294h ; cDRAM Configuration High address


mov ebx,000000080h ; copy register data for Async Latency 8nsec
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,0FFFFFF0Fh ; set data byte to zero
or eax,ebx ; increase data by new setting
out dx,eax ; send data through port data

mov eax,08000C288h ; DRAM Timing Low address


mov ebx,000A00000h ; copy register data for Twr: 5T/Trrd: 4T
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,0FF0FFFFFh ; 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:

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----------------------------------------
;---------------------------------------------------------------------------------

ROM_SIZE_IN_BLOCK = 1 ; 1 means ROM size is 1 block (512 bytes)


ROM_SIZE_IN_BYTE = ROM_SIZE_IN_BLOCK * 512

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

db 0 ; checksum, to be filled in later


TIMES 18h-($-$$) DB 0 ; padding zeros to offset 18h
DW PCIHDR ; pointer to PCI Header
DW PNPHDR ; pointer to PnP Expansion Header

PCIHDR: DB 'PCIR' ; PCI data structure signature


DW VENDOR_ID ; vendor ID (must match real PCI
device)
DW DEVICE_ID ; device ID (must match real PCI
device)
DW 0 ; pointer to vital product data (0=none)
DW 24 ; PCI data structure length [B]
DB 0 ; PCI data structure revision (0=PCI 2.1)
DB 2,0,0 ; PCI device class code (2=network
ctrlr,0=eth.)
DW ROM_SIZE_IN_BLOCK ; ROM size in 512B blocks
DW 0 ; revision level of code
DB 0 ; code type (0=x86 compitable)
DB 80h ; last image indicator
DW 0 ; reserved

PNPHDR: DB '$PnP' ; PnP data structure signature


DB 1 ; PnP structure revision
DB 2 ; PnP structure length (in 16B blocks)
DW 0 ; offset to next header (0-none)
DB 0 ; reserved
DB 33h ; PnP structure checksum
DD 0 ; device identifier
DW 0 ; pointer to manufacturer string
DW 0 ; pointer to productname string
DB 2,0,0 ; device class code (2=network ctrlr,0=eth.)
DB 64h ; device indicators (64h - shadowable,cacheable,not
; only for boot,IPL device)
DW 0 ; boot connection vector (0-none)
DW 0 ; disconnect vector (0-none)
DW 0 ; bootstrap entry vector (0-none)
DW 0 ; reserved
DW 0 ; static resource info vector (0-none)

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

mov eax,08000C28Ch ; DRAM Timing High address


mov ebx,000002000h ; copy register data for twrwr: 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,0FFFFCFFFh ; set data byte to zero
or eax,ebx ; increase data by new setting
out dx,eax ; send data through port data

mov eax,08000C28Ch ; DRAM Timing High address


mov ebx,000004000h ; copy register data for trdrd: 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,0FFFF3FFFh ; set data byte to zero
or eax,ebx ; increase data by new setting
out dx,eax ; send data through port data

mov eax,08000C28Ch ; DRAM Timing High address


mov ebx,000020000h ; copy register data for Tref: 7.8usec
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,0FFFCFFFFh ; set data byte to zero
or eax,ebx ; increase data by new setting
out dx,eax ; send data through port data

;-------------------------------------------------------------------------------------

mov eax,08000C294h ; DRAM Configuration High address


mov ebx,000000090h ; copy register data for Async Latency 9nsec
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,0FFFFFF0Fh ; set data byte to zero
or eax,ebx ; increase data by new setting
out dx,eax ; send data through port data

mov eax,08000C294h ; DRAM Configuration High address


mov ebx,007000000h ; copy register data for Bypass max: 7 memclk cycles
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,0F0FFFFFFh ; set data byte to zero
or eax,ebx ; increase data by new setting
out dx,eax ; send data through port data

mov eax,08000C294h ; DRAM Configuration High address


mov ebx,0A0000000h ; copy register data for 4 bank act window: 17 memclk
cycles
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,00FFFFFFFh ; set data byte to zero
or eax,ebx ; increase data by new setting
out dx,eax ; send data through port data

;-------------------------------------------------------------------------------------

mov eax,08000C2A0h ; DRAM Controller Miscellaneous Data address


mov ebx,0000001C0h ; copy register data for Idle cycle limit: 256 cycles
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,0FFFFFE3Fh ; 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:

Updated the AM2 Rom Patcher to 1.0.5 dated 6/9/07.

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:

1. It's a plain binary file.


2. It's size is a multiple of 512 bytes.
3. It's header has the following format:
A. 55AAh ;This is the 1st and 2nd byte, its a bootable code sign.
B. xxh ;This is the 3rd byte, where xx is the hex number that indicate the size of the rom
in a multiple of 512 bytes, e.g. for a 512 bytes rom it will be 01h.
C. jmp ;Commonly this is the 4th through 6th byte, usually this is a near jump instruction
that invoke the real initialization code of the rom.
D. retf (return far);The last byte in the header, it invokes a far return to pass the
program execution back to the main bios, you can invoke it in the initialization part as
well, so this does not have to be in the header.
4. Its byte checksum is exactly zero.
A. After all of its bytes are summed and goes through modulo 100h operation, it's equal
to zero. In practice this should be pretty easy, for example if you use Hexworkshop
version 3.0 or higher, from the Tools menu, choose generate checksum and choose byte
(8 bit) checksum to see the checksum of your file, for a valid rom it should be equal to
zero. This can be very handy if you want to turn your plain binary file into a valid rom,
just open the file using Hexworkshop or similar hex editor program and then generate the
checksum of your xxxx.com file, if it's not zero then subtract the remainder of your
current checksum from 100h, this is the byte you need to insert into your plain binary
file, for example if the remainder shown in Hexworkshop is 0x2C then you will need to
add D4 into your file. I usually add this byte into the end of the program to compensate
for the checksum needed, after the return instruction, so that it won't interfere with your
main code.

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:

use16 ; 16bit mode


ROM_SIZE_IN_BLOCK = 1 ; 1 means ROM size is 1 block (512
bytes)
ROM_SIZE_IN_BYTE = ROM_SIZE_IN_BLOCK * 512 ; number of 512 byte blocks

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

times (256)-($-$$) db 0 ; locate Main routine at 100h


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

mov eax,08000C28Ch ; copy register address DRAM Timing


High
mov ebx,000000300h ; copy register data for 200Mhz
15.6usec
mov dx,0CF8h ; set port address
out dx,eax ; send address through the port
mov dx,0CFCh ; set port data
in eax,dx ; receive data
and eax,0FFFFE0FFh ; set data in eax
or eax,ebx ; increase data
out dx,eax ; send data through port data

mov eax,08000C294h ; copy register address DRAM Config


High
mov ebx,000000008h ; copy register data for Async Latency
8nsec
mov dx,0CF8h ; set port address
out dx,eax ; send address through the port
mov dx,0CFCh ; set port data
in eax,dx ; receive data
and eax,0FFFFFFF0h ; set data in eax
or eax,ebx ; increase data
out dx,eax ; send data through port data

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
; 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

;***************** Set Tref to 15.6usec


*****************************************
mov eax, 8000C28Ch ; copy register address DRAM Timing
High
mov dx, 0CF8h ; set port address
out dx, eax ; send address through the port
mov dx, 0CFCh ; set port data
in eax, dx ; receive data
and eax, 0FFFFE0FFh ; set data in eax with Tref bit=0h
or eax, 00000300h ; set data in eax Tref bit=3h(200Mhz
15.6usec)
out dx, eax ; send new data through port data

;***************** Set Async Latency to 8nsec ;


************************************
mov eax, 8000C294h ; copy register address DRAM Config
High
mov dx, 0CF8h ; set port address
out dx, eax ; send address through the port
mov dx, 0CFCh ; set port data
in eax, dx ; receive data
and eax, 0FFFFFFF0h ; set data in eax with Async Latency
bit=0h
or eax, 00000008h ; set data in eax Async Latency bit=8h
(8nsec)
out dx, eax ; send new data through port data

;
***********************************************************************************
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:

1. It's a plain binary file.


2. It's size is a multiple of 512 bytes.
3. It's header has the following format:
A. 55AAh ;This is the 1st and 2nd byte, its a bootable code sign.
B. xxh ;This is the 3rd byte, where xx is the hex number that indicate the size of the rom
in a multiple of 512 bytes, e.g. for a 512 bytes rom it will be 01h.
C. jmp ;Commonly this is the 4th through 6th byte, usually this is a near jump instruction
that invoke the real initialization code of the rom.
D. retf (return far);The last byte in the header, it invokes a far return to pass the
program execution back to the main bios, you can invoke it in the initialization part as
well, so this does not have to be in the header.
4. Its byte checksum is exactly zero.
A. After all of its bytes are summed and goes through modulo 100h operation, it's equal
to zero. In practice this should be pretty easy, for example if you use Hexworkshop
version 3.0 or higher, from the Tools menu, choose generate checksum and choose byte
(8 bit) checksum to see the checksum of your file, for a valid rom it should be equal to
zero. This can be very handy if you want to turn your plain binary file into a valid rom,
just open the file using Hexworkshop or similar hex editor program and then generate the
checksum of your xxxx.com file, if it's not zero then subtract the remainder of your
current checksum from 100h, this is the byte you need to insert into your plain binary
file, for example if the remainder shown in Hexworkshop is 0x2C then you will need to
add D4 into your file. I usually add this byte into the end of the program to compensate
for the checksum needed, after the return instruction, so that it won't interfere with your
main code.
5. The PCI Option ROM has the additional requirement of having the Vendor and
Device ID codes in the header. The ID's of your PCI module can be found using the
techniques described in the Building an AWARD PCI ROM Discussion Thread.

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----------------------------------------
;---------------------------------------------------------------------------------

ROM_SIZE_IN_BLOCK = 1 ; 1 means ROM size is 1 block (512


bytes)
ROM_SIZE_IN_BYTE = ROM_SIZE_IN_BLOCK * 512

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 = nforce4 CK804 NIC

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


TIMES 18h-($-$$) DB 0 ; padding zeros to offset 18h
DW PCIHDR ; pointer to PCI Header
DW PNPHDR ; pointer to PnP Expansion Header

PCIHDR: DB 'PCIR' ; PCI data structure signature


DW VENDOR_ID ; vendor ID (must
match real PCI device)
DW DEVICE_ID ; device ID (must
match real PCI device)
DW 0 ; pointer to vital product data
(0=none)
DW 24 ; PCI data structure length [B]
DB 0 ; PCI data structure revision (0=PCI
2.1)
DB 2,0,0 ; PCI device class code
(2=network ctrlr,0=eth.)
DW ROM_SIZE_IN_BLOCK ; ROM size in 512B blocks
DW 0 ; revision level of code
DB 0 ; code type (0=x86
compitable)
DB 80h ; last image indicator
DW 0 ; reserved

PNPHDR: DB '$PnP' ; PnP data structure signature


DB 1 ; PnP structure revision
DB 2 ; PnP structure length (in
16B blocks)
DW 0 ; offset to next header (0-
none)
DB 0 ; reserved
DB 33h ; PnP structure checksum
DD 0 ; device identifier
DW 0 ; pointer to manufacturer string
DW 0 ; pointer to productname string
DB 2,0,0 ; device class code (2=network
ctrlr,0=eth.)
DB 64h ; device indicators (64h - shadowable,
cacheable,not
; only for boot,IPL device)
DW 0 ; boot connection vector (0-
none)
DW 0 ; disconnect vector (0-
none)
DW 0 ; bootstrap entry vector (0-
none)
DW 0 ; reserved
DW 0 ; static resource info vector (0-
none)

MAIN:
pushfd
push eax
push ebx
push bx
push dx
push si
push ds
push bp

mov eax,08000C28Ch ; copy register address DRAM Timing


High
mov ebx,000000300h ; copy register data for 200Mhz
15.6usec
mov dx,0CF8h ; set port address
out dx,eax ; send address through the port
mov dx,0CFCh ; set port data
in eax,dx
and eax,0FFFFE0FFh ; set data in eax
or eax,ebx ; increase data
out dx,eax ; send data through port data

mov eax,08000C294h ; copy register address DRAM Config


High
mov ebx,000000007h ; copy register data for Async Latency
7nsec
mov dx,0CF8h ; set port address
out dx,eax ; send address through the port
mov dx,0CFCh ; set port data
in eax,dx
and eax,0FFFFFFF0h ; set data in eax
or eax,ebx ; increase data
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:

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 PCI Option ROM Using Code Injection
The information presented here is the product of many months of trial, error with both the PCI and ISA Option ROM
projects, plus reading Assembly Language Programming tutorials and manuals over and over. 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.

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:

1. It's a plain binary file.


2. It's size is a multiple of 512 bytes.
3. It's header has the following format:
A. 55AAh ;This is the 1st and 2nd byte, its a bootable code sign.
B. xxh ;This is the 3rd byte, where xx is the hex number that indicate the size of the rom in a multiple of 512 bytes, e.
g. for a 512 bytes rom it will be 01h.
C. jmp ;Commonly this is the 4th through 6th byte, usually this is a near jump instruction that invoke the real
initialization code of the rom. Some BIOS use a call instruction here.
D. retf (return far);The last byte in the header, it invokes a far return to pass the program execution back to the main
bios, you can invoke it in the initialization part as well, so this does not have to be in the header.
4. Its byte checksum is exactly zero.
A. After all of its bytes are summed and goes through modulo 100h operation, it's equal to zero. In practice this should
be pretty easy, for example if you use Hexworkshop version 3.0 or higher, from the Tools menu, choose generate
checksum and choose byte (8 bit) checksum to see the checksum of your file, for a valid rom it should be equal to zero.
This can be very handy if you want to turn your plain binary file into a valid rom, just open the file using Hexworkshop
or similar hex editor program and then generate the checksum of your xxxx.com file, if it's not zero then subtract the
remainder of your current checksum from 100h, this is the byte you need to insert into your plain binary file, for
example if the remainder shown in Hexworkshop is 0x2C then you will need to add D4 into your file. I usually add this
byte into the end of the program to compensate for the checksum needed, after the return instruction, so that it won't
interfere with your main code.
5. The PCI Option ROM has the additional requirement of having the Vendor and Device ID codes in the
header. The ID's of your PCI module can be found using the techniques described in the Building an AWARD PCI ROM
Discussion Thread.
All of the requirements for the PCI ROM Module are met with the LAN Boot ROM, as it is a valid PCI ROM. Only the jump
instruction in the header will be changed.
It should be noted the PCI, ISA, VGA, and GV3 ROM modules all have the same basic format requirements of items 1-4.
The "Code Injection" method could probably be performed on any of these that exist in the subject BIOS, if they have
enough room. But that is the subject for another topic and will not be pursued here.
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.

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.....

Here's copy and pasteable code:

code:

pushfd
push eax
push ebx
push bx
push dx
push si
push ds
push bp

mov eax,08000C288h ; DRAM Timing Low address


mov ebx,000EDC224h ; register data for: Cas, Trcd, Trp, Tras,
; Trc, Trrd, Twr
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,0FF000CC8h ; set data byte to zero
or eax,ebx ; increase data by new setting
out dx,eax ; send data through port data

mov eax,08000C28Ch ; cDRAM Timing High address


mov ebx,06DB20300h ; register data for: Twtr, Tref, Trfc
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,0000CFCFFh ; set data byte to zero
or eax,ebx ; increase data by new setting
out dx,eax ; send data through port data

mov eax,08000C290h ; DRAM Configuration Low address


mov ebx,000000080h ; register data for: Drive Strength Normal
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,0FFFFFF7Fh ; set data byte to zero
or eax,ebx ; increase data by new setting
out dx,eax ; send data through port data

mov eax,08000C294h ; DRAM Configuration High address


mov ebx,000100090h ; register data for: Async & CRC
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,0FFEFFF0Fh ; set data byte to zero
or eax,ebx ; increase data by new setting
out dx,eax ; send data through port data

mov eax,08000C2A0h ; DRAM Miscellaneous address


mov ebx,00000012Ch ; register data for: Idle Cycle,
; Dynamic Idle, Queue Bypass, Trfc0-3
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,0FFFFFE13h ; 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

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.

Put it all back together and it works perfectly!


Details:
This is the _ITEM.BIN module. Top window is unchanged from the original. The bottom has 1B0Fh changed to 0010h at the beginning
and 1B0Fh changed to 0110h at the end. 1B0Fh is the 28th address in the 16th group. I changed it to the 1st address in the 17th
group. 00h is always the 1st position.
Here in the _EN_CODE.BIN module, we see the address of the 17th group. It was blank, and I made it 6082h, because that is where I
added the labels addresses.
Here we see the labels that I added to the end of the _EN_CODE.BIN module.
And finally the addresses of the labels. Note that in the 6082h address is 0200h which indicates that there are 2 labels in this group or
address list. The first address is 5FE0h and I have highlighted that address in the label area in the bottom window.

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.

A modification of a BIOS that has no _item.bin is documented here:


Adding a New Item to a BIOS Without _ITEM.BIN
Item Help
In my BIOS mods, I try to add "Item Help" verbiage in the right hand pane of the BIOS window. One of the issues is formatting that
information. It tends to run on, wrap around, and sometimes loses a character when wrapping around..

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!

Here I have selected 4 Items to put under a unused branch:


Adding New Unused Items, And Moving Them Safely

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:

And the result is 1 more unused Item:


Now to Moving Them Around
Another idea from luk1999 for "safe" moving of Items is to simply change their "Position Code" to that of where we want the
new Items to show up in the BIOS. This requires going in and finding the "Position Code" of Items already in the area where
we want our new Items to show up.

A quick reminder of the sequence definition:

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

All u need to have is Hex Editor & Cbrom

- After done modding Original.tmp file


lets say the file we mod is AN7.bin (biosfile) & original tmp file (System.bin)
- install it to the bios file:
cbrom an7.bin /other 5000:0 system.bin
-then open the AN7.bin with hex editor
-copy the new award compression for the file we just install
-save it to blank file(System.bin Award compression)

-Then release all bios module from an7.bin


-until only System Bios file left there
-now re-open back an7.bin the bios file with hex editor
-copy the hack system.bin compression file and paste it ON original temp file in Abit.bin
-then re-install back all bios module
-this way... Cbrom will do the checksum

Pinczakko:

Just a little bit clarifications to remove the "myths" regarding this method.

code:

cbrom an7.bin /other 5000:0 system.bin

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:

- install it to the bios file:


cbrom an7.bin /other 5000:0 system.bin
-then open the AN7.bin with hex editor
-copy the new award compression for the file we just install
-save it to blank file(System.bin Award compression)

These steps compress the modified system BIOS. Probably the same as using LHA compressor with modified header. I'll check it
later

Anyway, in a little better English terms .

quote:

This hack had been done to ABIT AN7 bios version 15... which was not possible to hack with Modbin/Modhack

All u need to have are Hex Editor & Cbrom

- After you're done modding Original.tmp file,


lets say the file you mod is AN7.bin (the biosfile) & its original_tmp/system_bios file is system.bin

- install it the system_bios/original_tmp file to the bios file:


cbrom an7.bin /other 5000:0 system.bin

-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.

-Then release all bios module from an7.bin

-until only system_bios file left there


-now re-open back an7.bin the bios file with hex editor

-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

-then re-install back all bios module with Cbrom

-this way... Cbrom will do the checksum

offtopic: Hei tictac I thought you're joining an English course in Bali . I'm just kidding man. Good work, as always

Polygon:

OK, let's try this and see where it leads.....


Here's a basic Award BIOS before releasing any modules. Note the System BIOS is at the top of the list:
Here I've released all the modules and only the System BIOS is left:

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

All u need to have are Hex Editor & Cbrom OK

- After you're done modding Original.tmp file,


lets say the file you mod is AN7.bin (the biosfile) & its original_tmp/system_bios file is system.bin OK

- install it the system_bios/original_tmp file to the bios file:


cbrom an7.bin /other 5000:0 system.bin 1st problem: the original BIOS does not have enough room to do this. I had
to release the Logo and Memtest for it to fit. I have successfully been installing the system.bin to a BIOS with all the
modules removed. The added system.bin immediately follows the original system bios(or the last module) with a single
FFh byte separating them when installed into the BIOS with all the modules removed.
I notice that CBRom generates a file called bios.rom that is the system.bin compressed and is exactly what has been
added to the BIOS. That bios.rom can be used as the "copy" and the BIOS that has 2 system bios can be deleted.
-then open the AN7.bin (which is injected with the modified system_bios file) with hex editor OK
-copy the new compressed system_bios in the injected AN7.bin and save it to blank binary file, named system.bin. OK,
this would save it as compressed, but it could be Copied N' Pasted right from here. Really no need for a blank binary
file or this step. The bios.rom file is the exact, compressed module we need.

-Then release all bios module from an7.bin OK

-until only system_bios file left there 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.

-this way... Cbrom will do the checksum OK

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.

Another informative thread is the CMOS Registers(Indexes) Discussion Thread

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:

use16 ; 16bit mode

ROM_SIZE_IN_BLOCK = 16 ; 1 means ROM size is 1 block (512 bytes)


ROM_SIZE_IN_BYTE = ROM_SIZE_IN_BLOCK * 512 ; number of 512 byte blocks

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

times (256)-($-$$) db 0 ; locate Main routine at 100h

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

; 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:
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 200Mhz@7.8usec.
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:

use16 ; 16bit mode

ROM_SIZE_IN_BLOCK = 16 ; 1 means ROM size is 1 block (512 bytes)


ROM_SIZE_IN_BYTE = ROM_SIZE_IN_BLOCK * 512 ; number of 512 byte blocks

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

times (256)-($-$$) db 0 ; locate Main routine at 100h

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)
;====================================================================

;READ MEMORY TIMING STATE


mov al, 81h ;index - 81h
out 072h, al ;send register offset
in al, 073h ;fetch data
and al, 30h ;mask 0011.0000
cmp al, 00h
je codend ;jump if equal 0000.0000, Auto Selected

;reading from cmos


mov al, 021h ;index - 021h
out 072h, al ;send register offset
in al, 073h ;fetch data
mov cl, al ;save for later
and al, 07h ;mask 0000.0111
cmp al, 00h ;
je TREF ;jump if equal 00h, Auto selected
cmp al, 01h ;
je RWQ2 ;jump if equal 01h
cmp al, 02h ;
je RWQ4 ;jump if equal 02h
cmp al, 03h ;
je RWQ8 ;jump if equal 03h
cmp al, 04h ;
je RWQ16 ;jump if equal 04h
jmp TREF ;jump to TREF
RWQ2:
;set Queue Bypass 2x
mov eax,08000C290h ; DRAM Configuration Low Address
mov ebx,000000000h ; 2X
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFFF3FFFh ;
or eax,ebx ;
out dx,eax ;
jmp TREF
RWQ4:
;set Queue Bypass 4x
mov eax,08000C290h ; DRAM Configuration Low Address
mov ebx,000004000h ; 4X
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFFF3FFFh ;
or eax,ebx ;
out dx,eax ;
jmp TREF
RWQ8:
;set Queue Bypass 8x
mov eax,08000C290h ; DRAM Configuration Low Address
mov ebx,000008000h ; 8X
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFFF3FFFh ;
or eax,ebx ;
out dx,eax ;
jmp TREF
RWQ16:
;set Queue Bypass 16x
mov eax,08000C290h ; DRAM Configuration Low Address
mov ebx,00000C000h ; 16X
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFFF3FFFh ;
or eax,ebx ;
out dx,eax ;

;====================================================================

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 Tref100@15.6 ;jump if equal 0001.0000
cmp al, 20h
je Tref133@15.6 ;jump if equal 0010.0000
cmp al, 30h
je Tref166@15.6 ;jump if equal 0011.0000
cmp al, 40h
je Tref200@15.6 ;jump if equal 0100.0000
cmp al, 50h
je Tref100@7.8 ;jump if equal 0101.0000
cmp al, 60h
je Tref133@7.8 ;jump if equal 0110.0000
cmp al, 70h
je Tref166@7.8 ;jump if equal 0111.0000
cmp al, 80h
je Tref200@7.8 ;jump if equal 1000.0000
cmp al, 90h
je Tref100@3.9 ;jump if equal 1001.0000
cmp al, 0A0h
je Tref133@3.9 ;jump if equal 1010.0000
cmp al, 0B0h
je Tref166@3.9 ;jump if equal 1011.0000
cmp al, 0C0h
je Tref200@3.9 ;jump if equal 1100.0000
jmp ICL

Tref100@15.6:
;set Tref=100Mhz@15.6usec
mov eax,08000C28Ch ; DRAM Timing High Address
mov ebx,000000000h ; 100Mhz@15.6usec
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFFFE0FFh ;
or eax,ebx ;
out dx,eax ;
jmp ICL

Tref133@15.6:
;set Tref=133Mhz@15.6usec
mov eax,08000C28Ch ; DRAM Timing High Address
mov ebx,000000100h ; 133Mhz@15.6usec
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

Tref166@15.6:
;set Tref=166Mhz@15.6usec
mov eax,08000C28Ch ; DRAM Timing High Address
mov ebx,000000200h ; 166Mhz@15.6usec
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

Tref200@15.6:
;set Tref=200Mhz@15.6usec
mov eax,08000C28Ch ; DRAM Timing High Address
mov ebx,000000300h ; 200Mhz@15.6usec
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

;===============================================================================

Tref100@7.8:
;set Tref=100Mhz@7.8usec
mov eax,08000C28Ch ; DRAM Timing High Address
mov ebx,000000400h ; 100Mhz@7.8usec
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFFFE0FFh ;
or eax,ebx ;
out dx,eax ;
jmp ICL

Tref133@7.8:
;set Tref=133Mhz@7.8usec
mov eax,08000C28Ch ; DRAM Timing High Address
mov ebx,000000500h ; 133Mhz@7.8usec
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

Tref166@7.8:
;set Tref=166Mhz@7.8usec
mov eax,08000C28Ch ; DRAM Timing High Address
mov ebx,000000600h ; 166Mhz@7.8usec
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

Tref200@7.8:
;set Tref=200Mhz@7.8usec
mov eax,08000C28Ch ; DRAM Timing High Address
mov ebx,000000700h ; 200Mhz@7.8usec
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

;===============================================================================

Tref100@3.9:
;set Tref=100Mhz@3.9usec
mov eax,08000C28Ch ; DRAM Timing High Address
mov ebx,000000800h ; 100Mhz@3.9usec
mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ;
and eax,0FFFFE0FFh ;
or eax,ebx ;
out dx,eax ;
jmp ICL

Tref133@3.9:
;set Tref=133Mhz@3.9usec
mov eax,08000C28Ch ; DRAM Timing High Address
mov ebx,000000900h ; 133Mhz@3.9usec
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

Tref166@3.9:
;set Tref=166Mhz@3.9usec
mov eax,08000C28Ch ; DRAM Timing High Address
mov ebx,000000A00h ; 166Mhz@3.9usec
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

Tref200@3.9:
;set Tref=200Mhz@3.9usec
mov eax,08000C28Ch ; DRAM Timing High Address
mov ebx,000000B00h ; 200Mhz@3.9usec
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

cmp al, 00h


je ICL0 ;jump if equal 0000.0000
cmp al, 20h
je ICL4 ;jump if equal 0010.0000
cmp al, 40h
je ICL8 ;jump if equal 0100.0000
cmp al, 60h
je ICL16 ;jump if equal 0110.0000
cmp al, 80h
je ICL32 ;jump if equal 1000.0000
cmp al, 0A0h
je ICL64 ;jump if equal 1010.0000
cmp al, 0C0h
je ICL128 ;jump if equal 1100.0000
cmp al, 0E0h
je ICL256 ;jump if equal 1110.0000
jmp codend

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

; 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 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:

use16 ; 16bit mode

ROM_SIZE_IN_BLOCK = 16 ; 1 means ROM size is 1 block (512 bytes)


ROM_SIZE_IN_BYTE = ROM_SIZE_IN_BLOCK * 512 ; number of 512 byte blocks

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

times (256)-($-$$) db 0 ; locate Main routine at 100h

MAIN:

pushfd
push eax
push ebx
push ecx
push dx

;====================================================================
; Async Latency Fix CR51A505.RHx BIOS
; _ITEM.BIN: 1168h
; CMOS: 0A3h
; mask: 0Fh
;====================================================================

;reading from cmos


mov al, 0A3h ;index - 0A3h
out 072h, al ;send register offset
in al, 073h ;fetch data
mov cl, al ;save for later
and al, 0Fh ;mask 0000.1111

cmp al, 00h


je AUTO ;jump if equal 0000.0000
cmp al, 01h
je ASL1 ;jump if equal 0000.0001
cmp al, 02h
je ASL2 ;jump if equal 0000.0010
cmp al, 03h
je ASL3 ;jump if equal 0000.0011
cmp al, 04h
je ASL4 ;jump if equal 0000.0100
cmp al, 05h
je ASL5 ;jump if equal 0000.0101
cmp al, 06h
je ASL6 ;jump if equal 0000.0110
cmp al, 07h
je ASL7 ;jump if equal 0000.0111
cmp al, 08h
je ASL8 ;jump if equal 0000.1000
cmp al, 09h
je ASL9 ;jump if equal 0000.1001
cmp al, 0Ah
je ASL10 ;jump if equal 0000.1010
cmp al, 0Bh
je ASL11 ;jump if equal 0000.1011
cmp al, 0Ch
je ASL12 ;jump if equal 0000.1100
cmp al, 0Dh
je ASL13 ;jump if equal 0000.1101
cmp al, 0Eh
je ASL14 ;jump if equal 0000.1110
cmp al, 0Fh
je ASL15 ;jump if equal 0000.1111

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

; 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 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:

Remember the Sequence Definition Chart:


At the end of the _EN_CODE.BIN module, I added a total of 508 bytes:

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:

use16 ; 16bit mode

ROM_SIZE_IN_BLOCK = 16 ; 1 means ROM size is 1 block (512 bytes)


ROM_SIZE_IN_BYTE = ROM_SIZE_IN_BLOCK * 512 ; number of 512 byte blocks

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

times (256)-($-$$) db 0 ; locate Main routine at 100h

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
;====================================================================

;reading from cmos


mov al, 020h ;index - 020h
out 072h, al ;send register offset
in al, 073h ;fetch data
mov cl, al ;save for later
and al, 0Fh ;mask 0000.1111

cmp al, 00h


je TREF ;jump if equal 0000.0000
cmp al, 01h
je TRTW2 ;jump if equal 0000.0001
cmp al, 02h
je TRTW3 ;jump if equal 0000.0010
cmp al, 03h
je TRTW4 ;jump if equal 0000.0011
cmp al, 04h
je TRTW5 ;jump if equal 0000.0100
cmp al, 05h
je TRTW6 ;jump if equal 0000.0101
cmp al, 06h
je TRTW7 ;jump if equal 0000.0110
cmp al, 07h
je TRTW8 ;jump if equal 0000.0111
cmp al, 08h
je TRTW9 ;jump if equal 0000.1000
jmp TREF

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

cmp al, 00h


je ASL ;jump if equal 0000.0000
cmp al, 10h
je TREF1 ;jump if equal 0001.0000
cmp al, 20h
je TREF2 ;jump if equal 0010.0000
cmp al, 30h
je TREF3 ;jump if equal 0011.0000
jmp ASL

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

cmp al, 00h


je codend ;jump if equal 0000.0000
cmp al, 01h
je ASL5 ;jump if equal 0000.0001
cmp al, 02h
je ASL6 ;jump if equal 0000.0010
cmp al, 03h
je ASL7 ;jump if equal 0000.0011
cmp al, 04h
je ASL8 ;jump if equal 0000.0100
cmp al, 05h
je ASL9 ;jump if equal 0000.0101
cmp al, 06h
je ASL10 ;jump if equal 0000.0110
cmp al, 07h
je ASL11 ;jump if equal 0000.0111
cmp al, 08h
je ASL12 ;jump if equal 0000.1000
cmp al, 09h
je ASL13 ;jump if equal 0000.1001
cmp al, 0Ah
je ASL14 ;jump if equal 0000.1010
cmp al, 0Bh
je ASL15 ;jump if equal 0000.1011

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

; 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:

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.

Here is an example of the "jump" code I have been using:

;READ MEMORY TIMING STATE


mov al, 0C0h ;Memory Timing index - C0h
out 072h, al ;send register offset
in al, 073h ;fetch data
and al, 08h ;mask 0000.1000
cmp al, 00h ;compare al to 00h
je codend ;jump if equal 0000.0000, Auto Selected
Original post by luk1999:
I had this problem to. But I found a solution: ISA-code should be executed only if some option (which is cleared after
resetting CMOS) in original BIOS is set to some value. Almost all BIOS's have option which allows to set memory timings
manually and by SPD. We need to found where this option writes data, and check this byte before executing code inside ISA-
ROM.
Here’s a example:
We know, that option, which allows us to set memory timings manually stores information in register no. 50h.
Mask is 01h.
00h - load timings from SPD (default setting after Clearing CMOS), and 01h allows us to set timings manually.
So we need to use 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:

I hope, that this will help you.

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:

Here are the modules in the original BIOS:


I had previously released all the modules and renamed the BIOS, shell.bin, and made several backup copies. Now that the
new system.bin compressed code is pasted over the original compressed code, it's time to add the modules back in using
CBROM:

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:

use16 ; 16bit mode

ROM_SIZE_IN_BLOCK = 16 ; 1 means ROM size is 1 block (512 bytes)


ROM_SIZE_IN_BYTE = ROM_SIZE_IN_BLOCK * 512 ; number of 512 byte blocks

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

times (256)-($-$$) db 0 ; locate Main routine at 100h

;====================================================================
; 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

;READ TIMING MODE STATE


mov al, 81h ;index - C0h
out 072h, al ;send register offset
in al, 073h ;fetch data
and al, 20h ;mask 0010.01000
cmp al, 00h ;compare al to 00h
je codend ;jump if equal 0000.0000, Auto Selected

;===================== DRAM Configuration Low ========================

;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

mov eax,08000C290h ; DRAM Configuration Low Address


mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ; fetch dword at DRAM Configuration Low Address

mov ebx, eax ; move dword to ebx in case cl=00h


cmp cl, 00h
je RWQSEND ;jump if equal 0000.0000
mov ebx,000000000h ; 2x
cmp cl, 20h
je RWQSEND ;jump if equal 0010.0000
mov ebx,000004000h ; 4x
cmp cl, 40h
je RWQSEND ;jump if equal 0100.0000
mov ebx,000008000h ; 8x
cmp cl, 60h
je RWQSEND ;jump if equal 0110.0000
mov ebx,00000C000h ; 16x
cmp cl, 80h
je RWQSEND ;jump if equal 1000.0000
mov ebx, eax ; move dword to ebx in case cl out of range
RWQSEND:
and eax,0FFFF3FFFh ; Mask R/W Queue Bit
or ebx,eax ; add R/W byte to dword

;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

mov eax, ebx ; move dword to ebx in case cl=00h


cmp cl, 00h
je BPMSEND ;jump if equal 0000.0000
mov ebx,002000000h ; 1x
cmp cl, 04h
je BPMSEND ;jump if equal 0000.0100
mov ebx,004000000h ; 2x
cmp cl, 08h
je BPMSEND ;jump if equal 0000.1000
mov ebx,006000000h ; 3x
cmp cl, 0Ch
je BPMSEND ;jump if equal 0000.1100
mov ebx,008000000h ; 4x
cmp cl, 10h
je BPMSEND ;jump if equal 0001.0000
mov ebx,00A000000h ; 5x
cmp cl, 14h
je BPMSEND ;jump if equal 0001.0100
mov ebx,00C000000h ; 6x
cmp cl, 18h
je BPMSEND ;jump if equal 0001.1000
mov ebx,00E000000h ; 7x
cmp cl, 1Ch
je BPMSEND ;jump if equal 0001.1100
mov ebx, eax ; move dword to ebx in case cl out of range
BPMSEND: and eax,0F1FFFFFFh ; Mask R/W Queue Bit
or eax,ebx ; add R/W byte to dword
out dx,eax ; Send dword at DRAM Config Low Address

;===================== DRAM Configuration High =======================

;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

mov eax,08000C294h ; DRAM Config High Address


mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ; fetch dword at DRAM Config High Address

mov ebx, eax ; move dword to ebx in case cl=00h


cmp cl, 00h
je ASLSEND ;jump if equal 0000.0000
mov ebx,000000004h ; Async Lat 4T
cmp cl, 10h
je ASLSEND ;jump if equal 0001.0000
mov ebx,000000005h ; Async Lat 5T
cmp cl, 20h
je ASLSEND ;jump if equal 0010.0000
mov ebx,000000006h ; Async Lat 6T
cmp cl, 30h
je ASLSEND ;jump if equal 0011.0000
mov ebx,000000007h ; Async Lat 7T
cmp cl, 40h
je ASLSEND ;jump if equal 0100.0000
mov ebx,000000008h ; Async Lat 8T
cmp cl, 50h
je ASLSEND ;jump if equal 0101.0000
mov ebx,000000009h ; Async Lat 9T
cmp cl, 60h
je ASLSEND ;jump if equal 0110.0000
mov ebx,00000000Ah ; Async Lat 10T
cmp cl, 70h
je ASLSEND ;jump if equal 0111.0000
mov ebx,00000000Bh ; Async Lat 11T
cmp cl, 80h
je ASLSEND ;jump if equal 1000.0000
mov ebx,00000000Ch ; Async Lat 12T
cmp cl, 90h
je ASLSEND ;jump if equal 1001.0000
mov ebx,00000000Dh ; Async Lat 13T
cmp cl, 0A0h
je ASLSEND ;jump if equal 1010.0000
mov ebx,00000000Eh ; Async Lat 14T
cmp cl, 0B0h
je ASLSEND ;jump if equal 1011.0000
mov ebx,00000000Fh ; Async Lat 15T
cmp cl, 0C0h
je ASLSEND ;jump if equal 1100.0000
mov ebx, eax ; move dword to ebx in case cl out of range
ASLSEND:
and eax,0FFFFFFF0h ; mask Async Lat bit
or ebx,eax ; add Async byte to dword

;Idle Cycle Limit


;reading from cmos
mov al, 0BCh ;index - 0BCh
out 072h, al ;send register offset
in al, 073h ;fetch data
and al, 0Fh ;mask 0000.1111
mov cl, al ;save for later

mov eax, ebx ;save new dword for later


cmp cl, 00h
je IDLSEND ;jump if equal 0000.0000
mov ebx,000000000h ; 0 Clocks
cmp cl, 01h
je IDLSEND ;jump if equal 0000.0001
mov ebx,000010000h ; 4 Clocks
cmp cl, 02h
je IDLSEND ;jump if equal 0000.0010
mov ebx,000020000h ; 8 Clocks
cmp cl, 03h
je IDLSEND ;jump if equal 0000.0011
mov ebx,000030000h ; 16 Clocks
cmp cl, 04h
je IDLSEND ;jump if equal 0000.0100
mov ebx,000040000h ; 32 Clocks
cmp cl, 05h
je IDLSEND ;jump if equal 0000.0101
mov ebx,000050000h ; 64 Clocks
cmp cl, 06h
je IDLSEND ;jump if equal 0000.0110
mov ebx,000060000h ; 128 Clocks
cmp cl, 07h
je IDLSEND ;jump if equal 0000.0111
mov ebx,000070000h ; 256 Clocks
cmp cl, 08h
je IDLSEND ;jump if equal 0000.1000
mov ebx, eax ; move dword to ebx in case cl out of range
IDLSEND:
and eax,0FFF0FFFFh ; Mask Idle Cycle Limit Bit
or eax,ebx ; add Idle Cycle byte to dword
out dx,eax ; Send dword at DRAM Controller Misc Address

;===================== DRAM DQS Delay Line Register ==========================

;DQS Slew Control


;reading from cmos
mov al, 0BDh ;index - 0BDh
out 072h, al ;send register offset
in al, 073h ;fetch data
and al, 03h ;mask 0000.0011
mov cl, al ;save for later

mov eax,08000C298h ; DRAM Delay Line Register Address


mov dx,0CF8h ;
out dx,eax ;
mov dx,0CFCh ;
in eax,dx ; fetch dword at DRAM Delay Line Register Address

mov ebx, eax ; move dword to ebx in case cl=00h


cmp cl, 00h
je DQSSEND ;jump if equal 0000.0000
mov ebx,001000000h ; slow
cmp cl, 01h
je DQSSEND ;jump if equal 0000.0001
mov ebx,002000000h ; fast
cmp cl, 02h
je DQSSEND ;jump if equal 0000.0010
mov ebx, eax ; move dword to ebx in case cl out of range
DQSSEND:
and eax,0FCFFFFFFh ; Mask DQS Bit
or eax,ebx ; add DQS to dword
out dx,eax ; Send dword at DRAM DQS Delay Line Register
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

; 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:

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"

Modified Sequences(3Ah was unused):


057Dh-->0000 0008 87F8 3F00 4A3F 0001 0800 002B 0083 0200 0000 0000 00 "CPU Multiplier Setting"
10C4h-->0000 0008 FFFF 3F00 3A3F 0001 0800 002B 0081 0200 0000 0000 00 "NPT Fid Control"

Here's the Sequence definition again:

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

Here is a link to memtest.rom and memsetup.rom for 1.70: memtest170rom.zip

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:

Now to remove the existing memsetup.rom, at the command prompt, we execute:


Cbrom yourbios.bin /oem3 release.

Then we insert the new memsetup.rom into the BIOS by executing:


Cbrom yourbios.bin /oem3 memsetup.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.

Here is a link to memtest.rom and memsetup.rom for 1.70: memtest170rom.zip

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

Here is the download link:


AMIBCP8 2.25Beta (Windows)
And some newer versions:
AMIBCP2.42.zip
AMIBCP2.43.23.zip

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)

Latest is here: MMTool 3.12

This program is the AMI equivalent of CBROM32 for AWARD BIOS's....

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:

First one, I later find out, is the LAN Boot Agent:


Second is the SATA2 code:
Here we see the tell-tale code for the ISA, PCI, and several other Option ROM's(55h AAh) The 3ed byte is the Hex size of 512bytes. That's 88(58h) blocks
of 512 bytes. Note that I checked the checksum, and it's 00h just like any good Option ROM should be:
And here is the VendorID and Device ID, least siginifcent byte first. Note that MMTool had given us those ID's that are required for a PCI ROM to work:
The assembly code compiled without a hitch:
Looking at the binary with Hex Workshop, everything seems to be in order. Header, ID's and checksum are as they should be:
Here we're setup to replace the PCI Boot LAN with our Option ROM:
Here the replacement has taken place and you can notice the locations and size are different.
The "RunLoc" is the same because that is the ID's:
As a sanity check, I'll extract the added ROM and compare it to the original PCI_ROM3.bin:
The "test.rom" and the original PCI_ROM3.bin compare to be the same:
After saving the BIOS and shutting down all the programs, I reopened the BIOS and extracted
the ROM for 1 last comparison. I really want this to work:
Once again, Hex Workshop says the ROM has not changed:
All that's left now is to flash the BIOS and #1 see it it even boots( ) and #2 see if turning the Network Boot LAN to "Enable", sets the Tref to
15.6usec@200 as checked with the A64 Tweaker.

Here's the PCI Option ROM code I used to set Tref to 15.6usec@200:

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

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

db 0 ; checksum, to be filled in later


TIMES 18h-($-$$) DB 0 ; padding zeros to offset 18h
DW PCIHDR ; pointer to PCI Header
DW PNPHDR ; pointer to PnP Expansion Header

PCIHDR: DB 'PCIR' ; PCI data structure signature


DW VENDOR_ID ; vendor ID (must match real PCI device)
DW DEVICE_ID ; device ID (must match real PCI device)
DW 0 ; pointer to vital product data (0=none)
DW 24 ; PCI data structure length [B]
DB 0 ; PCI data structure revision (0=PCI 2.1)
DB 2,0,0 ; PCI device class code (2=network ctrlr,0=eth.)
DW ROM_SIZE_IN_BLOCK ; ROM size in 512B blocks
DW 0 ; revision level of code
DB 0 ; code type (0=x86 compitable)
DB 80h ; last image indicator
DW 0 ; reserved

PNPHDR: DB '$PnP' ; PnP data structure signature


DB 1 ; PnP structure revision
DB 2 ; PnP structure length (in 16B blocks)
DW 0 ; offset to next header (0-none)
DB 0 ; reserved
DB 33h ; PnP structure checksum
DD 0 ; device identifier
DW 0 ; pointer to manufacturer string
DW 0 ; pointer to productname string
DB 2,0,0 ; device class code (2=network ctrlr,0=eth.)
DB 64h ; device indicators (64h - shadowable,cacheable,not
; only for boot,IPL device)
DW 0 ; boot connection vector (0-none)
DW 0 ; disconnect vector (0-none)
DW 0 ; bootstrap entry vector (0-none)
DW 0 ; reserved
DW 0 ; static resource info vector (0-none)

MAIN:
pushfd
push eax
push ebx
push bx
push dx
push si
push ds
push bp

mov eax,08000C28Ch ; copy register address DRAM Timing High


mov ebx,000000300h ; copy register data for 200Mhz 15.6usec
mov dx,0CF8h ; set port address
out dx,eax ; send address through the port
mov dx,0CFCh ; set port data
in eax,dx
and eax,0FFFFE0FFh ; set data in eax
or eax,ebx ; increase data
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:
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...

Here's the link if you want to try it...

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:

Here's the Intel equivalent:


Here's the registers 250h-251h map. I'll start with a simple change to Tras:

--------------------

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:

use16 ; 16bit mode


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 ;<------------ 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

mov eax,080000048h ; (G)MCH Base Address Register


mov ebx,000000001h ; copy register data for MCHBAR Enable
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,0FFFFFFFEh ; set data bit to zero
or eax,ebx ; increase data by new setting
out dx,eax ; send data through port data

mov ax,[00003FD95h] ; fetch data at 250h-251h address


mov bx,8800h ; copy data for Tras 17T
and ax,07FFh ; set Tras data bit to zero
or ax,bx ; increase data for Tras: 17T
mov [00003FD95h],ax ; send data with 17T change

pop dx
pop ebx
pop eax
popfd ; Pop Stack into Eflags Register
retf ; Return Far from Procedure

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, 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:

F000:EE3B call Enter_UnrealMode ; jump below in UnrealMode


F000:EE3E Begin_in_UnrealMode
F000:EE3E mov ax, ds
F000:EE40 mov es, ax ; es = ds (3rd entry in GDT)
F000:EE40 ; base_addr=0000 0000h;limit 4GB
F000:EE42 assume es:nothing
F000:EE42 mov esi, 80000h ; mov esi,(POST_Cmprssed_Temp_Seg shl 4)
F000:EE42 ; relocate lower 128KB bios code
F000:EE48 mov edi, 160000h
F000:EE4E mov ecx, 8000h
F000:EE54 cld ; Clear Direction Flag
F000:EE55 rep movs dword ptr es:[edi], dword ptr [esi] ; move
F000:EE55 ; 128k data to 160000h (phy addr)
F000:EE59 call Leave_UnrealMode ; Call Procedure
F000:EE59 End_in_UnrealMode
.........
F000:7440 Enter_UnrealMode proc near ; CODE XREF: F000:EE3B
F000:7440 mov ax, cs
F000:7442 mov ds, ax ; ds = cs
F000:7444 assume ds:F000
F000:7444 lgdt qword ptr GDTR_F000_5504 ; Load Global Descriptor Table Register
F000:7449 mov eax, cr0
F000:744C or al, 1 ; Logical Inclusive OR
F000:744E mov cr0, eax
F000:7451 mov ax, 10h
F000:7454 mov ds, ax ; ds = 10h (3rd entry in GDT)
F000:7456 assume ds:nothing
F000:7456 mov ss, ax ; ss = 10h (3rd entry in GDT)
F000:7458 assume ss:nothing
F000:7458 retn ; Return Near from Procedure
F000:7458 Enter_UnrealMode endp
.........
F000:5504 GDTR_F000_5504 dw 30h ; DATA XREF: Enter_PMode+4
F000:5504 ; GDT limit (6 valid desc)
F000:5506 dd 0F550Ah ; GDT phy addr (below)
F000:550A dq 0 ; null desc
F000:5512 dq 9F0F0000FFFFh ; code desc (08h)
F000:5512 ; base_addr=F0000h;seg_limit=64KB;code,execute/ReadOnly
F000:5512 ; conforming,accessed;granularity=1Byte;16-bit segment;
F000:5512 ; segment present,code,DPL=0
F000:551A dq 8F93000000FFFFh ; data desc (10h)
F000:551A ; base_addr=0000 0000h;seg_limit=4GB;data,R/W,accessed;
F000:551A ; granularity=4KB;16-bit segment; segment present,
F000:551A ; data,DPL=0
F000:5522 dq 0FF0093FF0000FFFFh ; data desc 18h
F000:5522 ; base_addr=FFFF0000h;seg_limit=64KB;data,R/W,accessed;
F000:5522 ; 16-bit segment,granularity = 1 byte;
F000:5522 ; segment present, data, DPL=0.
F000:552A dq 0FF0093FF8000FFFFh ; data desc 20h
F000:552A ; base_addr=FFFF8000h;seg_limit=64KB;data,R/W,accessed;
F000:552A ; 16-bit segment,granularity = 1 byte;
F000:552A ; segment present, data, DPL=0.
F000:5532 dq 930F0000FFFFh ; data desc 28h
F000:5532 ; base_addr=F0000h;seg_limit=64KB;data,R/W,accessed;
F000:5532 ; 16-bit segment,granularity = 1 byte;
F000:5532 ; segment present, data, DPL=0.

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:

use16 ; 16bit mode


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 ;<------------ 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

mov eax,080000048h ; (G)MCH Base Address Register


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
mov ebx,eax ; save the old value
or eax,1 ; increase data by new setting
out dx,eax ; send data through port data

and ebx,0FFFFC000h ; mask off bits 31:14 inclusive


add ebx,250h ; point to the relevant part
mov ax,[fs:ebx] ; fetch data at 250h address
and ax,07FFh ; set Tras data bit to zero
or ax,8800h ; copy data for Tras 17T
mov [fs:ebx],ax ; send data with 17T change

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

; 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:

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

Yes it boots into Windows without issue....

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:

use16 ; 16bit mode


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 ;<------------ 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

mov eax,080000048h ; (G)MCH Base Address Register


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
mov ebx,eax ; save the old value
or eax,1 ; increase data by new setting
out dx,eax ; send data through port data

and ebx,0FFFFC000h ; mask off bits 31:14 inclusive


add ebx,250h ; point to the relevant part
mov ax,[fs:ebx] ; fetch data at 250h address
and ax,07FFh ; set Tras data bit to zero
or ax,9000h ; copy data for Tras 18T
mov [fs:ebx],ax ; send data with 18T change

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

; 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:

--------------------

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:

mov eax,080000048h ; (G)MCH Base Address Register


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
mov ebx,eax ; save the old value
or eax,1 ; increase data by new setting
out dx,eax ; send data through port data

and ebx,0FFFFC000h ; mask off bits 31:14 inclusive


add ebx,250h ; point to the relevant part
mov ax,[fs:ebx] ; fetch data at 250h address
and ax,07FFh ; set Tras data bit to zero
or ax,9000h ; copy data for Tras 18T
mov [fs:ebx],ax ; send data with 18T change

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:

use16 ; 16bit mode


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 ;<------------ 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

call flatmode ; first, set up FS to access all 4G

mov eax,080000048h ; (G)MCH Base Address Register


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
mov ebx,eax ; save the old value
or eax,1 ; increase data by new setting
out dx,eax ; send data through port data

mov ax,[fs:0FED14250h] ; fetch data at 250h-251h address


mov bx,9000h ; copy data for Tras 18T
and ax,07FFh ; set Tras data bit to zero
or ax,bx ; increase data for Tras: 18T
mov [fs:0FED14250h],ax ; send data with 18T change

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

; 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:
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

; now load the GDT into the GDTR


lgdt fword ptr gdt ; load GDT base (286-style 24-bit load)
mov bx,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
and al,0FEh ; clear the PE bit again
mov cr0,eax ; back to real mode
sti ; resume handling interrupts
ret ;
flatmode endp
;----------------------------------------------------------------------
GDT DESC386 <GDT_END - GDT - 1, GDT, 0, 0, 0, 0> ; the GDT itself
DESC386 <0ffffh, 0, 0, 092h, 0cfh, 0> ; 4G data segment
GDT_END:
end start
Studying Protected Mode, Global Descriptor Tables, and Assembly around the clock the
last few days....

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.

Here's the new code:


code:

use16 ; 16bit mode


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 ;<------------ 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

mov eax,080000048h ; (G)MCH Base Address Register


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
mov ebx,eax ; save the old value
or eax,1 ; increase data by new setting
out dx,eax ; send data through port data
and ebx,0FFFFC000h ; mask off bits 31:14 inclusive
add ebx,250h ; point to the relevant part
mov ax,[fs:ebx] ; fetch data at 250h address
and ax,07FFh ; set Tras data bit to zero
or ax,9000h ; copy data for Tras 18T
mov [fs:ebx],ax ; send data with 18T change

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.....

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....

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.

Potrebbero piacerti anche