---
# System prepended metadata

title: AWARD BIOS v4.5x hacking notes

---

# AWARD BIOS v4.5x hacking notes

This document contains information used to construct modifications in BIOSes on vintage motherboards.

It is the knowledge base for the BIOS modifications released here:

https://github.com/oerg866/TRW-BiosMods

# New Setup Structure

The "New Setup Structure" usually starts at **0xF85C** in the F Segment and contains the following items:

* 0xBB identifier
    * **F85D:** Bios Setup Menu List Pointer
    * **F85F:** Rom Table Pointer (Chipset register configuration list)
    * **F861:** Rom Table End Pointer
    * **F863:** "Auto Table" pointer - obsolete and unused IIRC?
    * **F865:** "Auto Table" end pointer
    * **F867:** "Auto Table" String list pointer

## Rom Table (Chipset Configuration Register List)

This is an array of Register list entries of the following format:


| Offset | Type | Description |
| ------ | ---- | ----------- |
| 0      | BYTE | "Register Type" (?) - Not sure what this is. Seems to be 2 for most things, but I've seen 3 as well (might be for Power management regs) |
| 1      | BYTE | **Index** - Register index in PCI config space. |
| 2      | BYTE | **PCI Device Identifier** - For PCI this is 5 bits device, 3 bits function (always on bus 0). Not sure of the format for ISA devices. |
| 3      | WORD | **Mask** Mask of the bits that will be affected by this write. Example: **FB** would affect all bytes except bit 2 (**1111 1X11**). Note that this is a word, but for PCI config writes only the least significant byte will be used. I think this can theoretically also be used for 16 bit ISA writes, but I'm not sure. |
| 5      | WORD | **Value** The value to write to the register. It will be ANDed with the *Mask* and ORed with the previous value in the register.

The size of this structure is 7 bytes and is not padded.

### How this table is referenced

***Note:*** The "New Setup Structure" is *not* usually how the BIOS retreives this table. This structure is there for automatic processing with tools such as CBROM and MODBIN, *not* for the BIOS' own operation.

It's sadly more "hardcoded" than that.

![image](https://hackmd.io/_uploads/SkwbJ84xR.png)

This is example code pulled from a BIOS ROM. 

To relocate this table, both the vector table *and* the code must be updated.


# PCI Bus Configuration

## PCI Slot table

This table is standardized for all BIOSes that support PCI 2.0.

At `FE90` in the F segment you will find the `0xBB` marker, along with an offset in the F segment to the PCI slot list.

```nasm
    CK_ORG    0FE90H
    db        0bbh				
    extrn     Pci_Slot_Cfg:near		
    dw        offset DGROUP:Pci_Slot_Cfg
```

The corresponding table would look like this:

```nasm 
    db        0bh
    db        0dh
    db 	      0fh
    db        11h
    db        0ffh
```

Where there's 1 byte per slot ID and a list end marker (0xff).

Exception: ASUS PVI-486SP3 - The slot table does exist, but it is empty?!

**TODO: Why?** I assume ASUS is doing some ASUSian custom shenanigans here - MODBIN also shows the PCI slot table as empty. I have not yet been able to locate where.

Interesting factoid: The latest BIOS version for that board *does* have an intact interrupt table.

## PCI Interrupt table

The expectation *AWDBEDIT* makes is that this table is standardized in the configuration vectors of the AWARD BIOS, at `F_SEG:0FE99h`.

The leaked AWARD 4.51PG source code confirms this suspicion, prepends it with the 0xAA identification marker.

However, this was previously *not* the case, as earlier 4.51 variants prove (e.g. SOYO 4SAW).

Generally, there seems to be no standardized way of finding this table, other than finding the code that loads it.

# Text rendering

There are two major text rendering functions in any AWARD 4.5x BIOS:

* `Show_String`
* `Show_CS_String`

They take two parameters, the **Segment** and **Offset** of the string to show.

The difference between the two is that `Show_String` uses the `ds` (data segment) register as input parameter for the segment, whereas `Show_CS_String` uses the `cs` (code segment) register (really, it is just a wrapper that saves `ds` and then sets it to the value of `ds` before calling the regular `Show_String`).

## Control codes

The text can have control codes (ASCII < 0x20) in it, which allow you to modify text attributes or do other actions during the printing of the string.

The following table lists them for AWARD 4.50 / 4.51 (later BIOSes may differ slightly).

| Code | Name | Description |
| ---- | ---- | ----------- |
| 0x00 | V_DONE      	| End of string marker. |
| 0x01 | V_DONE1     	| End of string marker (OR blank entry marker, see details below.) |
| 0x02 | V_BORDER    	| Draw border on the screen. |
| 0x03 | V_CLEAR     	| Clear rectangle on the screen. |
| 0x04 | V_STRSHOW   	| Prints another sub-string and continues. |
| 0x05 | V_POS       	| Set absolute cursor position. |
| 0x06 | V_HILITE       | Draws text with intensity bit set. |
| 0x07 | V_REVERSE      | Draws text with "REVERSE" color of current color scheme (usually inverted to the regular color). |
| 0x08 | V_NORMAL    	| Resets text attributes (color, etc.) to normal. |
| 0x09 | V_BLINK     	| Draws text with BLINK attribute. |
| 0x0A | V_WARN      	| Draws text with "WARN" color of current color scheme. |
| 0x0B | V_NEWLINE   	| Moves cursor to the beginning of the next line. |
| 0x0C | V_ADDX 	 	| Add to X position. |
| 0x0D | V_SUBX 	 	| Subtract from X position.|
| 0x0E | V_ADDY 	 	| Add to Y position. |
| 0x0F | V_SUBY 	 	| Subtract from Y position. |
| 0x10 | V_CALLROUTINE  | Calls a subroutine. |

### Offset parameters for control codes

Some control codes take an offset as part of the parameters. This is always an offset **within the segment of the string that is currently being displayed.**

There is no way to reference data in another segment within the strings.

### 0x01 (V_DONE1)

This is another end of text marker, except for setup menu entry text.

In case of a setup menu entry, **this indicates the current item should be skipped in the selection, i.e. not selectable.**

### 0x02 (V_BORDER)

Draws a border on the screen.

| Parameters | |
|------|------|
| BYTE | 0x02 (V_BORDER) |
| BYTE | Left X position |
| BYTE | Left Y position |
| BYTE | Right X position |
| BYTE | Right Y position |
| BYTE | Border type (Bitfield) |

| Bit  | Border Type |
|------|--|
| 0x01 | ║ Double Border |
| 0x02 | ? Empty Border (?) |
| 0x04 | │ Line Border |
| 0x08 | ? "NO BORDER" (?) |
| 0x10 | Shadow Border (**Late 4.51PG ONLY**) |

I don't know why this is a bit field because other than shadow border, these seem mutually exclusive :thinking_face: 


### 0x03 (V_CLEAR)

**TODO**

### 0x04 (V_STRSHOW)

Calls the string printing function with another string. Frequently used to print the same string for multiple different options where part of the string remains identical between them all to save space.

| Parameters | |
|------|------|
| BYTE | 0x04 (V_STRSHOW) |
| BYTE | X Position <br> (0xFF = at current position) |
| BYTE | Y Position <br> (0xFF = at current position) |
| WORD | Offset of substring to insert. |

### 0x05 (V_POS)

Set absolute cursor position.

| Parameters | |
|------|------|
| BYTE | 0x05 (V_POS) |
| BYTE | X Position |
| BYTE | Y Position |

### 0x0C (V_ADDX), 0x0D (V_SUBXX), 0x0E (V_ADDY), 0x0F (V_SUBY)

Adds or subtracts from cursor X or Y position.

| Parameters | |
|------|------|
| BYTE | 0x0C (V_ADDX), 0x0D (V_SUBXX), 0x0E (V_ADDY), 0x0F (V_SUBY) |
| BYTE | Value to add/subtract |

### 0x10 (V_CALLROUTINE)

Calls a subroutine before resuming printing

| Parameters | |
|------|------|
| BYTE | 0x05 (V_POS) |
| WORD | Offset of routine to call |

# Setup Menu
