Implement firmware state dumper
authorMichael Buesch <mb@bu3sch.de>
Thu, 19 Jun 2008 17:20:41 +0000 (19:20 +0200)
committerMichael Buesch <mb@bu3sch.de>
Thu, 19 Jun 2008 17:20:41 +0000 (19:20 +0200)
Signed-off-by: Michael Buesch <mb@bu3sch.de>
debug/b43-fwdump
debug/libb43.py

index d87e378e2a18c787999afd1e3d1402a5c9144bf7..928634abd7c56a1a0163f81adc6a7f09e8b41413 100755 (executable)
@@ -1,5 +1,5 @@
 #!/usr/bin/env python
-#
+"""
 #  b43 firmware state dumper
 #
 #  Copyright (C) 2008 Michael Buesch <mb@bu3sch.de>
 #
 #  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
 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 <mb@bu3sch.de>"
+       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 "<Could not find PC in the binary>"
+       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 "<No binary supplied. See --binary option>"
+       return
 
+
+try:
+       main()
 except B43Exception:
        sys.exit(1)
index 4535cfb6b976f94ec87d381261a3c17443201a4a..f834bc76d9bbee0b28f7039f8048cd64da0a1687 100644 (file)
@@ -1,4 +1,4 @@
-#
+"""
 #  b43 debugging library
 #
 #  Copyright (C) 2008 Michael Buesch <mb@bu3sch.de>
@@ -14,7 +14,7 @@
 #
 #  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 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
+