2 # b43 debugging library
4 # Copyright (C) 2008 Michael Buesch <mb@bu3sch.de>
6 # This program is free software: you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License version 3
8 # as published by the Free Software Foundation.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with this program. If not, see <http://www.gnu.org/licenses/>.
23 from tempfile import *
34 class B43Exception(Exception):
38 B43_MMIO_MACCTL = 0x120
39 B43_MMIO_PSMDEBUG = 0x154
41 B43_MACCTL_PSM_MACEN = 0x00000001
42 B43_MACCTL_PSM_RUN = 0x00000002
43 B43_MACCTL_PSM_JMP0 = 0x00000004
44 B43_MACCTL_PSM_DEBUG = 0x00002000
48 """Parse the contents of the PSM-debug register"""
49 def __init__(self, reg_content):
50 self.raw = reg_content
54 """Get the raw PSM-debug register value"""
58 """Get the microcode program counter"""
59 return self.raw & 0xFFF
63 def __init__(self, phy):
64 debugfs_path = self.__debugfs_find()
66 # Construct the debugfs b43 path to the device
67 b43_path = debugfs_path + "/b43/"
72 phys = os.listdir(b43_path)
74 print "Could not find any b43 device"
77 print "Found multiple b43 devices."
78 print "You must call this tool with a phyX parameter to specify a device"
83 # Open the debugfs files
85 self.f_mmio16read = file(b43_path + "/mmio16read", "r+")
86 self.f_mmio16write = file(b43_path + "/mmio16write", "w")
87 self.f_mmio32read = file(b43_path + "/mmio32read", "r+")
88 self.f_mmio32write = file(b43_path + "/mmio32write", "w")
89 self.f_shm16read = file(b43_path + "/shm16read", "r+")
90 self.f_shm16write = file(b43_path + "/shm16write", "w")
91 self.f_shm32read = file(b43_path + "/shm32read", "r+")
92 self.f_shm32write = file(b43_path + "/shm32write", "w")
94 print "Could not open debugfs file %s: %s" % (e.filename, e.strerror)
97 self.b43_path = b43_path
100 # Get the debugfs mountpoint.
101 def __debugfs_find(self):
102 mtab = file("/etc/mtab").read().splitlines()
103 regexp = re.compile(r"^[\w\-_]+\s+([\w/\-_]+)\s+debugfs")
106 m = regexp.match(line)
111 print "Could not find debugfs in /etc/mtab"
115 def read16(self, reg):
116 """Do a 16bit MMIO read"""
118 self.f_mmio16read.seek(0)
119 self.f_mmio16read.write("0x%X" % reg)
120 self.f_mmio16read.flush()
121 self.f_mmio16read.seek(0)
122 val = self.f_mmio16read.read()
124 print "Could not access debugfs file %s: %s" % (e.filename, e.strerror)
128 def read32(self, reg):
129 """Do a 32bit MMIO read"""
131 self.f_mmio32read.seek(0)
132 self.f_mmio32read.write("0x%X" % reg)
133 self.f_mmio32read.flush()
134 self.f_mmio32read.seek(0)
135 val = self.f_mmio32read.read()
137 print "Could not access debugfs file %s: %s" % (e.filename, e.strerror)
141 def maskSet16(self, reg, mask, set):
142 """Do a 16bit MMIO mask-and-set operation"""
146 self.f_mmio16write.seek(0)
147 self.f_mmio16write.write("0x%X 0x%X 0x%X" % (reg, mask, set))
148 self.f_mmio16write.flush()
150 print "Could not access debugfs file %s: %s" % (e.filename, e.strerror)
154 def write16(self, reg, value):
155 """Do a 16bit MMIO write"""
156 self.maskSet16(reg, 0, value)
159 def maskSet32(self, reg, mask, set):
160 """Do a 32bit MMIO mask-and-set operation"""
164 self.f_mmio32write.seek(0)
165 self.f_mmio32write.write("0x%X 0x%X 0x%X" % (reg, mask, set))
166 self.f_mmio32write.flush()
168 print "Could not access debugfs file %s: %s" % (e.filename, e.strerror)
172 def write32(self, reg, value):
173 """Do a 32bit MMIO write"""
174 self.maskSet32(reg, 0, value)
177 def shmRead16(self, routing, offset):
178 """Do a 16bit SHM read"""
180 self.f_shm16read.seek(0)
181 self.f_shm16read.write("0x%X 0x%X" % (routing, offset))
182 self.f_shm16read.flush()
183 self.f_shm16read.seek(0)
184 val = self.f_shm16read.read()
186 print "Could not access debugfs file %s: %s" % (e.filename, e.strerror)
190 def shmMaskSet16(self, routing, offset, mask, set):
191 """Do a 16bit SHM mask-and-set operation"""
195 self.f_shm16write.seek(0)
196 self.f_shm16write.write("0x%X 0x%X 0x%X 0x%X" % (routing, offset, mask, set))
197 self.f_shm16write.flush()
199 print "Could not access debugfs file %s: %s" % (e.filename, e.strerror)
203 def shmWrite16(self, routing, offset, value):
204 """Do a 16bit SHM write"""
205 self.shmMaskSet16(routing, offset, 0, value)
208 def shmRead32(self, routing, offset):
209 """Do a 32bit SHM read"""
211 self.f_shm32read.seek(0)
212 self.f_shm32read.write("0x%X 0x%X" % (routing, offset))
213 self.f_shm32read.flush()
214 self.f_shm32read.seek(0)
215 val = self.f_shm32read.read()
217 print "Could not access debugfs file %s: %s" % (e.filename, e.strerror)
221 def shmMaskSet32(self, routing, offset, mask, set):
222 """Do a 32bit SHM mask-and-set operation"""
226 self.f_shm32write.seek(0)
227 self.f_shm32write.write("0x%X 0x%X 0x%X 0x%X" % (routing, offset, mask, set))
228 self.f_shm32write.flush()
230 print "Could not access debugfs file %s: %s" % (e.filename, e.strerror)
234 def shmWrite32(self, routing, offset, value):
235 """Do a 32bit SHM write"""
236 self.shmMaskSet32(routing, offset, 0, value)
240 """Returns an array of 64 ints. One for each General Purpose register."""
242 for i in range(0, 64):
243 val = self.shmRead16(B43_SHM_REGS, i)
247 def getLinkRegs(self):
248 """Returns an array of 4 ints. One for each Link Register."""
250 for i in range(0, 4):
251 val = self.read16(0x4D0 + (i * 2))
255 def getOffsetRegs(self):
256 """Returns an array of 7 ints. One for each Offset Register."""
258 for i in range(0, 7):
259 val = self.read16(0x4C0 + (i * 2))
263 def shmSharedRead(self):
264 """Returns a string containing the SHM contents."""
266 for i in range(0, 4096, 4):
267 val = self.shmRead32(B43_SHM_SHARED, i)
268 ret += "%c%c%c%c" % (val & 0xFF,
274 def getPsmDebug(self):
275 """Read the PSM-debug register and return an instance of B43PsmDebug."""
276 val = self.read32(B43_MMIO_PSMDEBUG)
277 return B43PsmDebug(val)
279 def getPsmConditions(self):
280 """This returns the contents of the programmable-PSM-conditions register."""
281 return self.read16(0x4D8)
284 """Unconditionally stop the microcode PSM. """
285 self.maskSet32(B43_MMIO_MACCTL, ~B43_MACCTL_PSM_RUN, 0)
288 def ucodeStart(self):
289 """Unconditionally start the microcode PSM. This will restart the
290 microcode on the current PC. It will not jump to 0. Warning: This will
291 unconditionally restart the PSM and ignore any driver-state!"""
292 self.maskSet32(B43_MMIO_MACCTL, ~0, B43_MACCTL_PSM_RUN)
296 """Disassembler for b43 firmware."""
297 def __init__(self, binaryText, b43DasmOpts):
298 input = NamedTemporaryFile()
299 output = NamedTemporaryFile()
301 input.write(binaryText)
303 #FIXME check b43-dasm errors
304 os.system("b43-dasm %s %s %s" % (input.name, output.name, b43DasmOpts))
306 self.asmText = output.read()
309 """Returns the assembly code."""
313 """Assembler for b43 firmware."""
314 def __init__(self, assemblyText, b43AsmOpts):
315 input = NamedTemporaryFile()
316 output = NamedTemporaryFile()
318 input.write(assemblyText)
320 #FIXME check b43-asm errors
321 os.system("b43-asm %s %s %s" % (input.name, output.name, b43AsmOpts))
323 self.binaryText = output.read()
326 """Returns the binary code."""
327 return self.binaryText
330 """A textfile patcher that does not include any target context.
331 This can be used to patch b43 firmware files."""
334 def __init__(self, index, line):
339 def __init__(self, text, expected_md5sum):
340 sum = md5.md5(text).hexdigest()
341 if sum != expected_md5sum:
342 print "Patcher: The text does not match the expected MD5 sum"
343 print "Expected: " + expected_md5sum
344 print "Calculated: " + sum
346 text = text.splitlines()
350 self.lines.append(TextPatcher.TextLine(i, line))
352 # Add an after-last dummy. Needed for the add-before logic
353 lastDummy = TextPatcher.TextLine(i, "")
354 lastDummy.deleted = True
355 self.lines.append(lastDummy)
358 """This returns the current text."""
362 textLines.append(l.line)
363 return "\n".join(textLines)
365 def delLine(self, linenumber):
366 """Delete a line of text. The linenumber corresponds to the
367 original unmodified text."""
369 if l.index == linenumber:
372 print "Patcher deleteLine: Did not find the line!"
375 def addText(self, beforeLineNumber, text):
376 """Add a text before the specified linenumber. The linenumber
377 corresponds to the original unmodified text."""
378 text = text.splitlines()
381 if l.index == beforeLineNumber:
384 if index >= len(self.lines):
385 print "Patcher addText: Did not find the line!"
388 self.lines.insert(index, TextPatcher.TextLine(-1, l))