From: Michael Buesch Date: Thu, 19 Jun 2008 17:20:41 +0000 (+0200) Subject: Implement firmware state dumper X-Git-Tag: b43-fwcutter-013~34 X-Git-Url: https://jxself.org/git/?p=b43-tools.git;a=commitdiff_plain;h=1542e8b171362b8c85af4d3cac2e30946ee7f3bf Implement firmware state dumper Signed-off-by: Michael Buesch --- diff --git a/debug/b43-fwdump b/debug/b43-fwdump index d87e378..928634a 100755 --- a/debug/b43-fwdump +++ b/debug/b43-fwdump @@ -1,5 +1,5 @@ #!/usr/bin/env python -# +""" # b43 firmware state dumper # # Copyright (C) 2008 Michael Buesch @@ -15,26 +15,140 @@ # # You should have received a copy of the GNU General Public License # along with this program. If not, see . -# +""" +import getopt from libb43 import * +from sys import stdout +from tempfile import * -try: - phy = sys.argv[1] -except IndexError: - phy = None +def usage(): + print "b43 firmware state dumper" + print "" + print "Copyright (C) 2008 Michael Buesch " + print "Licensed under the GNU/GPL version 3" + print "" + print "Usage: b43-fwdump [OPTIONS]" + print "" + print "-h|--help Print this help text" + print "-p|--phy PHY The PHY to use. For example phy0" + print "-b|--binary BIN The firmware binary. This is required for" + print " an instruction dump." + print "-d|--dasmopt OPT Additional options to the disassembler." + return +def parseArgs(): + global phy + global binary + global dasmopt + + phy = None # Autodetect + binary = None # No instruction dump + dasmopt = "" + + try: + (opts, args) = getopt.getopt(sys.argv[1:], + "hp:b:d:", + [ "help", "phy=", "binary=", "dasmopt=" ]) + except getopt.GetoptError: + usage() + sys.exit(1) + + for (o, v) in opts: + if o in ("-h", "--help"): + usage() + sys.exit(0) + if o in ("-p", "--phy"): + phy = v + if o in ("-b", "--binary"): + binary = v + if o in ("-d", "--dasmopt"): + dasmopt = v + return + + +def dump_regs(prefix, regs): + if len(regs) >= 10: + template = "%s%02u: %04X " + else: + template = "%s%01u: %04X " + for i in range(0, len(regs)): + if i != 0 and i % 4 == 0: + stdout.write("\n") + stdout.write(template % (prefix, i, regs[i])) + stdout.write("\n") + return + +def disassembleText(text): + input = NamedTemporaryFile() + output = NamedTemporaryFile() + + input.write(text) + input.flush() + os.system("b43-dasm %s %s %s --paddr" % (input.name, dasmopt, output.name)) + + return output.read() + +def makeShortDump(dasm, pc): + dasm = dasm.splitlines() + i = 0 + for line in dasm: + if "/* %03X */" % pc in line: + break + i += 1 + if i >= len(dasm): + return "" + ret = "" + pos = max(i - 8, 0) + end = min(i + 8, len(dasm) - 1) + while pos != end: + ret += dasm[pos] + if "/* %03X */" % pc in dasm[pos]: + ret += "\t\t<<<<<<<<<<<" + ret += "\n" + pos += 1 + return ret + +def main(): + parseArgs() -try: b43 = B43(phy) - regs = b43.ucodeRegsRead() + # Fetch the hardware information + b43.ucodeStop() + gpr = b43.getGprs() + lr = b43.getLinkRegs() + off = b43.getOffsetRegs() shm = b43.shmSharedRead() dbg = b43.getPsmDebug() + psmcond = b43.getPsmConditions() + b43.ucodeStart() + + print "--- B43 microcode state dump ---" + print "PC: %03X PSM-COND: %04X" % (dbg.getPc(), psmcond) + print "Link registers:" + dump_regs("lr", lr) + print "Offset registers:" + dump_regs("off", off) + print "General purpose registers:" + dump_regs("r", gpr) - print "PC is at 0x%03X" % dbg.getPc() -#TODO + print "Code:" + if binary: + try: + bintext = file(binary, "r").read() + except IOError, e: + print "Could not read binary file %s: %s" % (binary, e.strerror) + sys.exit(1) + dasm = disassembleText(bintext) + print makeShortDump(dasm, dbg.getPc()) + else: + print "" + return + +try: + main() except B43Exception: sys.exit(1) diff --git a/debug/libb43.py b/debug/libb43.py index 4535cfb..f834bc7 100644 --- a/debug/libb43.py +++ b/debug/libb43.py @@ -1,4 +1,4 @@ -# +""" # b43 debugging library # # Copyright (C) 2008 Michael Buesch @@ -14,7 +14,7 @@ # # You should have received a copy of the GNU General Public License # along with this program. If not, see . -# +""" import sys import os @@ -33,17 +33,28 @@ class B43Exception(Exception): pass -B43_MMIO_PSMDEBUG = 0x154 +B43_MMIO_MACCTL = 0x120 +B43_MMIO_PSMDEBUG = 0x154 + +B43_MACCTL_PSM_MACEN = 0x00000001 +B43_MACCTL_PSM_RUN = 0x00000002 +B43_MACCTL_PSM_JMP0 = 0x00000004 +B43_MACCTL_PSM_DEBUG = 0x00002000 + class B43PsmDebug: """Parse the contents of the PSM-debug register""" def __init__(self, reg_content): - self.pc = reg_content & 0xFFF + self.raw = reg_content return + def getRaw(self): + """Get the raw PSM-debug register value""" + return self.raw + def getPc(self): """Get the microcode program counter""" - return self.pc + return self.raw & 0xFFF class B43: @@ -80,6 +91,8 @@ class B43: except IOError, e: print "Could not open debugfs file %s: %s" % (e.filename, e.strerror) raise B43Exception + + self.b43_path = b43_path return # Get the debugfs mountpoint. @@ -102,10 +115,11 @@ class B43: try: self.f_mmio16read.seek(0) self.f_mmio16read.write("0x%X" % reg) + self.f_mmio16read.flush() self.f_mmio16read.seek(0) val = self.f_mmio16read.read() except IOError, e: - print "Coult not access debugfs file %s: %s" % (e.filename, e.strerror) + print "Could not access debugfs file %s: %s" % (e.filename, e.strerror) raise B43Exception return int(val, 16) @@ -114,52 +128,73 @@ class B43: try: self.f_mmio32read.seek(0) self.f_mmio32read.write("0x%X" % reg) + self.f_mmio32read.flush() self.f_mmio32read.seek(0) val = self.f_mmio32read.read() except IOError, e: - print "Coult not access debugfs file %s: %s" % (e.filename, e.strerror) + print "Could not access debugfs file %s: %s" % (e.filename, e.strerror) raise B43Exception return int(val, 16) - def write16(self, reg, value): - """Do a 16bit MMIO write""" + def maskSet16(self, reg, mask, set): + """Do a 16bit MMIO mask-and-set operation""" try: + mask &= 0xFFFF + set &= 0xFFFF self.f_mmio16write.seek(0) - self.f_mmio16write.write("0x%X = 0x%X" % (reg, value)) + self.f_mmio16write.write("0x%X 0x%X 0x%X" % (reg, mask, set)) + self.f_mmio16write.flush() except IOError, e: - print "Coult not access debugfs file %s: %s" % (e.filename, e.strerror) + print "Could not access debugfs file %s: %s" % (e.filename, e.strerror) raise B43Exception return + + def write16(self, reg, value): + """Do a 16bit MMIO write""" + self.maskSet16(reg, 0, value) + return - def write32(self, reg, value): - """Do a 32bit MMIO write""" + def maskSet32(self, reg, mask, set): + """Do a 32bit MMIO mask-and-set operation""" try: + mask &= 0xFFFFFFFF + set &= 0xFFFFFFFF self.f_mmio32write.seek(0) - self.f_mmio32write.write("0x%X = 0x%X" % (reg, value)) + self.f_mmio32write.write("0x%X 0x%X 0x%X" % (reg, mask, set)) + self.f_mmio32write.flush() except IOError, e: - print "Coult not access debugfs file %s: %s" % (e.filename, e.strerror) + print "Could not access debugfs file %s: %s" % (e.filename, e.strerror) raise B43Exception return + def write32(self, reg, value): + """Do a 32bit MMIO write""" + self.maskSet32(reg, 0, value) + return + def shmRead16(self, routing, offset): """Do a 16bit SHM read""" try: self.f_shm16read.seek(0) self.f_shm16read.write("0x%X 0x%X" % (routing, offset)) + self.f_shm16read.flush() self.f_shm16read.seek(0) val = self.f_shm16read.read() except IOError, e: - print "Coult not access debugfs file %s: %s" % (e.filename, e.strerror) + print "Could not access debugfs file %s: %s" % (e.filename, e.strerror) raise B43Exception return int(val, 16) def shmMaskSet16(self, routing, offset, mask, set): """Do a 16bit SHM mask-and-set operation""" try: + mask &= 0xFFFF + set &= 0xFFFF self.f_shm16write.seek(0) self.f_shm16write.write("0x%X 0x%X 0x%X 0x%X" % (routing, offset, mask, set)) + self.f_shm16write.flush() except IOError, e: - print "Coult not access debugfs file %s: %s" % (e.filename, e.strerror) + print "Could not access debugfs file %s: %s" % (e.filename, e.strerror) raise B43Exception return @@ -173,20 +208,24 @@ class B43: try: self.f_shm32read.seek(0) self.f_shm32read.write("0x%X 0x%X" % (routing, offset)) + self.f_shm32read.flush() self.f_shm32read.seek(0) val = self.f_shm32read.read() except IOError, e: - print "Coult not access debugfs file %s: %s" % (e.filename, e.strerror) + print "Could not access debugfs file %s: %s" % (e.filename, e.strerror) raise B43Exception return int(val, 16) def shmMaskSet32(self, routing, offset, mask, set): """Do a 32bit SHM mask-and-set operation""" try: + mask &= 0xFFFFFFFF + set &= 0xFFFFFFFF self.f_shm32write.seek(0) self.f_shm32write.write("0x%X 0x%X 0x%X 0x%X" % (routing, offset, mask, set)) + self.f_shm32write.flush() except IOError, e: - print "Coult not access debugfs file %s: %s" % (e.filename, e.strerror) + print "Could not access debugfs file %s: %s" % (e.filename, e.strerror) raise B43Exception return @@ -195,26 +234,59 @@ class B43: self.shmMaskSet32(routing, offset, 0, value) return - def ucodeRegsRead(self): - """Returns an array of 64 ints. One for each ucode register.""" + def getGprs(self): + """Returns an array of 64 ints. One for each General Purpose register.""" ret = [] for i in range(0, 64): val = self.shmRead16(B43_SHM_REGS, i) ret.append(val) return ret - def shmSharedRead(self): - """Returns an array of ints containing the bytewise SHM contents.""" + def getLinkRegs(self): + """Returns an array of 4 ints. One for each Link Register.""" + ret = [] + for i in range(0, 4): + val = self.read16(0x4D0 + (i * 2)) + ret.append(val) + return ret + + def getOffsetRegs(self): + """Returns an array of 7 ints. One for each Offset Register.""" ret = [] + for i in range(0, 7): + val = self.read16(0x4C0 + (i * 2)) + ret.append(val) + return ret + + def shmSharedRead(self): + """Returns a string containing the SHM contents.""" + ret = "" for i in range(0, 4096, 4): val = self.shmRead32(B43_SHM_SHARED, i) - ret.append(val & 0xFF) - ret.append((val >> 8) & 0xFF) - ret.append((val >> 16) & 0xFF) - ret.append((val >> 24) & 0xFF) + ret += "%c%c%c%c" % (val & 0xFF, + (val >> 8) & 0xFF, + (val >> 16) & 0xFF, + (val >> 24) & 0xFF) return ret def getPsmDebug(self): """Read the PSM-debug register and return an instance of B43PsmDebug.""" val = self.read32(B43_MMIO_PSMDEBUG) return B43PsmDebug(val) + + def getPsmConditions(self): + """This returns the contents of the programmable-PSM-conditions register.""" + return self.read16(0x4D8) + + def ucodeStop(self): + """Unconditionally stop the microcode PSM. """ + self.maskSet32(B43_MMIO_MACCTL, ~B43_MACCTL_PSM_RUN, 0) + return + + def ucodeStart(self): + """Unconditionally start the microcode PSM. This will restart the + microcode on the current PC. It will not jump to 0. Warning: This will + unconditionally restart the PSM and ignore any driver-state!""" + self.maskSet32(B43_MMIO_MACCTL, ~0, B43_MACCTL_PSM_RUN) + return +