From 9575819f43b568b2bd13ede0ba9afd31db767ec0 Mon Sep 17 00:00:00 2001 From: travisutk Date: Sun, 7 Oct 2012 13:59:30 +0000 Subject: [PATCH 1/1] Added godfet.maxusbdfu for USD Device Firmware Update emulation with the Facedancer. git-svn-id: https://svn.code.sf.net/p/goodfet/code/trunk@1289 12e2690d-a6be-4b82-a7b7-67c4a43b65c8 --- client/goodfet.maxusbdfu | 325 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 325 insertions(+) create mode 100755 client/goodfet.maxusbdfu diff --git a/client/goodfet.maxusbdfu b/client/goodfet.maxusbdfu new file mode 100755 index 0000000..04f4001 --- /dev/null +++ b/client/goodfet.maxusbdfu @@ -0,0 +1,325 @@ +#!/usr/bin/env python + +#DFU USB Device Emulator +#by Travis Goodspeed + +import sys; +import binascii; +import array; +import time; + +from GoodFETMAXUSB import *; + +class GoodFETMAXUSBDFU(GoodFETMAXUSBDevice): + usbverbose=False; + """This emulates the DFU USB to Serial chips.""" + def dfuinit(self,vid=0xFFFF,pid=0x0004): + """Initialize a USB DFU device.""" + self.usb_disconnect(); + time.sleep(1); + self.usb_connect(); + self.dfurun(vid,pid); + def dfurun(self,vid,pid): + """Main loop of the USB DFU emulator.""" + print "Starting a DFU device as %04X:%04X" % (vid,pid); + sys.stdout.flush(); + #Set the VID and PID. + self.DD[8]=vid&0xFF; + self.DD[9]=(vid>>8)&0xFF; + self.DD[10]=pid&0xFF; + self.DD[11]=(pid>>8)&0xFF; + + #Run the service loop. + while 1: + self.service_irqs(); + def do_SETUP(self): + """Handle USB Enumeration""" + #Grab the SETUP packet from the buffer. + SUD=self.readbytes(rSUDFIFO,8); + + #Parse the SETUP packet + #print "Handling a setup packet of %s" % self.setup2str(SUD); + setuptype=(ord(SUD[bmRequestType])&0x60); + if setuptype==0x00: + self.std_request(SUD); + elif setuptype==0x20: + self.class_request(SUD); + elif setuptype==0x40: + self.vendor_request(SUD); + else: + print "Unknown request type 0x%02x." % ord(SUD[bmRequestType]) + self.STALL_EP0(SUD); + def printblock(self,block,data): + """Prints a block, perhaps inserting it into the dump file.""" + s=""; + for foo in data: + s=s+("%02x "%ord(foo)); + print "BLOCK %04x : %s" % (block,s); + sys.stdout.flush(); #Needed for the tee command. + return; + def handle_dfu_download(self,SUD): + """Sometimes this comes from a Class request, sometimes a Vendor.""" + #Compute the total length, though we'll be accepting 64-byte chunks. + l=( + ord(SUD[wLengthL])+ + (ord(SUD[wLengthH])<<8) + ); + block=ord(SUD[wValueL])+ (ord(SUD[wValueH])<<8); + b=""; + while len(b)0): + self.SETBIT(rUSBIEN,bmSUSPIE); + self.rregAS(rFNADDR); + def get_status(self,SUD): + """Get the USB Setup Status.""" + testbyte=ord(SUD[bmRequestType]) + + #Toward Device + if testbyte==0x80: + self.wreg(rEP0FIFO,0x03); #Enable RWU and self-powered + self.wreg(rEP0FIFO,0x00); #Second byte is always zero. + self.wregAS(rEP0BC,2); #Load byte count, arm transfer, and ack CTL. + #Toward Interface + elif testbyte==0x81: + self.wreg(rEP0FIFO,0x00); + self.wreg(rEP0FIFO,0x00); #Second byte is always zero. + self.wregAS(rEP0BC,2); + #Toward Endpoint + elif testbyte==0x82: + if(ord(SUD[wIndexL])==0x83): + self.wreg(rEP0FIFO,0x01); #Stall EP3 + self.wreg(rEP0FIFO,0x00); #Second byte is always zero. + self.wregAS(rEP0BC,2); + else: + self.STALL_EP0(SUD); + else: + self.STALL_EP0(SUD); + def service_irqs(self): + """Handle USB interrupt events.""" + + epirq=self.rreg(rEPIRQ); + usbirq=self.rreg(rUSBIRQ); + + #Are we being asked for setup data? + if(epirq&bmSUDAVIRQ): #Setup Data Requested + self.wreg(rEPIRQ,bmSUDAVIRQ); #Clear the bit + self.do_SETUP(); + elif(epirq&bmIN3BAVIRQ): #EN3-IN packet + #print "IN3 event."; + #self.do_IN3(); + self.wreg(rEPIRQ,bmIN3BAVIRQ); #Clear the bit + elif(epirq&bmOUT1DAVIRQ): #OUT1-OUT packet + print "OUT1 event."; + self.do_OUT1(); + self.wregAS(rEPIRQ,bmOUT1DAVIRQ); #Clear the bit *AFTER* servicing. + #else: + # self.do_IN3(); + + typestring="GoodFET emulates DFU properly, if you can read this!\n"; + typepos=0; + + def typeletter(self,key): + """Type a letter on IN3. Zero for keyup.""" + if type(key)==str: key=ord(key); + + self.wreg(rEP3INFIFO,0x01); #Modem Status + self.wreg(rEP3INFIFO,0x00); #Line Status + self.wreg(rEP3INFIFO,key); + self.wregAS(rEP3INBC,3); + def do_IN3(self): + """Handle IN3 input event.""" + #Don't bother clearing interrupt flag, that's done by sending the reply. + + def do_OUT1(self): + """Handle an OUT1 output event.""" + print """ +Got an output event, but it's not part of the DFU standard so this +client can't know what to do with it. Usually, this needs some sort +of acknowledgment to tell the host that you are switching into. +"""; + + l=self.rreg(rEP1OUTBC); + frame=self.readbytesAS(rEP1OUTFIFO,l); + print "DFU OUT1: %s" % frame[1:len(frame)]; + + + +if(len(sys.argv)<3): + print "Usage: %s VID PID" % sys.argv[0]; + print ""; + print """Example VID/PID pairs: +\tFFFF 0004 -- Ubertooth ( Tested ) +\t0483 DF11 -- STM32 (Untested) +\t03EB 2F.. -- Atmel DFU (Untested) +""" + sys.exit(); + + +#Initialize FET and set baud rate +client=GoodFETMAXUSBDFU(); +client.serInit() + +vid=int(sys.argv[1],16); +pid=int(sys.argv[2],16); + +client.MAXUSBsetup(); + +print """ +The DFU emulator is now running. Any firmware which is downloaded to +the virtual device will be locked to this console, beginning with the +block device.""" + +client.dfuinit(vid,pid); + -- 2.20.1