Skip to content

ObjectInfoNavi

Ausdauersportler edited this page Mar 23, 2023 · 11 revisions

Description and analysis of data table

Using the atomdis tool we can extract the ObjInfo data table from the RX5500XT original video BIOS. It prints the contents and even the information about the most important variables we want to examine and modify. Keep in mind we have to reverse byte order when fetching data from the vBIOS file directly, see Endianness.

atomdis RX5500XT.rom d 16
Read 100000 bytes of data from RX5500XT-ORIG.rom

data_table  0000c530  #16  (Object_Info/Object_Header):

  Size         00a8
  Format Rev.  01
  Param Rev.   00
  Content Rev. 04

  00000000:            880e 0500  1331 5800  2122 0000        .....1X.!"..
  00000010: 8500 0000  0800 0000  1332 6100  1e21 0000    .........2a..!..
  00000020: 8c00 0000  8000 0000  1333 6a00  1e22 0000    .........3j.."..
  00000030: 9300 0000  0002 0000  1334 7300  2021 0000    .........4s. !..
  00000040: 9a00 0000  0004 0000  1335 7c00  2121 0000    .........5|.!!..
  00000050: a100 0000  0008 0000  0104 9100  0204 0200    ................
  00000060: ff01 0492  0002 0403  00ff 0104  9300 0204    ................
  00000070: 0400 ff01  0494 0002  0405 00ff  0104 9000    ................
  00000080: 0204 0100  ff14 060f  0000 00ff  1406 0f00    ................
  00000090: 0000 ff14  060f 0000  00ff 1406  0f00 0000    ................
  000000a0: ff14 060f  0000 00ff                          ........        

  NOTE: General revisionless dumper only.
  NOTE: Data part see radeonhd

  0000:  ATOM_COMMON_TABLE_HEADER sHeader                    :
  0000:  USHORT usStructureSize                              = 0x00a8     (168)
  0002:  UCHAR ucTableFormatRevision                         = 0x01       (1)
  0003:  UCHAR ucTableContentRevision                        = 0x04       (4)

  0004:  USHORT usDeviceSupport                              = 0x0e88     (3720)
  0006:  USHORT usConnectorObjectTableOffset                 = 0x0005     (5)

  0008:  USHORT usRouterObjectTableOffset                    = 0x3113     (12563)
  000a:  USHORT usEncoderObjectTableOffset                   = 0x0058     (88)
  000c:  USHORT usProtectionObjectTableOffset                = 0x2221     (8737)
  000e:  USHORT usDisplayPathTableOffset                     = 0x0000     (0)

  Total data structure size:  0010

This complete structure has been defined in the Linux header files. Whenever necessary I have added links to the very same header file using particular line numbers were crucial information can be found.

The 4 byte header decode length of the table in bytes (A800 becomes (endian) to 0x00A8 = 168d bytes) next bytes 0104 is the ucTableFormatRevision and 0x01 the ucTableContentRevision 0x04.

The next two byte are 880e and encode the device support 880e-> 0x0e88 of all connectors defines later, it is a bitfield, the bits are described in this list. We needed to change this value to 0x0e8a -> 8a0e - it sets basically bit #1 to 1 (LCD1 support).

Next two bytes decode the number of connectors in the vBIOS, here 0500 -> 0x0005 = 5d. This info will remain unchanged.

Now follow 5 (# of connectors) chunks of 16 bytes describing each of the five connectors, in particular

13315800212200008500000008000000

Using the C struct atom_display_object_path_v2 or the upper printout from atomdis we can easily decode these 16 Byte into

1331  uint16_t display_objid; //Connector Object ID or Misc Object ID
5800  uint16_t disp_recordoffset;
2122  uint16_t encoderobjid; //first encoder closer to the connector, could be either an external or intenal encoder
0000  uint16_t extencoderobjid; //2nd encoder after the first encoder, from the connector point of view;
8500  uint16_t encoder_recordoffset;
0000  uint16_t extencoder_recordoffset;
0800  uint16_t device_tag; //a supported device vector, each display path starts with this.the paths are enumerated in the way of priority, a path appears first 

The device_tag contain two bye called

uint8_t  priority_id;
uint8_t  reserved;

All entries including recordoffset in it's name are literally only offsets in bytes (absolute numbers counting from the start of the data table. These records can contain one or more encoded structures, in particular here again at position 0x58 you find two such structures followed by a FF stop byte:

0104910002040200FF

The first structure is 01049100 and decodes to

01049100 - 01 struture type, 04 structure length in byte, content 9100 (this is 0x0091 the I2C ID of the first connector)

(Typ 01 = ATOM_I2C_RECORD_TYPE)

The second structure is 02040200 and decodes to

02040200 - 02 struture type, 04 structure length in byte, content 0200 (this is 0x0020 the pin ID and plugin state of the first connector)

(Typ 02 = ATOM_HPD_INT_RECORD_TYPE)

at position 0x85 you will find another list of such structures, in this particular case it is only a single one

14060F000000FF - 14 struture type, 06 structure length in byte, content 0F00 0000 (this is 0x0000000F, a bit mask)

(Typ 14 = ATOM_ENCODER_CAP_RECORD_TYP) 0xF covers the first five entries of this enumeration, 0x1FF would cover them all.

Changing connector type from DP to eDP to enable internal LCD

The device_tag describes the connector type, all five connectors described uses a display port type. So we need to change this entry to eDP 0x002 or 0200 and at the same time we know from analyzing all the former AMD vBIOS versions that the display_objid like 1331 has to begin with 14, like 1431.

In my case the successful change was using the second connector changing the display_objid

1332 -> 1432

and the device_tag from

8000 -> 0200

If you take the complete 16 byte description of the second connector you get this:

1332 6100 1E21 0000 8C00 0000 8000 0000 (original DP)

1432 6100 1E21 0000 8C00 0000 0200 0000 (modified to eDP)

This was in addition to the usDeviceSupport value adjustment all we needed to change at the very end!

Injecting the vBIOS using OpenCore

So the process in general would be quite easy: You prepare five simple modified OBJ_INFO data tables using ATOMTableResize to fetch the original table from the BIOS, using Hex Fiend to do this simple modification and change on by one the both device_tag and display_objid. These modified tables will be imported back into the original BIOS creating five versions. It is important to use the tool ATOMTableResize because it will fix the checksum of the legacy BIOS header. A wrong checksum makes macOS ignoring the injected BIOS!

Unfortunately the RX5500XT in particular does not run when flashed with a modified BIOS. So the only workaround would be to inject the first 64K bytes of the five versions via OpenCore DeviceProperties of the GPU into the macOS.

The DevicePath of this GPU looks unusual PciRoot(0x0)/Pci(0x1,0x0)/Pci(0x0,0x0)/Pci(0x0,0x0)/Pci(0x0,0x0) and using the ATY,bin _image with type Data you can copy and paste from Hex Fiend into Xcode editing the config.plist the first 64k. Change the view in Hex Fiend (byte grouping to None) to avoid getting white spaces copied over).

<key>PciRoot(0x0)/Pci(0x1,0x0)/Pci(0x0,0x0)/Pci(0x0,0x0)/Pci(0x0,0x0)</key>
                        <dict>
                                <key>enable-gva-support</key>
                                <integer>1</integer>
                                <key>shikigva</key>
                                <integer>128</integer>
                                <key>unfairgva</key>
                                <integer>1</integer>
                                <key>ATY,bin_image</key> 
                                <data>Vapw6T ...... 64K bytes</data>
                       </dict>

You will also need two more entries applbkl=3 and agdpmod=pikera to the boot-args of OpenCore in the config.plist. The former will enable the brightness control keys and after a system sleep also brightness control while the latter is key to avoid macOS shutting down the internal LCD on the login screen. This agdpmod=pikera is needed for all RDNA1.0 AMD dGPU when used in Macs and Hacks. So no exception here.

Further potential enhancements to the OBJ_INFO and LCD_INFO data table

Before using the simple mode described above we also added in one big operation more modifications to the table changing the size by adding more structures.

The second structure is 02040200 and decodes to

03040200 - 03 struture type, 04 structure length in byte, content 0200 (this is 0x0020 the I2C ID of the first connector)

(Typ 03 = ATOM_CONNECTOR_CAP_RECORD_TYPE)

and

2306020000 - 23 struture type, 06 structure length in byte, content 020000 (this is 0x000020 the I2C ID of the first connector)

(Typ 23 = ATOM_DISP_CONNECTOR_CAPS_RECORD_TYPE)

The result will be like this, you have to adjust size and record address entries as described above:

DA0001048A0E05001331580021220000
B70000000800000014326B001E210000
BE0000000200000013337E001E220000
C5000000000200001334910020210000
CC000000000400001335A40021210000
D3000000000800000104910002040200
03040200230602000000FF0104920002
04030003040200230602000000FF0104
93000204040003040200230602000000
FF010494000204050003040200230602
000000FF010490000204010003040200
230602000000FF14060F000000FF1406
0F000000FF14060F000000FF14060F00
0000FF14060F000000FF

finally we thought we would have to add the PWM frequency of 13.000 Hz used by the iMac in an another data table named LCD_INFO. The process to fetch, alter and reinsert is always the same and needs ATOMTableResize to fix the checksum after each change.

The PWM frequency would be located at absolute position 36d, and coded to C832 = 0x32C8 = 13000d Hz - the number has to be used in Hertz.

The absolute position of 36d depends on table analysis, again. The table header is always 4 bytes encoding length and revision numbers. It is followed by an structure containing another struct atom_dtd_format of 28 bytes size and atom_common_table_header of four bytes size, makes 4+28+4 = 36 (all decimal).

4 Byte LCD_INFO HEADER 28 Byte struct atom_dtd_format 4 Byte struct atom_common_table_header

-> 2 Byte uint16_t backlight_pwm at position 36d

5C00 0201 0000 0000 0000 0000 0000 0000
0000 0000 0000 0000 0000 0000 0600 0000
0000 C832 0000 3421 0000 B80B 0000 0000
7D00 0001 0000 0000 00FF FF00 0000 0000
0000 0000 0000 0000 0000 0000 0000 0000
0000 0000 0000 0000 0000 0000

Final reminder:

After making changes to your vBIOS use ATOMTableResize to included the modified tables and fix the checksum. Thereafter you can get the first 64k using Hex Fiend, again. Do not just alter the vBIOS using the editor. Your iMac will ignore the injected vBIOS!