Commit 98a28c2c authored by Michael Büsch's avatar Michael Büsch

Add b43 firmware assembly beautifier

This tool converts numeric identifiers to symbolic names.
Signed-off-by: Michael Büsch's avatarMichael Buesch <mb@bu3sch.de>
parent e41dd6db
#!/usr/bin/env python
"""
# b43 firmware assembly code beautifier
#
# Copyright (C) 2008 Michael Buesch <mb@bu3sch.de>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 3
# as published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
import getopt
import sys
from libb43 import *
def usage():
print "b43 firmware assembly code beautifier"
print ""
print "Copyright (C) 2008 Michael Buesch <mb@bu3sch.de>"
print "Licensed under the GNU/GPL version 3"
print ""
print "Usage: b43-beautifier [OPTIONS]"
print ""
print "-h|--help Print this help text"
print "-a|--asmfile [FILE] Assembly code source file"
print "-b|--binfile [FILE] Binary code source file"
print "-d|--defs [DIR] Directory containing the defs files"
print ""
print "The options -d AND (-a XOR -b) are essential"
def parseArgs():
global opt_asmfile
global opt_binfile
global opt_defsfiles
opt_asmfile = None
opt_binfile = None
opt_defsfiles = None
try:
(opts, args) = getopt.getopt(sys.argv[1:],
"ha:b:d:",
[ "help", "asmfile=", "binfile=", "defs=" ])
except getopt.GetoptError:
usage()
sys.exit(1)
for (o, v) in opts:
if o in ("-h", "--help"):
usage()
sys.exit(0)
if o in ("-a", "--asmfile"):
if opt_binfile:
print "Must not set both of --asmfile and --binfile"
sys.exit(1)
opt_asmfile = v
if o in ("-b", "--binfile"):
if opt_asmfile:
print "Must not set both of --asmfile and --binfile"
sys.exit(1)
opt_binfile = v
if o in ("-d", "--defs"):
opt_defsfiles = v
if not opt_asmfile and not opt_binfile:
print "Must set either --asmfile or --binfile"
sys.exit(1)
if not opt_defsfiles:
print "Must set --defs"
sys.exit(1)
def main():
parseArgs()
# Get the assembly
if opt_asmfile:
try:
asm = file(opt_asmfile).read()
except IOError, e:
print "Could not read asmfile %s: %s" % (e.filename, e.strerror)
sys.exit(1)
else:
try:
bin = file(opt_binfile).read()
except IOError, e:
print "Could not read binfile %s: %s" % (e.filename, e.strerror)
sys.exit(1)
asm = Disassembler(bin, "").getAsm()
b = B43Beautifier(asm, opt_defsfiles)
sys.stdout.write(b.getAsm())
try:
main()
except B43Exception:
sys.exit(1)
......@@ -12,5 +12,5 @@ if len(sys.argv) == 1:
setup(
name="B43-debug-tools",
py_modules=["libb43"],
scripts=["b43-fwdump"]
scripts=["b43-fwdump", "b43-beautifier"]
)
......@@ -60,6 +60,8 @@ class B43PsmDebug:
class B43:
"""Hardware access layer. This accesses the hardware through the debugfs interface."""
def __init__(self, phy):
debugfs_path = self.__debugfs_find()
......@@ -388,3 +390,271 @@ class TextPatcher:
self.lines.insert(index, TextPatcher.TextLine(-1, l))
index += 1
class B43SymbolicSpr:
"""This class converts numeric SPR names into symbolic SPR names."""
def __init__(self, header_file):
"""The passed header_file parameter is a file path to the
assembly file containing the symbolic SPR definitions."""
try:
defs = file(header_file).readlines()
except IOError, e:
print "B43SymbolicSpr: Could not read %s: %s" % (e.filename, e.strerror)
B43Exception
# Parse the definitions
self.spr_names = { }
r = re.compile(r"#define\s+(\w+)\s+(spr[a-fA-F0-9]+)")
for line in defs:
m = r.match(line)
if not m:
continue # unknown line
name = m.group(1)
offset = m.group(2)
self.spr_names[offset.lower()] = name
def get(self, spr):
"""Get the symbolic name for an SPR. The spr parameter
must be a string like "sprXXX", where XXX is a hex number."""
try:
spr = self.spr_names[spr.lower()]
except KeyError:
pass # Symbol not found. Return numeric name.
return spr
def getRaw(self, spr_hexnumber):
"""Get the symbolic name for an SPR. The spr_hexnumber
parameter is the hexadecimal number for the SPR."""
return self.get("spr%03X" % spr_hexnumber)
class B43SymbolicShm:
"""This class converts numeric SHM offsets into symbolic SHM names."""
def __init__(self, header_file):
"""The passed header_file parameter is a file path to the
assembly file containing the symbolic SHM definitions."""
try:
defs = file(header_file).readlines()
except IOError, e:
print "B43SymbolicShm: Could not read %s: %s" % (e.filename, e.strerror)
raise B43Exception
# Parse the definitions
self.shm_names = { }
in_abi_section = False
r = re.compile(r"#define\s+(\w+)\s+SHM\((\w+)\).*")
for line in defs:
if line.startswith("/* BEGIN ABI"):
in_abi_section = True
if line.startswith("/* END ABI"):
in_abi_section = False
if not in_abi_section:
continue # Only parse ABI definitions
m = r.match(line)
if not m:
continue # unknown line
name = m.group(1)
offset = int(m.group(2), 16)
offset /= 2
self.shm_names[offset] = name
def get(self, shm_wordoffset):
"""Get the symbolic name for an SHM offset."""
try:
sym = self.shm_names[shm_wordoffset]
except KeyError:
# Symbol not found. Return numeric name.
sym = "0x%03X" % shm_wordoffset
return sym
class B43SymbolicCondition:
"""This class converts numeric External Conditions into symbolic names."""
def __init__(self, header_file):
"""The passed header_file parameter is a file path to the
assembly file containing the symbolic condition definitions."""
try:
defs = file(header_file).readlines()
except IOError, e:
print "B43SymbolicCondition: Could not read %s: %s" % (e.filename, e.strerror)
raise B43Exception
# Parse the definitions
self.cond_names = { }
r = re.compile(r"#define\s+(\w+)\s+EXTCOND\(\s*(\w+),\s*(\d+)\s*\).*")
for line in defs:
m = r.match(line)
if not m:
continue # unknown line
name = m.group(1)
register = m.group(2)
bit = int(m.group(3))
if register == "CONDREG_RX":
register = 0
elif register == "CONDREG_TX":
register = 2
elif register == "CONDREG_PHY":
register = 3
elif register == "CONDREG_4":
register = 4
elif register == "CONDREG_PSM":
continue # No lookup table for this one
elif register == "CONDREG_RCM":
register = 6
elif register == "CONDREG_7":
register = 7
else:
continue # unknown register
cond_number = bit | (register << 4)
self.cond_names[cond_number] = name
def get(self, cond_number):
"""Get the symbolic name for an External Condition."""
register = (cond_number >> 4) & 0x7
bit = cond_number & 0xF
eoi = ((cond_number & 0x80) != 0)
cond_number &= ~0x80
if register == 5: # PSM register
return "COND_PSM(%d)" % bit
try:
sym = self.cond_names[cond_number]
except KeyError:
# Symbol not found. Return numeric name.
sym = "0x%02X" % cond_number
if eoi:
sym = "EOI(%s)" % sym
return sym
class B43AsmLine:
def __init__(self, text):
self.text = text
def getLine(self):
return self.text
def isInstruction(self):
return False
class B43AsmInstruction(B43AsmLine):
def __init__(self, opcode):
self.opcode = opcode
self.operands = []
def getOpcode(self):
return self.opcode
def addOperand(self, operand):
self.operands.append(operand)
def getOperands(self):
return self.operands
def getLine(self):
ret = "\t" + self.opcode
if self.operands:
ret += "\t"
for op in self.operands:
ret += op + ", "
if self.operands:
ret = ret[:-2]
return ret
def isInstruction(self):
return True
class B43AsmParser:
"""A simple B43 assembly code parser."""
def __init__(self, asm_code):
self.__parse_code(asm_code)
def __parse_code(self, asm_code):
self.codelines = []
label = re.compile(r"^\s*\w+:\s*$")
insn_0 = re.compile(r"^\s*([@\.\w]+)\s*$")
insn_2 = re.compile(r"^\s*([@\.\w]+)\s+([@\[\],\w]+),\s*([@\[\],\w]+)\s*$")
insn_3 = re.compile(r"^\s*([@\.\w]+)\s+([@\[\],\w]+),\s*([@\[\],\w]+),\s*([@\[\],\w]+)\s*$")
insn_5 = re.compile(r"^\s*([@\.\w]+)\s+([@\[\],\w]+),\s*([@\[\],\w]+),\s*([@\[\],\w]+),\s*([@\[\],\w]+),\s*([@\[\],\w]+)\s*$")
for line in asm_code.splitlines():
m = label.match(line)
if m: # Label:
l = B43AsmLine(line)
self.codelines.append(l)
continue
m = insn_0.match(line)
if m: # No operands
insn = B43AsmInstruction(m.group(1))
self.codelines.append(insn)
continue
m = insn_2.match(line)
if m: # Two operands
insn = B43AsmInstruction(m.group(1))
insn.addOperand(m.group(2))
insn.addOperand(m.group(3))
self.codelines.append(insn)
continue
m = insn_3.match(line)
if m: # Three operands
insn = B43AsmInstruction(m.group(1))
insn.addOperand(m.group(2))
insn.addOperand(m.group(3))
insn.addOperand(m.group(4))
self.codelines.append(insn)
continue
m = insn_5.match(line)
if m: # Three operands
insn = B43AsmInstruction(m.group(1))
insn.addOperand(m.group(2))
insn.addOperand(m.group(3))
insn.addOperand(m.group(4))
insn.addOperand(m.group(5))
insn.addOperand(m.group(6))
self.codelines.append(insn)
continue
# Unknown line
l = B43AsmLine(line)
self.codelines.append(l)
class B43Beautifier(B43AsmParser):
"""A B43 assembly code beautifier."""
def __init__(self, asm_code, headers_dir):
"""asm_code is the assembly code. headers_dir is a full
path to the directory containing the symbolic SPR,SHM,etc... definitions"""
B43AsmParser.__init__(self, asm_code)
self.symSpr = B43SymbolicSpr(headers_dir + "/spr.inc")
self.symShm = B43SymbolicShm(headers_dir + "/shm.inc")
self.symCond = B43SymbolicCondition(headers_dir + "/cond.inc")
self.preamble = "#include <%s/spr.inc>\n" % headers_dir
self.preamble += "#include <%s/shm.inc>\n" % headers_dir
self.preamble += "#include <%s/cond.inc>\n" % headers_dir
self.preamble += "\n"
self.__process_code()
def __process_code(self):
spr_re = re.compile(r"^spr\w\w\w$")
shm_re = re.compile(r"^\[(0x\w+)\]$")
code = self.codelines
for line in code:
if not line.isInstruction():
continue
opcode = line.getOpcode()
operands = line.getOperands()
if opcode == "jext" or opcode == "jnext":
operands[0] = self.symCond.get(int(operands[0], 16))
continue
for i in range(0, len(operands)):
o = operands[i]
m = spr_re.match(o)
if m:
operands[i] = self.symSpr.get(o)
continue
m = shm_re.match(o)
if m:
offset = int(m.group(1), 16)
operands[i] = "[" + self.symShm.get(offset) + "]"
continue
def getAsm(self):
"""Returns the beautified asm code."""
ret = self.preamble
for line in self.codelines:
ret += line.getLine() + "\n"
return ret
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment