Last active
May 11, 2023 07:08
-
-
Save jfoster/f1a93e017389b0679d573fe988585346 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
""" | |
Copyright 2015 tx12 http://www.overclock.net/u/376106 | |
Portions of this software are based in part on the work of atomdis authors | |
Portions of this software are based in part on the work of amdgpu Linux | |
kernel driver authors | |
* Permission is hereby granted, free of charge, to any person obtaining a | |
* copy of this software and associated documentation files (the "Software"), | |
* to deal in the Software without restriction, including without limitation | |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
* and/or sell copies of the Software, and to permit persons to whom the | |
* Software is furnished to do so, subject to the following conditions: | |
* | |
* The above copyright notice and this permission notice shall be included in | |
* all copies or substantial portions of the Software. | |
* | |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | |
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | |
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | |
* OTHER DEALINGS IN THE SOFTWARE. | |
Simple ATOMBIOS table manipulation tool v1.1 | |
optional arguments: | |
-h, --help show this help message and exit | |
commands: | |
{f,x,e,c,d,a} | |
f Fix BIOS image checksum | |
x Extract ATOM command table | |
e Extract ATOM data table | |
c Replace ATOM command table | |
d Replace ATOM data table | |
a Activate disabled cores | |
Usage: | |
Fix BIOS image checksum: | |
atomtool.py f [-h] infile outfile | |
arguments: | |
infile input rom file | |
outfile output rom file | |
Extract ATOM command table | |
atomtool.py x [-h] -t tableid infile table.bin | |
arguments: | |
-t tableid table id to extract | |
infile input rom file | |
table.bin output binary table file | |
Extract ATOM data table | |
atomtool.py e [-h] -t tableid infile table.bin | |
arguments: | |
-t tableid table id to extract | |
infile input rom file | |
table.bin output binary table file | |
Replace ATOM command table | |
atomtool.py c [-h] -t tableid -f table.bin infile outfile | |
arguments: | |
-t tableid table id to replace | |
-f table.bin input binary table file | |
infile input rom file | |
outfile output rom file | |
Replace ATOM data table | |
atomtool.py d [-h] -t tableid -f table.bin infile outfile | |
arguments: | |
-t tableid table id to replace | |
-f table.bin input binary table file | |
infile input rom file | |
outfile output rom file | |
NOTE: replacement is only possible to the table of the same size | |
Activate disabled cores | |
atomtool.py a [-h] -p type infile outfile | |
arguments: | |
-p type patch type (1 for 4-LOW, 2 for 4-HIGH, 3 for LOW+HIGH, or 65535 for all) | |
infile input rom file | |
outfile output rom file | |
Examples: | |
- extract PowerPlay table from file.rom to PowerPlay.bin: | |
atomtool.py e -t 15 file.rom PowerPlay.bin | |
- update PowerPlay table in file.rom from PowerPlay.bin and save rom as file_new.rom: | |
atomtool.py d -t 15 -f PowerPlay.bin file.rom file_new.rom | |
- fix checksum of PCBIOS image in file.rom and save rom as file_csok.rom: | |
atomtool.py f file.rom file_csok.rom | |
- try to activate cores in column #1 (4LOW) and save rom as file_4low.rom: | |
atomtool.py a -p 1 file.rom file_4low.rom | |
- try to activate all cores and save rom as file_all.rom (NOT RECOMMENDED!): | |
atomtool.py a -p 65535 file.rom file_all.rom | |
""" | |
import array | |
import struct | |
import argparse | |
import sys | |
import md5 | |
class AtomBios: | |
def __init__(self, file): | |
self.ATOM_COMMON_TABLE_HEADER = "<HBB" | |
self.__loadbios(file) | |
self.__init_atombios() | |
def __loadbios(self, f): | |
# PC PCI BIOS Expansion ROM header, per 6.3.3.1 PCI local bus specification 2.2 | |
PCBIOS_HEADER="<HB21xH" | |
f.seek(0,2) | |
l = f.tell() | |
f.seek(0,0) | |
if l < 32768 or l > 262144: | |
raise ValueError("unexpected file length ({0})".format(l)) | |
b = array.array('B', f.read(l)) | |
sig,rom_size,pcir_offset = struct.unpack_from(PCBIOS_HEADER,b) | |
if sig != 0xAA55: | |
raise ValueError("unexpected signature 0x{0:04X}".format(sig)) | |
self.bios = b | |
self.file_len = l | |
self.pcbios_len = rom_size*512 | |
self.pcir_offset = pcir_offset | |
def __init_atombios(self): | |
b = self.bios | |
# ATOM ROM HEADER, extremely simplified, per atombios.h | |
atom_rom_hdr_offset = struct.unpack_from("<H",b,0x48)[0] | |
ATOM_SIMPLE_HEADER = "<4x I22xHHxx" | |
ATOM_SIGNATURE = 0x4D4F5441 | |
atomsig, self.amct, self.amdt = struct.unpack_from( | |
ATOM_SIMPLE_HEADER, b, atom_rom_hdr_offset | |
) | |
if atomsig != ATOM_SIGNATURE: | |
raise ValueError("unexpected ATOM signature 0x{0:08X}".format(atomsig)) | |
self.command_tables = ( | |
struct.unpack_from( | |
self.ATOM_COMMON_TABLE_HEADER, b, self.amct | |
)[0] - struct.calcsize(self.ATOM_COMMON_TABLE_HEADER) ) / 2 | |
self.data_tables = ( | |
struct.unpack_from( | |
self.ATOM_COMMON_TABLE_HEADER, b, self.amdt | |
)[0] - struct.calcsize(self.ATOM_COMMON_TABLE_HEADER) ) / 2 | |
def __command_table(self, table): | |
b = self.bios | |
ATOM_MASTER_COMMAND_TABLE = "<4x {0}H".format(self.command_tables) | |
if table < 0 or table >= self.command_tables: | |
raise IndexError("command table index out of range: {0}".format(table)) | |
offset = struct.unpack_from(ATOM_MASTER_COMMAND_TABLE, b, self.amct)[table] | |
size = struct.unpack_from(self.ATOM_COMMON_TABLE_HEADER, b, offset)[0] | |
return offset, size | |
def __data_table(self, table): | |
b = self.bios | |
ATOM_MASTER_DATA_TABLE = "<4x {0}H".format(self.data_tables) | |
if table < 0 or table >= self.data_tables: | |
raise IndexError("data table index out of range: {0}".format(table)) | |
offset = struct.unpack_from(ATOM_MASTER_DATA_TABLE, b, self.amdt)[table] | |
size = struct.unpack_from(self.ATOM_COMMON_TABLE_HEADER, b, offset)[0] | |
return offset, size | |
def __replace_table(self, offset, size, newtable): | |
if offset == 0: | |
raise ValueError("can't replace target table because it doesn't exist") | |
new_len = struct.unpack_from(self.ATOM_COMMON_TABLE_HEADER, newtable)[0] | |
if new_len != len(newtable): | |
raise ValueError("incorrect length in new table data ({0})".format(new_len)) | |
if size != len(newtable): | |
raise ValueError("size mismatch between new and old table data ({0} != {1})".format(new_len, size)) | |
self.bios[offset:offset+size] = newtable | |
def get_command_table(self, table): | |
offset, size = self.__command_table(table) | |
return self.bios[offset:offset+size] if offset else None | |
def get_data_table(self, table): | |
offset, size = self.__data_table(table) | |
return self.bios[offset:offset+size] if offset else None | |
def replace_command_table(self, table, newtable): | |
offset, size = self.__command_table(table) | |
self.__replace_table(offset, size, newtable) | |
def replace_data_table(self, table, newtable): | |
offset, size = self.__data_table(table) | |
self.__replace_table(offset, size, newtable) | |
def calculate_checksum(self, fix=False): | |
CHECKSUM_OFFSET=0x21 | |
cs = sum(self.bios[0:self.pcbios_len]) & 0xFF | |
if(cs and fix): | |
ss = self.bios[CHECKSUM_OFFSET] | |
self.bios[CHECKSUM_OFFSET] = (ss - cs) & 0xFF | |
cs = sum(self.bios[0:self.pcbios_len]) & 0xFF | |
return cs | |
def tofile(self, file): | |
return self.bios.tofile(file) | |
def read_binary_file(file, sizelimit = 262144): | |
file.seek(0,2) | |
len = file.tell() | |
file.seek(0,0) | |
if(len > sizelimit): | |
raise VaueError("file is too long ({0})!".format(len)) | |
buffer = array.array('B', file.read(len)) | |
file.close() | |
return buffer | |
def save_binary(buffer, filename): | |
file = open(filename, "wb") | |
buffer.tofile(file) | |
file.close() | |
return 0 | |
def fix_checksum(atom, args): | |
atom.calculate_checksum(True) | |
return save_binary(atom, args.outfile) | |
def extract_command_table(atom, args): | |
table = atom.get_command_table(args.t) | |
if None == table: | |
raise ValueError("command table {0} is empty".format(args.t)) | |
return save_binary(table, args.outfile) | |
def extract_data_table(atom, args): | |
table = atom.get_data_table(args.t) | |
if None == table: | |
raise ValueError("data table {0} is empty".format(args.t)) | |
return save_binary(table, args.outfile) | |
def replace_command_table(atom, args): | |
atom.replace_command_table(args.t, read_binary_file(args.f)) | |
return fix_checksum(atom, args) | |
def replace_data_table(atom, args): | |
atom.replace_data_table(args.t, read_binary_file(args.f)) | |
return fix_checksum(atom, args) | |
def patch_table(table, mask): | |
# check table against known one | |
compat = set(["cb3aa12ad70d1f3d44f86b7bd7f02a00", "9c360f623acd511eaff96676d46c5050"]) | |
hash = md5.new(table).digest().encode('hex') | |
table_len = struct.unpack_from("<H", table)[0] | |
if hash not in compat: | |
raise ValueError("incompatible table in BIOS image") | |
PATCHADDR = 0x48 | |
PATCH_MASK_ADDR = 4 | |
patchdata = array.array( | |
'B', | |
"078d0100feff2d0d4202002d2540013e254004493900010500c2000000e05b7a6700".decode('hex') | |
) | |
patch_size_addr = len(patchdata) - 2 | |
db_size = table_len - PATCHADDR - patch_size_addr - 2 | |
mask = int(mask) ^ 0xFFFF | |
struct.pack_into("<H", patchdata, PATCH_MASK_ADDR, mask) | |
struct.pack_into("<H", patchdata, patch_size_addr, db_size) | |
l = len(patchdata) | |
table[PATCHADDR:PATCHADDR+l] = patchdata | |
return table | |
def activate_cores(atom, args): | |
t = 32; | |
table = atom.get_command_table(t) | |
if None == table: | |
raise ValueError("incompatible BIOS image") | |
table = patch_table(table, args.p) | |
atom.replace_command_table(t, table) | |
return fix_checksum(atom, args) | |
def main(): | |
parser = argparse.ArgumentParser(description="Simple ATOMBIOS table manipulation tool v1.1") | |
subparsers = parser.add_subparsers(title="commands") | |
# Fix PC BIOS checksum | |
fixchecksum = subparsers.add_parser("f", help="Fix BIOS image checksum") | |
fixchecksum.add_argument('infile', type=argparse.FileType("rb"), help="input rom file") | |
fixchecksum.add_argument('outfile', type=str, help="output rom file") | |
fixchecksum.set_defaults(func=fix_checksum) | |
# Extract ATOM command table | |
extractcmd = subparsers.add_parser("x", help="Extract ATOM command table") | |
extractcmd.add_argument('-t', metavar="tableid", required=True, type=int, help="table id to extract") | |
extractcmd.add_argument('infile', type=argparse.FileType("rb"), help="input rom file") | |
extractcmd.add_argument('outfile', metavar="table.bin", type=str, help="output binary table file") | |
extractcmd.set_defaults(func=extract_command_table) | |
# Extract ATOM data table | |
extractdata = subparsers.add_parser("e", help="Extract ATOM data table") | |
extractdata.add_argument('-t', metavar="tableid", required=True, type=int, help="table id to extract") | |
extractdata.add_argument('infile', type=argparse.FileType("rb"), help="input rom file") | |
extractdata.add_argument('outfile', type=str, help="output binary table file") | |
extractdata.set_defaults(func=extract_data_table) | |
# Replace ATOM command table | |
replacecmd = subparsers.add_parser("c", help="Replace ATOM command table") | |
replacecmd.add_argument('-t', metavar="tableid", required=True, type=int, help="table id to replace") | |
replacecmd.add_argument('-f', metavar="table.bin", required=True, type=argparse.FileType("rb"), help="input binary table file") | |
replacecmd.add_argument('infile', type=argparse.FileType("rb"), help="input rom file") | |
replacecmd.add_argument('outfile', type=str, help="output rom file") | |
replacecmd.set_defaults(func=replace_command_table) | |
# Replace ATOM data table | |
replacedata = subparsers.add_parser("d", help="Replace ATOM data table") | |
replacedata.add_argument('-t', metavar="tableid", required=True, type=int, help="table id to replace") | |
replacedata.add_argument('-f', metavar="table.bin", required=True, type=argparse.FileType("rb"), help="input binary table file") | |
replacedata.add_argument('infile', type=argparse.FileType("rb"), help="input rom file") | |
replacedata.add_argument('outfile', type=str, help="output rom file") | |
replacedata.set_defaults(func=replace_data_table) | |
# Activate cores | |
activate = subparsers.add_parser("a", help="Activate disabled cores") | |
activate.add_argument( | |
'-p', metavar="type", required=True, choices = [1,2,3,65535], type=int, | |
help="patch type (1 for 4-LOW, 2 for 4-HIGH or 65535 for all)" | |
) | |
activate.add_argument('infile', type=argparse.FileType("rb"), help="input rom file") | |
activate.add_argument('outfile', type=str, help="output rom file") | |
activate.set_defaults(func=activate_cores) | |
args = parser.parse_args() | |
try: | |
a = AtomBios(args.infile) | |
except ValueError as err: | |
print "BIOS load error:", err.args[0] | |
return -1 | |
try: | |
return args.func(a, args) | |
except IndexError as err: | |
print "Error:", err.args[0] | |
return -1 | |
except ValueError as err: | |
print "Error:", err.args[0] | |
return -1 | |
if __name__ == '__main__': | |
sys.exit(main()) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Simple ATOMBIOS table manipulation tool | |
DISCLAIMER | |
THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. | |
IN NO EVENT SHALL AUTHOR, OR ANY PERSON BE LIABLE FOR ANY LOSS, | |
EXPENSE OR DAMAGE, OF ANY TYPE OR NATURE ARISING OUT OF THE USE | |
OF, OR INABILITY TO USE THIS SOFTWARE OR PROGRAM, INCLUDING, | |
BUT NOT LIMITED TO, CLAIMS, SUITS OR CAUSES OF ACTION INVOLVING | |
ALLEGED INFRINGEMENT OF COPYRIGHTS, PATENTS, OR TRADE SECRETS. | |
This tool supports simple ATOMBIOS table manipulation like table read and same size table write. | |
Another included feature is possibility to unlock inactive cores for some chips. | |
Short help: | |
Simple ATOMBIOS table manipulation tool | |
optional arguments: | |
-h, --help show this help message and exit | |
commands: | |
{f,x,e,c,d,a} | |
f Fix BIOS image checksum | |
x Extract ATOM command table | |
e Extract ATOM data table | |
c Replace ATOM command table | |
d Replace ATOM data table | |
a Activate disabled cores | |
Usage: | |
Fix BIOS image checksum: | |
atomtool.py f [-h] infile outfile | |
arguments: | |
infile input rom file | |
outfile output rom file | |
Extract ATOM command table | |
atomtool.py x [-h] -t tableid infile table.bin | |
arguments: | |
-t tableid table id to extract | |
infile input rom file | |
table.bin output binary table file | |
Extract ATOM data table | |
atomtool.py e [-h] -t tableid infile table.bin | |
arguments: | |
-t tableid table id to extract | |
infile input rom file | |
table.bin output binary table file | |
Replace ATOM command table | |
atomtool.py c [-h] -t tableid -f table.bin infile outfile | |
arguments: | |
-t tableid table id to replace | |
-f table.bin input binary table file | |
infile input rom file | |
outfile output rom file | |
Replace ATOM data table | |
atomtool.py d [-h] -t tableid -f table.bin infile outfile | |
arguments: | |
-t tableid table id to replace | |
-f table.bin input binary table file | |
infile input rom file | |
outfile output rom file | |
NOTE: replacement is only possible to the table of the same size | |
Activate disabled cores | |
atomtool.py a [-h] -p type infile outfile | |
arguments: | |
-p type patch type (1 for 4-LOW, 2 for 4-HIGH, 3 for LOW+HIGH, or 65535 for all) | |
infile input rom file | |
outfile output rom file | |
Examples: | |
- extract PowerPlay table from file.rom to PowerPlay.bin: | |
atomtool.py e -t 15 file.rom PowerPlay.bin | |
- update PowerPlay table in file.rom from PowerPlay.bin and save rom as file_new.rom: | |
atomtool.py d -t 15 -f PowerPlay.bin file.rom file_new.rom | |
- fix checksum of PCBIOS image in file.rom and save rom as file_csok.rom: | |
atomtool.py f file.rom file_csok.rom | |
- try to activate cores in column #1 (4LOW) and save rom as file_4low.rom: | |
atomtool.py a -p 1 file.rom file_4low.rom | |
- try to activate all cores and save rom as file_all.rom (NOT RECOMMENDED!): | |
atomtool.py a -p 65535 file.rom file_all.rom | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@echo off | |
atomtool.py a -p 1 %1 %~n1_4low.rom | |
atomtool.py a -p 2 %1 %~n1_4high.rom | |
atomtool.py a -p 3 %1 %~n1_low+high.rom | |
atomtool.py a -p 65535 %1 %~n1_all.rom |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment