3

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

t I I
Advanced Chipset features
Idle Cycle Limit [Auto]
Async Latency [Auto]
R/W Queue Bypass [Auto]
Bypass Max [Auto]
O D S Slew Castro[ i
ACP Aperture SizeIdle tjcle Limit
x ACP 3.0 Speed
ACP 2.8 Speed Auto [■]
ACP Fast Write Sclks [ ]
ACP Sideband Addr 4clks [ ]
Special I/O for P 8clks [ ]
x Base 1/0 Address 16clks [ ]
x 1/0 Length 32clks [ ]
System BILLS Cache 64clks [ ]
128cLks [ ]
34 =177RIILL

oenix - AwardBIOS CMOS Setup Utill,
Advanced Chipset Features
Idle Cycle Limit (Auto] Item Help
Async Latency EAuto]
R/M Queue Bypass EAuto] Neon Level ►
Bypass Mix Este]
PUS Slew Control
ACP Aperture SizeAayac Ilateecy
x A C P 3. 8 Sd pee
AC! 2.8 Speed Auto E.] •
ACP Fast write 4nsec E 1
ACP Sideband Addr 5nsec E ]
Special I/O for t 6nsec E ]
x Base I/O Address ?nsec [ ]
:x I/O Length Onsec . E ]
Sgetew BIOS Cabe 9nsec E ]
18nsec . E ]
ti :Move ENTER :Accept ESC :Rbort
ter :Select + :Save ESC :Exit F
:Previous teal : Optiwi�iid ISfali,

Idle Cyc l'e [Auto]
Asguc Latency [Auto]
R/W Queue Bypass [Auto] Menu Level ►
Bypass Max [Auto]
DQS Slew Control
ACP Aperture Size Async Latency
x AGP 3.8 Speed
ACP 2.8 Speed Bnsec [ ]
AGP Fast Write 9nsec [ ]
AGP Sideband Addr lUnsec [ I
Special I/O for P 11nsec [ ]
x Base I/O Address 12nsec [ I
x I/O Length 13nsec [ I
System BIOS Cache 14nsec [ ]
15nsec [•]
tl:Nove ENTER Accept ESC:Rbort
ter :Select */
:Previous Ualu

7n: 11 1; 1 (1
t
Idle Cycle Limit (Auto] IteN Nerp
Async Latency [Auto]
B/Il Queue Bypass [Auto] Menu Level ►
Bypass Nax [Auto]
)QS Slew Control
AC? Aperture Size R/M qua
ACP 3.8 Speed
ACP 2.6 Speed Auto [e]
ACP Fast Write 2x [ ]
ACP Sideband Addr 4x I ]
Specia t I/O for P 8x t ]
x Base I/O Address 16x [ ]
xI/O Length
System BIOS Cacbe
tl :Move ENTER :Accept ESC :Abort

W 71
Advanced
Idle Cycle Limit [Auto]
Async Latency [Auto]
R/W Queue Bypass [Auto] Menu Level ►
Bypass Max [Auto]
DQS Slew Coatro l
ACP Aperture Size Bypass Max
x ACP 3.8 Speed
ACP 2.8 Speed
ACP Fast Write
ACP Sideband Rddr
Special I/O for P
x Base I/O Address
x I/O Length
SysteM BIOS Cache
tl :Move ENTER :Accept ESC:Abort

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

IS <Address>
Set Start Address.
<Address> MUST be a 8 digits hexadecimal value.
/U
Specifies that the module is to be placed as uncompressed.
Note:
• Any parameter encolsed by < > is a mandatory field.
• Any parameter enclosed by [ I is an optional field.
• <Module ID> MUST be a 2 digits hexadecimal value.
• <ROM Hole Number> MUST be a decimal value.
• [/M] can be a condition to find out module in ROM Image exactly.
• [/A]&[/C]&[/N]&[/S] are valid only for </I> and </R> command.
• </D> command can use [/M] only.
• Both [/M] and [/U] are available for </E> command.
•[/N] should not co-exist with [/S]. By priority, [/N] < [/S].
•[/C] should not co-exist with [/S]. By priority, [/C] < [/S].
• All option is available only for </D>, </E>, </I> and </R> commands.
C:\Documents and Settings\aryan\Desktop\BIOS Disassembly>AMIMMWIN BIOS.ROM /R 1B
1B.BIN

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:

(G)MCH Register Description
Bit Access & Description
Default
23:16 R/W Bus Number. If the Bus Number is programmed to 00h the target
of the Configuration Cycle is a PCI Bus 0 agent. If this is the case
00h
and the (G)MCH is not the target (i.e., the device number is >_ 2),
then a DMI Type 0 configuration cycle is generated.
If the Bus Number is non-zero, and does not fall within the ranges
enumerated by device 1's Secondary Bus Number or Subordinate
Bus Number Register, then a DMI Type 1 configuration cycle is
generated.
If the Bus Number is non-zero and matches the value programmed
into the Secondary Bus Number Register of device 1, a Type 0 PCI
configuration cycle will be generated on PCI Express-G.
If the Bus Number is non-zero, greater than the value in the
Secondary Bus Number Register of device 1 and less than or equal to
the value programmed into the Subordinate Bus Number Register of
device 1, a Type 1 PCI configuration cycle will be generated on PCI
Express-G.
This field is mapped to byte 8 (7:0] of the request header format
during PCI Express Configuration cycles and A[23:16] dunng the
DMI Type 1 configuration cycles.
15:11 R/W Device Number. This field selects one agent on the PCI bus
selected by the Bus Number. When the Bus Number field is 00h, the
00h
(G)MCH decodes the Device Number field. The (G)MCH is always
Device Number 0 for the Host bridge entity, Device Number 1 for the
Host-PCI Express entity. Therefore, when the Bus Number =0 and
the Device Number equals 0, 1, or 2, the internal (G)MCH devices
are selected.
This field is mapped to byte 6 [7:3] of the request header format
during PCI Express Configuration cycles and A [15:11] during the
DMI configuration cycles.
10:8 R/W Function Number. This field allows the configuration registers of a
particular function in a multi-function device to be accessed. The
OOOb
(G)MCH ignores configuration cycles to its internal devices if the
function number is not equal to 0 or 1.
This field is mapped to byte 6 [2:0] of the request header format
during PCI Express Configuration cycles and A[10:8] during the DMI
configuration cycles.
7:2 R/W Register Number. This field selects one register within a particular
Bus, Device, and Function as specified by the other fields in the
00h
Configuration Address Register.
This field is mapped to byte 7 [7:2] of the request header format
during PCI Express Configuration cycles and A[7:2] during the DMI
Configuration cycles.
1:0 Reserved

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

5.1.13 MCHBAR-(G)MCH Memory-Mapped Register Range Base
BID/F/Type: 0/0/0/PCI
Address Offset: 48-4Fh
Default Value: 0000000000000000h
Access: R/W, RO
Size: 64 bits
This is the base address for the (G)MCH memory-mapped configuration space. There
is no physical memory within this 16 KB window that can be addressed. The 16 KB
reserved by this register does not alias to any PCI 2.3 compliant memory mapped
space. On reset, the (G)MCH MMIO memory-mapped configuration space is disabled
and must be enabled by writing a 1 to MCHBAREN [Dev 0, offset 48h, bit 0].
Bit Access & Description
Default
63:36 RO Reserved
0000000h
35:14 R/'W (G)MCH Memory Mapped Base Address (MCHBAR): This field
000000h corresponds to bits 35 to 14 of the base address (G)MCH memory-
mapped configuration space. BICS will program this register resulting
in a base address for a 16 KB block of contiguous memory address
space. his register ensures that a naturally aligned 16 KB space is
allocated within the first 4 GB of addressable memory space. System
Software uses this base address to program the (G)MCH memory-
mapped register set.
13:1 RO Reserved
0000h
0 RJW MCHBAR Enable (MCHBAREN):
Ob 0 = D;sable. MCHBAR Ices rot clam any memory
1 = Enable. MCHBAR memory-mapped accesses are claimed and
decoded appropriately.

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

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License