2 # GoodFET ARM Debugging Interface v5 (ADIv5) Client Library.
3 # the ideal interface to pwning ARM Cortex
5 # Contributions and bug reports welcome.
9 import sys, binascii, struct, time
10 import atlasutils.smartprint as asp
11 from GoodFET import GoodFET
12 from intelhex import IntelHex
28 # ARM7TDMI JTAG commands
36 # Really ARM specific stuff
43 #4-bit ARM JTAG INSTRUCTIONS - STANDARD
52 #4-bit ARM JTAG INSTRUCTIONS - IMPLEMENTATION-DEFINED
74 0: ("UNKNOWN, MESSED UP PROCESSOR MODE","fsck", "This should Never happen. MCU is in funky state!"),
75 PM_usr: ("User Processor Mode", "usr", "Normal program execution mode"),
76 PM_fiq: ("FIQ Processor Mode", "fiq", "Supports a high-speed data transfer or channel process"),
77 PM_irq: ("IRQ Processor Mode", "irq", "Used for general-purpose interrupt handling"),
78 PM_svc: ("Supervisor Processor Mode", "svc", "A protected mode for the operating system"),
79 PM_abt: ("Abort Processor Mode", "abt", "Implements virtual memory and/or memory protection"),
80 PM_und: ("Undefined Processor Mode", "und", "Supports software emulation of hardware coprocessor"),
81 PM_sys: ("System Processor Mode", "sys", "Runs privileged operating system tasks (ARMv4 and above)"),
85 None, None, None, None, None, "Thumb", "nFIQ_int", "nIRQ_int",
86 "nImprDataAbort_int", "BIGendian", None, None, None, None, None, None,
87 "GE_0", "GE_1", "GE_2", "GE_3", None, None, None, None,
88 "Jazelle", None, None, "Q (DSP-overflow)", "oVerflow", "Carry", "Zero", "Neg",
91 ARM_INSTR_NOP = 0xe1a00000L
92 ARM_INSTR_BX_R0 = 0xe12fff10L
93 ARM_INSTR_STR_Rx_r14 = 0xe58f0000L # from atmel docs
94 ARM_READ_REG = ARM_INSTR_STR_Rx_r14
95 ARM_INSTR_LDR_Rx_r14 = 0xe59f0000L # from atmel docs
96 ARM_WRITE_REG = ARM_INSTR_LDR_Rx_r14
97 ARM_INSTR_LDR_R1_r0_4 = 0xe4901004L
98 ARM_READ_MEM = ARM_INSTR_LDR_R1_r0_4
99 ARM_INSTR_STR_R1_r0_4 = 0xe4801004L
100 ARM_WRITE_MEM = ARM_INSTR_STR_R1_r0_4
101 ARM_INSTR_MRS_R0_CPSR = 0xe10f0000L
102 ARM_INSTR_MSR_cpsr_cxsf_R0 =0xe12ff000L
103 ARM_INSTR_STMIA_R14_r0_rx = 0xE88e0000L # add up to 65k to indicate which registers...
104 ARM_INSTR_LDMIA_R14_r0_rx = 0xE89e0000L # add up to 65k to indicate which registers...
105 ARM_STORE_MULTIPLE = ARM_INSTR_STMIA_R14_r0_rx
106 ARM_INSTR_SKANKREGS = 0xE88F7fffL
107 ARM_INSTR_CLOBBEREGS = 0xE89F7fffL
109 ARM_INSTR_B_IMM = 0xea000000L
110 ARM_INSTR_B_PC = 0xea000000L
111 ARM_INSTR_BX_PC = 0xe1200010L # need to set r0 to the desired address
112 THUMB_INSTR_LDR_R0_r0 = 0x68006800L
113 THUMB_WRITE_REG = THUMB_INSTR_LDR_R0_r0
114 THUMB_INSTR_STR_R0_r0 = 0x60006000L
115 THUMB_READ_REG = THUMB_INSTR_STR_R0_r0
116 THUMB_INSTR_MOV_R0_PC = 0x46b846b8L
117 THUMB_INSTR_MOV_PC_R0 = 0x46474647L
118 THUMB_INSTR_BX_PC = 0x47784778L
119 THUMB_INSTR_NOP = 0x1c001c00L
120 THUMB_INSTR_B_IMM = 0xe000e000L
124 LDM_BITMASKS = [(1<<x)-1 for x in xrange(16)]
127 CSYSPWRUPACK_BIT = 31
129 CSYSPWRUPREQ_BIT = 30
131 CDBGPWRUPACK_BIT = 29
133 CDBGPWRUPREQ_BIT = 28
160 print >>sys.stderr,(strng)
161 def PSRdecode(psrval):
162 output = [ "(%s mode)"%proc_modes[psrval&0x1f][1] ]
163 for x in xrange(5,32):
165 output.append(PSR_bits[x])
166 return " ".join(output)
168 fmt = ["B", "B", "<H", "<L", "<L", "<Q", "<Q", "<Q", "<Q"]
170 s = struct.pack(fmt[byts], val)
171 return [ord(b) for b in s ][:byts]
173 class GoodFETADIv5(GoodFET):
174 """A GoodFET variant for use with ARM7TDMI microprocessor."""
176 GoodFET.__init__(self)
177 self.storedPC = 0xffffffff
178 self.current_dbgstate = 0xffffffff
179 self.flags = 0xffffffff
180 self.nothing = 0xffffffff
181 self.ir_status = None
182 self.ap_selected = None
190 """Move the FET into the JTAG ARM application."""
191 #print "Initializing ARM."
192 self.writecmd(0x14,SETUP,0,self.data)
195 return self.ADIgetPC()
197 def flash(self,file):
198 """Flash an intel hex file to code memory."""
199 print "Flash not implemented.";
201 def dump(self,file,start=0,stop=0xffff):
202 """Dump an intel hex file from code memory."""
203 print "Dump not implemented.";
206 """Get an ARM's ID."""
207 raise Exception("Not Implemented. Abstract base class method called.")
208 def ADIidentstr(self):
209 ident=self.ADIident()
211 partno = (ident >> 12) & 0xffff
212 mfgid = (ident >> 1) & 0x7ff
213 return "Chip IDCODE: 0x%x\n\tver: %x\n\tpartno: %x\n\tmfgid: %x\n" % (ident, ver, partno, mfgid);
215 def ADIget_register(self, reg):
216 """Get an ARM's Register"""
217 self.writecmd(0x14,GET_REGISTER,1,[reg&0xf])
218 retval = struct.unpack("<L", "".join(self.data[0:4]))[0]
220 def ADIset_register(self, reg, val):
221 """Get an ARM's Register"""
222 self.writecmd(0x14,SET_REGISTER,8,[val&0xff, (val>>8)&0xff, (val>>16)&0xff, val>>24, reg,0,0,0])
223 retval = struct.unpack("<L", "".join(self.data[0:4]))[0]
225 def ADIget_registers(self):
226 """Get ARM Registers"""
227 regs = [ self.ADIget_register(x) for x in range(15) ]
228 regs.append(self.ADIgetPC()) # make sure we snag the "static" version of PC
230 def ADIset_registers(self, regs, mask):
231 """Set ARM Registers"""
234 self.ADIset_register(x,regs.pop(0))
235 if (1<<15) & mask: # make sure we set the "static" version of PC or changes will be lost
236 self.ADIsetPC(regs.pop(0))
238 def ADIrestart(self):
239 raise Exception("Not Implemented. Abstract base class method called.")
241 ####### Common DP features #######
242 def ADIgetAPACC(self, addr, flags): # candidate for firmware. not sure the intelligence wants to be there, but performance may want it.
243 raise Exception("Not Implemented. Abstract base class method called.")
244 def ADIsetAPACC(self, addr, val):
245 raise Exception("Not Implemented. Abstract base class method called.")
246 def ADIgetDPACC(self, addr, flags): # candidate for firmware. not sure the intelligence wants to be there, but performance may want it.
247 raise Exception("Not Implemented. Abstract base class method called.")
248 def ADIsetDPACC(self, addr, val):
249 raise Exception("Not Implemented. Abstract base class method called.")
250 def ADIsetABORT(self):
251 """ ONLY use if the debugger has received WAIT responses over an extended period"""
252 raise Exception("Not Implemented. Abstract base class method called.")
254 def ADIsetSELECT(self, num):
255 return self.ADIsetDPACC(0x8, num)
256 def ADIgetSELECT(self):
257 return self.ADIgetDPACC(0x8)
258 def ADIgetSELECTrepr(self):
259 raw = self.ADIgetSELECT()
261 apbanksel = (raw>>4) & 0xf
263 return "SWDP_CTRLSEL = %d\nAPBANKSEL = %d\nAPSEL = %d\n"
265 def ADIgetWCR(self): # SWDP only
266 raise Exception("IMPLEMENT ME: ADIgetWCR")
268 def ADIgetRESEND(self): # SWDP only
269 raise Exception("IMPLEMENT ME: ADIgetRESEND")
271 class GoodFETADIjtag(GoodFETADIv5):
272 """A GoodFET variant for use with ARM7TDMI microprocessor."""
273 def ADIshift_IR(self, IR, noretidle=0):
274 if (self.ir_status != IR):
275 self.writecmd(0x14,IR_SHIFT,2, [IR, LSB|noretidle])
278 def ADIshift_DR(self, bignum, bits, flags=0):
279 data = [bits&0xff, flags&0xff,0,0]
280 data.extend(chop(data, bits/4))
281 self.writecmd(0x14,DR_SHIFT, len(data), data)
284 """Get an ARM's ID."""
285 self.ADIshift_IR(IR_IDCODE,0)
286 self.ADIshift_DR(0,32,LSB)
287 retval = struct.unpack("<L", "".join(self.data[0:4]))[0]
290 def ADIdebuginstr(self,instr,bkpt):
291 """if type (instr) == int or type(instr) == long:
292 instr = struct.pack("<L", instr)
293 instr = [int("0x%x"%ord(x),16) for x in instr]
295 self.writecmd(0x14,DEBUG_INSTR,len(instr),instr)
296 return (self.data)"""
298 def ADI_nop(self, bkpt=0):
299 """if self.status() & DBG_TBIT:
300 return self.ADIdebuginstr(THUMB_INSTR_NOP, bkpt)
301 return self.ADIdebuginstr(ARM_INSTR_NOP, bkpt)"""
304 def ADIrestart(self):
305 self.ADIshift_IR(IR_RESTART)
307 ####### Common DP features #######
308 def ADIgetAPACC(self, addr): # candidate for firmware. not sure the intelligence wants to be there, but performance may want it.
309 self.ADIshift_IR(IR_APACC)
310 data = 1 | (addr>>1) # addr[3:2] goes in bits [2:1]. this *must* be a multiple of 4.
311 return self.ADIshift_DR(data, 35, LSB)
312 def ADIsetAPACC(self, addr, val):
315 addr == 4*n (ie. multiple of four, returns the word at that register)
317 self.ADIshift_IR(IR_APACC)
318 data = (val<<3) | (addr>>1) # addr[3:2] goes in bits [2:1]. this *must* be a multiple of 4.
319 self.ADIshift_DR(data, 35, LSB)
320 def ADIgetDPACC(self, addr, flags): # candidate for firmware. not sure the intelligence wants to be there, but performance may want it.
321 self.ADIshift_IR(IR_DPACC)
322 data = 1 | (addr>>1) # addr[3:2] goes in bits [2:1]. this *must* be a multiple of 4.
323 return self.ADIshift_DR(data, 35, LSB)
324 def ADIsetDPACC(self, addr, val):
327 addr == 4*n (ie. multiple of four, returns the word at that register)
329 self.ADIshift_IR(IR_DPACC)
330 data = (val<<3) | (addr>>1) # addr[3:2] goes in bits [2:1]. this *must* be a multiple of 4.
331 self.ADIshift_DR(data, 35, LSB)
333 def ADIsetABORT(self):
334 """ ONLY use if the debugger has received WAIT responses over an extended period"""
335 self.ADIshift_IR(self, IR_ABORT)
336 self.ADIshift_DR(self, 1, 35)
338 def ADIsetSELECT(self, apnum, apbank, flags="ignored for jtag"):
339 if (apnum != self.ap_selected or apbank != self.ap_bank):
340 select = (apnum<<24) | (apbank<<4)
341 self.ADIsetDPACC(0x8, select)
342 self.ap_selected = apnum
343 self.ap_bank = apbank
344 def ADIgetSELECT(self, noncached=False):
346 return self.ADIgetDPACC(0x8)
347 return self.ap_selected
351 class ADI_AccessPort: # define common AP calls
352 def __init__(self, DP, apnum):
353 self.dp = DP # link to parent. all calls should use this to access the underlying debug port.
354 self.apnum = apnum # which AP am i to this DP?
356 def getRegister(self, bank, off):
357 self.dp.ADIsetSELECT(self.apnum, bank)
358 return self.dp.ADIgetAPACC(off)
360 def getRegisterByAddr(self, addr):
362 self.dp.ADIsetSELECT(self.apnum, bank)
363 return self.dp.ADIgetAPACC(addr&0xf)
365 def getIdentRegister(self):
366 ident = self.getRegisterByAddr(0xfc)
369 def getIdentRegisterrepr(self):
370 raw = self.getIdentRegister()
372 jep_cont = (raw>>24) & 0xf
373 jep_ident = (raw>>17) & 0x7f
374 ap_class = (raw>>16) & 1
375 ap_ident = raw & 0xff
376 return "AP Revision: 0x%x\nJEP-106 Continuation Code: 0x%x\nJEP-106 Identity Code: 0x%x\nAP Class: 0x%x\nAP Identification: %x (%s)\n"%(ap_rev,jep_cont,jep_ident,ap_class,ap_ident,AP_IDENT_TYPES[ap_ident&0xf])
379 class ADI_MEM_AP(ADI_AccessPort):
380 def __init__(self, DP, apnum):
381 ADI_AccessPort.__init__(self, DP, apnum)
382 self.cfg = self.getCFG() # necessary to cache endianness information
383 # FIXME: how do i determine if this adi supports multibyte access or just word? or packed transfers?
384 self.setMemAccessSize(4)
386 def setMemAccessSize(self, bytecount):
389 csw |= (bytecount>>1)
394 def setCSW(self, csw):
399 def setTAR(self, csw):
404 def setDRW(self, csw):
409 def setBD0(self, csw):
414 def setCFG(self, csw):
419 def setBASE(self, csw):
424 def setIDR(self, csw):