Index: embios/trunk/tools/embios.py |
— | — | @@ -1,7 +1,7 @@ |
2 | 2 | #!/usr/bin/env python
|
3 | 3 | #
|
4 | 4 | #
|
5 | | -# Copyright 2010 TheSeven, benedikt93
|
| 5 | +# Copyright 2010 TheSeven, benedikt93, Farthen
|
6 | 6 | #
|
7 | 7 | #
|
8 | 8 | # This file is part of emBIOS.
|
— | — | @@ -21,378 +21,595 @@ |
22 | 22 | #
|
23 | 23 | #
|
24 | 24 |
|
25 | | -# note: handles commands 1 to 20
|
| 25 | +import sys
|
| 26 | +import os
|
| 27 | +import inspect
|
| 28 | +import re
|
26 | 29 |
|
27 | | -import sys
|
28 | | -import time
|
29 | 30 | import libembios
|
30 | | -import struct
|
| 31 | +from libembios import Error
|
| 32 | +import libembiosdata
|
31 | 33 |
|
| 34 | +class NotImplementedError(Error):
|
| 35 | + pass
|
32 | 36 |
|
33 | | -def usage():
|
34 | | - print ""
|
35 | | - print "Please provide a command and (if needed) parameters as command line arguments"
|
36 | | - print ""
|
37 | | - print "Available commands:"
|
38 | | - print ""
|
39 | | - print " getinfo <infotype>"
|
40 | | - print " Get info on the running emBIOS."
|
41 | | - print " <infotype> may be either off 'version', 'packetsize', 'usermemrange'."
|
42 | | - print ""
|
43 | | - print " reset <force>"
|
44 | | - print " Resets the device"
|
45 | | - print " If <force> is 1, the reset will be forced, otherwise it will be gracefully,"
|
46 | | - print " which may take some time."
|
47 | | - print ""
|
48 | | - print " poweroff <force>"
|
49 | | - print " Powers the device off"
|
50 | | - print " If <force> is 1, the poweroff will be forced, otherwise it will be gracefully,"
|
51 | | - print " which may take some time."
|
52 | | - print ""
|
53 | | - print ""
|
54 | | - print " uploadfile <offset> <file> <usedma> <freezescheduler>"
|
55 | | - print " Uploads a file to the iPod"
|
56 | | - print " <offset>: the address to upload the file to"
|
57 | | - print " <file>: the path to the file"
|
58 | | - print " <usedma>: if 0, DMA will not be used when uploading the file,"
|
59 | | - print " otherwise it will be used. It can be omitted, default is then 1"
|
60 | | - print " <freezescheduler>: if not 0, the scheduler will be frozen during DMA access"
|
61 | | - print " to prevent non-consistent data after the transfer."
|
62 | | - print " It can be omitted, default is then 0"
|
63 | | - print ""
|
64 | | - print " downloadfile <offset> <size> <file> <usedma> <freezescheduler>"
|
65 | | - print " Uploads a file to the iPod"
|
66 | | - print " <offset>: the address to upload the file to"
|
67 | | - print " <size>: the number of bytes to be read"
|
68 | | - print " <file>: the path to the file"
|
69 | | - print " <usedma>: if 0, DMA will not be used when downloading the file,"
|
70 | | - print " otherwise it will be used. It can be omitted, default is then 1"
|
71 | | - print " <freezescheduler>: if not 0, the scheduler will be frozen during DMA access"
|
72 | | - print " to prevent non-consistent data after the transfer"
|
73 | | - print " It can be omitted, default is then 0"
|
74 | | - print ""
|
75 | | - print " uploadint <offset> <data>"
|
76 | | - print " Uploads a single integer to the iPod"
|
77 | | - print " <offset>: the address to upload the integer to"
|
78 | | - print " <data>: the integer to upload"
|
79 | | - print ""
|
80 | | - print " downloadint <offset>"
|
81 | | - print " Downloads a single integer from the iPod and prints it to the console window"
|
82 | | - print " <offset>: the address to download the integer from"
|
83 | | - print ""
|
84 | | - print ""
|
85 | | - print " i2crecv <bus> <slave> <addr> <size>"
|
86 | | - print " Reads data from an I2C device"
|
87 | | - print " <bus> the bus index"
|
88 | | - print " <slave> the slave address"
|
89 | | - print " <addr> the start address on the I2C device"
|
90 | | - print " <size> the number of bytes to read"
|
91 | | - print ""
|
92 | | - print " i2csend <bus> <slave> <addr> <db1> <db2> ... <dbN>"
|
93 | | - print " Writes data to an I2C device"
|
94 | | - print " <bus> the bus index"
|
95 | | - print " <slave> the slave address"
|
96 | | - print " <addr> the start address on the I2C device"
|
97 | | - print " <db1> ... <dbN> the data in single bytes, seperated by whitespaces,"
|
98 | | - print " eg. 0x37 0x56 0x45 0x12"
|
99 | | - print ""
|
100 | | - print ""
|
101 | | - print " readusbconsole <size> <outtype> <file>"
|
102 | | - print " Reads data from the USB console."
|
103 | | - print " <size>: the number of bytes to read"
|
104 | | - print " <outtype>: defines how to output the result:"
|
105 | | - print " 'file': writes the result to file <file>"
|
106 | | - print " 'printstring': writes the result as string to the console window"
|
107 | | - print " 'printhex': writes the result in hexedit notation to the console window"
|
108 | | - print " <file>: the file to write the result to, can be omitted"
|
109 | | - print " if <outtype> is not 'file'"
|
110 | | - print ""
|
111 | | - print " writeusbconsole file <file> <offset> <length>"
|
112 | | - print " Writes the file <file> to the USB console."
|
113 | | - print " Optional params <offset> <length>: specify the range in <file> to write"
|
114 | | - print " writeusbconsole direct <i1> <i2> ... <iN>"
|
115 | | - print " Writes the integers <i1> ... <iN> to the USB console."
|
116 | | - print " writeusbconsole string <str>"
|
117 | | - print " Writes the string <str> to the USB console."
|
118 | | - print ""
|
119 | | - print " readdevconsole <bitmask> <size> <outtype> <file>"
|
120 | | - print " Reads data from one or more of the device's consoles."
|
121 | | - print " <bitmask>: the bitmask of the consoles to read from"
|
122 | | - print " <size>: the number of bytes to read"
|
123 | | - print " <outtype>: defines how to output the result:"
|
124 | | - print " 'file': writes the result to file <file>"
|
125 | | - print " 'printstring': writes the result as string to the console window"
|
126 | | - print " 'printhex': writes the result in hexedit notation to the console window"
|
127 | | - print " <file>: the file to write the result to, can be omitted"
|
128 | | - print " if <outtype> is not 'file'"
|
129 | | - print ""
|
130 | | - print " writedevconsole file <bitmask> <file> <offset> <length>"
|
131 | | - print " Writes the file <file> to the device consoles specified by <bitmask>"
|
132 | | - print " Optional params <offset> <length>: specify the range in <file> to write"
|
133 | | - print " writedevconsole direct <bitmask> <i1> <i2> ... <iN>"
|
134 | | - print " Writes the integers <i1> ... <iN> to the device consoles specified"
|
135 | | - print " by <bitmask>"
|
136 | | - print " writedevconsole string <bitmask> <str>"
|
137 | | - print " Writes the string <str> to the device consoles specified by <bitmask>"
|
138 | | - print ""
|
139 | | - print " flushconsolebuffers <bitmask>"
|
140 | | - print " flushes one or more of the device consoles' buffers."
|
141 | | - print " <bitmask>: the bitmask of the consoles to be flushed"
|
142 | | - print ""
|
143 | | - print ""
|
144 | | - print " getprocessinformation / getprocinfo"
|
145 | | - print " Fetches data on the currently running processes"
|
146 | | - print " ATTENTION: this function will be print the information to the console window."
|
147 | | - print " If several threads are running this might overflow the window,"
|
148 | | - print " causing not everything to be shown."
|
149 | | - print ""
|
150 | | - print " lockscheduler"
|
151 | | - print " Locks (freezes) the scheduler"
|
152 | | - print ""
|
153 | | - print " unlockscheduler"
|
154 | | - print " Unlocks the scheduler"
|
155 | | - print ""
|
156 | | - print " suspendthread <threadid>"
|
157 | | - print " Suspends/resumes the thread with thread ID <threadid>"
|
158 | | - print ""
|
159 | | - print " resumethread <threadid>"
|
160 | | - print " Resumes the thread with thread ID <threadid>"
|
161 | | - print ""
|
162 | | - print " killthread <threadid>"
|
163 | | - print " Kills the thread with thread ID <threadid>"
|
164 | | - print ""
|
165 | | - print " createthread <namepointer> <entrypoint> <stackpointer> <stacksize> <type> <priority> <state>"
|
166 | | - print " Creates a new thread and returns its thread ID"
|
167 | | - print " <namepointer> a pointer to the thread's name"
|
168 | | - print " <entrypoint> a pointer to the entrypoint of the thread"
|
169 | | - print " <stackpointer> a pointer to the stack of the thread"
|
170 | | - print " <stacksize> the size of the thread's stack"
|
171 | | - print " <type> the thread type, vaild are: 0 => user thread, 1 => system thread"
|
172 | | - print " <priority> the priority of the thread, from 1 to 255"
|
173 | | - print " <state> the thread's initial state, valid are: 1 => ready, 0 => suspended"
|
174 | | - print ""
|
175 | | - print " execimage <offset>"
|
176 | | - print " Executes the emBIOS executable image at <offset>."
|
177 | | - print ""
|
178 | | - print " execfirmware <offset>"
|
179 | | - print " Executes the firmware image at the specified address <offset>."
|
180 | | - print ""
|
181 | | - print ""
|
182 | | - print " readrawbootflash <addr_bootflsh> <addr_mem> <size>"
|
183 | | - print " Reads <size> bytes from bootflash to memory."
|
184 | | - print " <addr_bootflsh>: the address in bootflash to read from"
|
185 | | - print " <addr_mem>: the address in memory to copy the data to"
|
186 | | - print ""
|
187 | | - print " writerawbootflash <addr_mem> <addr_bootflsh> <size>"
|
188 | | - print " Writes <size> bytes from memory to bootflash."
|
189 | | - print " Don't call this unless you really know what you're doing."
|
190 | | - print " <addr_mem>: the address in memory to copy the data from"
|
191 | | - print " <addr_bootflsh>: the address in bootflash to write to"
|
192 | | - print ""
|
193 | | - print ""
|
194 | | - print " flushcaches"
|
195 | | - print " Flushes the CPUs data and instruction caches."
|
196 | | - print ""
|
197 | | - print "All numbers are hexadecimal!"
|
198 | | - exit(2)
|
| 37 | +class ArgumentError(Error):
|
| 38 | + pass
|
199 | 39 |
|
| 40 | +class ArgumentTypeError(Error):
|
| 41 | + def __init__(self, expected, seen=False):
|
| 42 | + self.expected = expected
|
| 43 | + self.seen = seen
|
| 44 | + def __str__(self):
|
| 45 | + if self.seen:
|
| 46 | + return "Expected " + str(self.expected) + " but saw " + str(self.seen)
|
| 47 | + else:
|
| 48 | + return "Expected " + str(self.expected) + ", but saw something else"
|
200 | 49 |
|
201 | | -def parsecommand(dev, argv):
|
202 | | - if len(argv) < 2: usage()
|
203 | 50 |
|
204 | | - elif argv[1] == "getinfo":
|
205 | | - if len(argv) != 3: usage()
|
206 | | - dev.getinfo(argv[2])
|
207 | | -
|
208 | | - elif argv[1] == "reset":
|
209 | | - if len(argv) != 3: usage()
|
210 | | - dev.reset(int(argv[2]), 16)
|
211 | | -
|
212 | | - elif argv[1] == "poweroff":
|
213 | | - if len(argv) != 3: usage()
|
214 | | - dev.poweroff(int(argv[2]), 16)
|
| 51 | +def usage(errormsg=None, specific=False):
|
| 52 | + """
|
| 53 | + Prints the usage information.
|
| 54 | + It is auto generated from various places.
|
| 55 | + """
|
| 56 | + logger = Logger()
|
| 57 | + cmddict= Commandline.cmddict
|
| 58 | + doc = {}
|
| 59 | + # This sorts the output of various internal functions
|
| 60 | + # and puts everything in easy readable form
|
| 61 | + for function in cmddict:
|
| 62 | + function = cmddict[function].func
|
| 63 | + docinfo = {}
|
| 64 | + name = function.__name__
|
| 65 | + args = inspect.getargspec(function)[0]
|
| 66 | + docinfo['varargs'] = False
|
| 67 | + if inspect.getargspec(function)[1]:
|
| 68 | + docinfo['varargs'] = True
|
| 69 | + kwargvalues = inspect.getargspec(function)[3]
|
| 70 | + kwargs = {}
|
| 71 | + if args:
|
| 72 | + if kwargvalues:
|
| 73 | + argnum = len(args) - len(kwargvalues)
|
| 74 | + kwargnum = len(kwargvalues)
|
| 75 | + kwargs = dict(zip(args[argnum:], kwargvalues))
|
| 76 | + else:
|
| 77 | + argnum = len(args)
|
| 78 | + else:
|
| 79 | + argnum = 0
|
| 80 | + docinfo['args'] = args[1:argnum]
|
| 81 | + docinfo['kwargs'] = kwargs
|
| 82 | + if function.__doc__:
|
| 83 | + # strip unneccessary whitespace
|
| 84 | + docinfo['documentation'] = re.sub(r'\n ', '\n', function.__doc__)
|
| 85 | + else:
|
| 86 | + docinfo['documentation'] = None
|
| 87 | + doc[name] = docinfo
|
215 | 88 |
|
216 | | -
|
217 | | - elif argv[1] == "uploadfile":
|
218 | | - if len(argv) < 4 or len(argv) > 6: usage()
|
219 | | - if len(argv) > 4:
|
220 | | - usedma = int(argv[4], 16)
|
221 | | - if len(argv) > 5:
|
222 | | - freezesched = int(argv[5], 16)
|
223 | | - else:
|
224 | | - freezesched = 0
|
| 89 | + if not specific:
|
| 90 | + logger.log("Please provide a command and (if needed) parameters as command line arguments\n\n")
|
| 91 | + logger.log("Available commands:\n\n")
|
225 | 92 | else:
|
226 | | - freezesched = 0
|
227 | | - usedma = 1
|
228 | | - dev.uploadfile(int(argv[2], 16), argv[3], usedma, freezesched)
|
229 | | -
|
230 | | - elif argv[1] == "downloadfile":
|
231 | | - if len(argv) < 5 or len(argv) > 7: usage()
|
232 | | - if len(argv) > 5:
|
233 | | - usedma = int(argv[5], 16)
|
234 | | - if len(argv) > 6:
|
235 | | - freezesched = int(argv[6], 16)
|
236 | | - else:
|
237 | | - freezesched = 0
|
238 | | - else:
|
239 | | - freezesched = 0
|
240 | | - usedma = 1
|
241 | | - dev.downloadfile(int(argv[2], 16), int(argv[3], 16), argv[4], usedma, freezesched)
|
242 | | -
|
243 | | - elif argv[1] == "uploadint":
|
244 | | - if len(argv) != 4: usage()
|
245 | | - dev.uploadint(int(argv[2], 16), int(argv[3], 16))
|
246 | | -
|
247 | | - elif argv[1] == "downloadint":
|
248 | | - if len(argv) != 3: usage()
|
249 | | - dev.downloadint(int(argv[2], 16))
|
250 | | -
|
251 | | -
|
252 | | - elif argv[1] == "i2cread":
|
253 | | - if len(argv) != 6: usage()
|
254 | | - dev.i2crecv(int(argv[2], 16), int(argv[3], 16), int(argv[4], 16), int(argv[5], 16))
|
| 93 | + logger.log("\n")
|
| 94 | + for function in sorted(doc.items()):
|
| 95 | + function = function[0]
|
| 96 | + if specific == False or specific == function:
|
| 97 | + logger.log(" " + function + " ")
|
| 98 | + for arg in doc[function]['args']:
|
| 99 | + logger.log("<" + arg + "> ")
|
| 100 | + if doc[function]['kwargs']:
|
| 101 | + for kwarg in doc[function]['kwargs']:
|
| 102 | + logger.log("[" + kwarg + "] ")
|
| 103 | + if doc[function]['varargs']:
|
| 104 | + logger.log("<db1> ... <dbN>")
|
| 105 | + if doc[function]['documentation']:
|
| 106 | + logger.log(doc[function]['documentation']+"\n")
|
255 | 107 |
|
256 | | - elif argv[1] == "i2csend":
|
257 | | - if len(argv) < 6: usage()
|
258 | | - data = ""
|
259 | | - ptr = 5
|
260 | | - while ptr < len(argv):
|
261 | | - data += struct.pack("<B", int(argv[ptr], 16))
|
262 | | - ptr += 1
|
263 | | - dev.i2csend(int(argv[2], 16), int(argv[3], 16), int(argv[4], 16), data)
|
264 | | -
|
265 | | -
|
266 | | - elif argv[1] == "readusbconsole":
|
267 | | - if len(argv) not in [4, 5]: usage()
|
268 | | - if len(argv) == 4: argv[4] = ""
|
269 | | - dev.readusbcon(int(argv[2], 16), argv[3], argv[4])
|
270 | | -
|
271 | | - elif argv[1] == "writeusbconsole":
|
272 | | - if len(argv) < 4: usage()
|
| 108 | + logger.log("\n")
|
| 109 | +
|
| 110 | + if errormsg:
|
| 111 | + logger.error(str(errormsg)+"\n")
|
| 112 | + exit(2)
|
| 113 | +
|
| 114 | +
|
| 115 | +class Logger(object):
|
| 116 | + """
|
| 117 | + Simple stdout logger.
|
| 118 | + Loglevel 4 is most verbose, Loglevel 0 only say something if there is an error.
|
| 119 | + """
|
| 120 | + def __init__(self):
|
| 121 | + # Possible values: 0 (only errors), 1 (warnings), 2 (info, recommended for production use), 3 and more (debug)
|
| 122 | + self.loglevel = 3
|
| 123 | +
|
| 124 | + def log(self, text):
|
| 125 | + sys.stdout.write(text)
|
273 | 126 |
|
274 | | - if argv[2] == "file":
|
275 | | - f = open(argv[3], "rb")
|
276 | | - data = f.read()
|
277 | | -
|
278 | | - if len(argv) > 4:
|
279 | | - offset = int(argv[4], 16)
|
280 | | - else:
|
281 | | - offset = 0
|
282 | | - if len(argv) > 5:
|
283 | | - size = int(argv[5], 16)
|
284 | | - else:
|
285 | | - size = len(data)
|
286 | | - if len(argv) > 6: usage()
|
287 | | -
|
288 | | - dev.writeusbcon(data, 0, offset, size)
|
289 | | -
|
290 | | - if argv[2] == "direct":
|
291 | | - data = ""
|
292 | | - ptr = 3
|
293 | | - while ptr < len(argv):
|
294 | | - data += struct.pack("<I", int(argv[ptr], 16))
|
295 | | - ptr += 1
|
296 | | - dev.writeusbcon(data)
|
297 | | -
|
298 | | - if argv[2] == "string":
|
299 | | - if len(argv) > 4: usage()
|
300 | | - dev.writeusbcon(argv[3])
|
| 127 | + def debug(self, text):
|
| 128 | + if self.loglevel >= 3:
|
| 129 | + self.log(text)
|
301 | 130 |
|
302 | | - else: usage()
|
303 | | -
|
304 | | - elif argv[1] == "readdevconsole":
|
305 | | - if len(argv) not in [5, 6]: usage()
|
306 | | - if len(argv) == 5: argv[5] = ""
|
307 | | - dev.readusbcon(int(argv[2], 16), int(argv[3], 16), argv[4], argv[5])
|
308 | | -
|
309 | | - elif argv[1] == "writedevconsole":
|
310 | | - if len(argv) < 5: usage()
|
| 131 | + def info(self, text):
|
| 132 | + if self.loglevel >= 2:
|
| 133 | + self.log(text)
|
311 | 134 |
|
312 | | - if argv[2] == "file":
|
313 | | - f = open(argv[4], "rb")
|
314 | | - data = f.read()
|
315 | | -
|
316 | | - if len(argv) > 5:
|
317 | | - offset = int(argv[5], 16)
|
318 | | - else:
|
319 | | - offset = 0
|
320 | | - if len(argv) > 6:
|
321 | | - size = int(argv[6], 16)
|
322 | | - else:
|
323 | | - size = len(data)
|
324 | | - if len(argv) > 7: usage()
|
325 | | -
|
326 | | - dev.writeusbcon(int(argv[3], 16), data, 0, offset, size)
|
327 | | -
|
328 | | - if argv[2] == "direct":
|
329 | | - data = ""
|
330 | | - ptr = 4
|
331 | | - while ptr < len(argv):
|
332 | | - data += struct.pack("<I", int(argv[ptr], 16))
|
333 | | - ptr += 1
|
334 | | - dev.writeusbcon(int(argv[3], 16), data)
|
335 | | -
|
336 | | - if argv[2] == "string":
|
337 | | - if len(argv) > 5: usage()
|
338 | | - dev.writedevcon(int(argv[3], 16), argv[4])
|
| 135 | + def warning(self, text):
|
| 136 | + if self.loglevel >= 1:
|
| 137 | + self.log("WARNING: " + text)
|
339 | 138 |
|
340 | | - else: usage()
|
341 | | -
|
342 | | - elif argv[1] == "flushconsolebuffers":
|
343 | | - if len(argv) != 3: usage()
|
344 | | - dev.flushconsolebuffers(int(argv[2], 16))
|
345 | | -
|
346 | | -
|
347 | | - elif argv[1] == "getprocessinformation" or argv[1] == "getprocinfo":
|
348 | | - if len(argv) != 2: usage()
|
349 | | - dev.getprocinfo()
|
| 139 | + def error(self, text):
|
| 140 | + self.log("ERROR: " + text)
|
| 141 | +
|
| 142 | +
|
| 143 | +def command(func):
|
| 144 | + """
|
| 145 | + Decorator for all commands.
|
| 146 | + The decorated function is called with (self, all, other, arguments, ...)
|
| 147 | + """
|
| 148 | + def decorator(args):
|
| 149 | + return func(args[0], *args[1:])
|
| 150 | + func._command = True
|
| 151 | + decorator.func = func
|
| 152 | + return decorator
|
| 153 | +
|
| 154 | +
|
| 155 | +def commandClass(cls):
|
| 156 | + """
|
| 157 | + Decorator for the class. Sets the self.cmddict of the class
|
| 158 | + to all functions decorated with @command
|
| 159 | + """
|
| 160 | + cls.cmddict = {}
|
| 161 | + for attr, value in cls.__dict__.iteritems():
|
| 162 | + if getattr(value, 'func', False):
|
| 163 | + if getattr(value.func, '_command', False):
|
| 164 | + cls.cmddict[value.func.__name__] = value
|
| 165 | + return cls
|
| 166 | +
|
| 167 | +
|
| 168 | +@commandClass
|
| 169 | +class Commandline(object):
|
| 170 | + """
|
| 171 | + If you want to create a new commandline function you just need to
|
| 172 | + create a function with the name of it in this class and decorate
|
| 173 | + it with the decorator @command. If you don't want to call the desired
|
| 174 | + function (wrong arguments etc) just raise ArgumentError with or
|
| 175 | + without an error message or raise ArgumentCountError
|
| 176 | + """
|
| 177 | + def __init__(self):
|
| 178 | + self.logger = Logger()
|
| 179 | + try:
|
| 180 | + self.embios = libembios.Embios()
|
| 181 | + except libembios.DeviceNotFoundError:
|
| 182 | + self.logger.error("No emBIOS device found!")
|
| 183 | + end(1)
|
| 184 | +
|
| 185 | + def _parsecommand(self, func, args):
|
| 186 | + # adds self to the commandline args.
|
| 187 | + # this is needed because the functions need access to their class.
|
| 188 | + args.insert(0, self)
|
| 189 | + if func in self.cmddict:
|
| 190 | + try:
|
| 191 | + self.cmddict[func](args)
|
| 192 | + except ArgumentError, e:
|
| 193 | + usage(e)
|
| 194 | + except ArgumentError:
|
| 195 | + usage("Syntax Error in function '" + func + "'")
|
| 196 | + except ArgumentTypeError, e:
|
| 197 | + usage(e)
|
| 198 | + except NotImplementedError:
|
| 199 | + self.logger.error("This function is not implemented yet!")
|
| 200 | + except libembios.DeviceError, e:
|
| 201 | + self.logger.error(str(e))
|
| 202 | + except TypeError, e:
|
| 203 | + if str(e).split(" ", 1)[0] == func + "()":
|
| 204 | + self.logger.error(usage("Argument Error in '" + func + "': Wrong argument count", specific=func))
|
| 205 | + else:
|
| 206 | + raise
|
| 207 | + else:
|
| 208 | + usage("No such command")
|
350 | 209 |
|
351 | | - elif argv[1] == "lockscheduler":
|
352 | | - if len(argv) != 2: usage()
|
353 | | - dev.freezescheduler(1)
|
| 210 | + @staticmethod
|
| 211 | + def _bool(something):
|
| 212 | + """
|
| 213 | + Converts quite everything into bool.
|
| 214 | + """
|
| 215 | + if type(something) == bool:
|
| 216 | + return something
|
| 217 | + elif type(something) == int or type(something) == long:
|
| 218 | + return bool(something)
|
| 219 | + elif type(something == str):
|
| 220 | + truelist = ['true', '1', 't', 'y', 'yes']
|
| 221 | + falselist = ['false', '0', 'f', 'n', 'no']
|
| 222 | + if something.lower() in truelist:
|
| 223 | + return True
|
| 224 | + elif something.lower() in falselist:
|
| 225 | + return False
|
| 226 | + raise ArgumentTypeError("bool", "'"+str(something)+"'")
|
| 227 | +
|
| 228 | + @staticmethod
|
| 229 | + def _hexint(something):
|
| 230 | + """
|
| 231 | + Converts quite everything to a hexadecimal represented integer.
|
| 232 | + This works for default arguments too, because it returns
|
| 233 | + None when it found that it got a NoneType object.
|
| 234 | + """
|
| 235 | + if type(something) == int or type(something) == long:
|
| 236 | + return something
|
| 237 | + elif type(something) == str:
|
| 238 | + try:
|
| 239 | + return int(something, 16)
|
| 240 | + except ValueError:
|
| 241 | + raise ArgumentTypeError("hexadecimal coded integer", "'"+str(something)+"'")
|
| 242 | + elif type(something) == NoneType:
|
| 243 | + return None
|
| 244 | + else:
|
| 245 | + raise ArgumentTypeError("hexadecimal coded integer", "'"+str(something)+"'")
|
| 246 | +
|
| 247 | + @staticmethod
|
| 248 | + def _strcheck(string, values):
|
| 249 | + if string in values:
|
| 250 | + return string
|
| 251 | + else:
|
| 252 | + expected = ""
|
| 253 | + for item in values:
|
| 254 | + expected += "'" + item + "', "
|
| 255 | + expected = expected[:-2]
|
| 256 | + raise ArgumentTypeError("one out of " + expected, "'" + string + "'")
|
354 | 257 |
|
355 | | - elif argv[1] == "unlockscheduler":
|
356 | | - if len(argv) != 2: usage()
|
357 | | - dev.freezescheduler(0)
|
358 | 258 |
|
359 | | - elif argv[1] == "suspendthread":
|
360 | | - if len(argv) != 3: usage()
|
361 | | - dev.suspendthread(1, int(argv[2], 16))
|
| 259 | + @command
|
| 260 | + def getinfo(self, infotype):
|
| 261 | + """
|
| 262 | + Get info on the running emBIOS.
|
| 263 | + <infotype> may be either of 'version', 'packetsize', 'usermemrange'.
|
| 264 | + """
|
| 265 | + if infotype == "version":
|
| 266 | + resp = self.embios.getversioninfo()
|
| 267 | + self.logger.info(libembiosdata.swtypes[resp.swtypeid] + " v" + str(resp.majorv) + "." + str(resp.minorv) +
|
| 268 | + "." + str(resp.patchv) + " r" + str(resp.revision) + " running on " + libembiosdata.hwtypes[resp.hwtypeid] + "\n")
|
| 269 | + elif infotype == "packetsize":
|
| 270 | + resp = self.embios.getpacketsizeinfo()
|
| 271 | + self.logger.info("Maximum packet sizes: "+str(resp))
|
| 272 | + elif infotype == "usermemrange":
|
| 273 | + resp = self.embios.getusermemrange()
|
| 274 | + self.logger.info("The user memory range is "+hex(resp.lower)+" - "+hex(resp.upper-1))
|
| 275 | + else:
|
| 276 | + raise ArgumentTypeError("one out of 'version', 'packetsize', 'usermemrange'", infotype)
|
362 | 277 |
|
363 | | - elif argv[1] == "resumethread":
|
364 | | - if len(argv) != 3: usage()
|
365 | | - dev.suspendthread(0, int(argv[2], 16))
|
| 278 | + @command
|
| 279 | + def reset(self, force=False):
|
| 280 | + """
|
| 281 | + Resets the device"
|
| 282 | + If <force> is 1, the reset will be forced, otherwise it will be gracefully,
|
| 283 | + which may take some time.
|
| 284 | + """
|
| 285 | + force = self._bool(force)
|
| 286 | + if force: self.logger.info("Resetting forcefully...\n")
|
| 287 | + else: self.logger.info("Resetting...\n")
|
| 288 | + self.embios.reset(force)
|
366 | 289 |
|
367 | | - elif argv[1] == "killthread":
|
368 | | - if len(argv) != 3: usage()
|
369 | | - dev.killthread(int(argv[2], 16))
|
| 290 | + @command
|
| 291 | + def poweroff(self, force=False):
|
| 292 | + """
|
| 293 | + Powers the device off
|
| 294 | + If <force> is 1, the poweroff will be forced, otherwise it will be gracefully,
|
| 295 | + which may take some time.
|
| 296 | + """
|
| 297 | + force = self._bool(force)
|
| 298 | + if force: self.logger.info("Resetting forcefully...\n")
|
| 299 | + else: self.logger.info("Resetting...\n")
|
| 300 | + self.embios.reset(force)
|
370 | 301 |
|
371 | | - elif argv[1] == "createthread":
|
372 | | - if len(argv) != 9: usage()
|
373 | | - dev.createthread(int(argv[2], 16), int(argv[3], 16), int(argv[4], 16), int(argv[5], 16), int(argv[6], 16), int(argv[7], 16), int(argv[8], 16))
|
| 302 | + @command
|
| 303 | + def uploadfile(self, addr, filename):
|
| 304 | + """
|
| 305 | + Uploads a file to the device
|
| 306 | + <offset>: the address to upload the file to
|
| 307 | + <filename>: the path to the file
|
| 308 | + """
|
| 309 | + addr = self._hexint(addr)
|
| 310 | + try:
|
| 311 | + f = open(filename, 'rb')
|
| 312 | + except IOError:
|
| 313 | + raise ArgumentError("File not readable. Does it exist?")
|
| 314 | + self.logger.info("Writing file '"+filename+"' to memory at "+hex(addr)+"...")
|
| 315 | + with f:
|
| 316 | + self.embios.write(addr, f.read())
|
| 317 | + self.logger.info("done\n")
|
| 318 | +
|
| 319 | +
|
| 320 | +
|
| 321 | + @command
|
| 322 | + def downloadfile(self, addr, size, filename):
|
| 323 | + """
|
| 324 | + Uploads a file to the device
|
| 325 | + <offset>: the address to upload the file to
|
| 326 | + <size>: the number of bytes to be read
|
| 327 | + <filename>: the path to the file
|
| 328 | + """
|
| 329 | + addr = self._hexint(addr)
|
| 330 | + size = self._hexint(size)
|
| 331 | + try:
|
| 332 | + f = open(filename, 'wb')
|
| 333 | + except IOError:
|
| 334 | + raise ArgumentError("Can not open file for write!")
|
| 335 | + self.logger.info("Reading data from address "+hex(addr)+" with the size "+hex(size)+" to '"+filename+"'...")
|
| 336 | + with f:
|
| 337 | + f.write(self.embios.read(addr, size))
|
| 338 | + self.logger.info("done\n")
|
| 339 | +
|
| 340 | + @command
|
| 341 | + def uploadint(self, addr, integer):
|
| 342 | + """
|
| 343 | + Uploads a single integer to the device
|
| 344 | + <offset>: the address to upload the integer to
|
| 345 | + <data>: the integer to upload
|
| 346 | + """
|
| 347 | + addr = self._hexint(addr)
|
| 348 | + integer = self._hexint(integer)
|
| 349 | + if integer > 0xFFFFFFFF:
|
| 350 | + raise ArgumentError("Specified integer too long")
|
| 351 | + data = chr(integer)
|
| 352 | + self.embios.writemem(addr, data)
|
| 353 | + self.logger.info("Integer '"+hex(integer)+"' written successfully to "+hex(addr))
|
| 354 | +
|
| 355 | + @command
|
| 356 | + def downloadint(self, addr):
|
| 357 | + """
|
| 358 | + Downloads a single integer from the device and prints it to the console window
|
| 359 | + <offset>: the address to download the integer from
|
| 360 | + """
|
| 361 | + addr = self._hexint(addr)
|
| 362 | + data = self.embios.readmem(addr, 1)
|
| 363 | + integer = ord(data)
|
| 364 | + self.logger.info("Integer '"+hex(integer)+"' read from address "+hex(addr))
|
| 365 | +
|
| 366 | + @command
|
| 367 | + def i2crecv(self, bus, slave, addr, size):
|
| 368 | + """
|
| 369 | + Reads data from an I2C device
|
| 370 | + <bus> the bus index
|
| 371 | + <slave> the slave address
|
| 372 | + <addr> the start address on the I2C device
|
| 373 | + <size> the number of bytes to read
|
| 374 | + """
|
| 375 | + bus = self._hexint(bus)
|
| 376 | + slave = self._hexint(slave)
|
| 377 | + addr = self._hexint(addr)
|
| 378 | + size = self._hexint(size)
|
| 379 | + raise NotImplementedError
|
| 380 | +
|
| 381 | + @command
|
| 382 | + def i2csend(self, bus, slave, addr, *args):
|
| 383 | + """
|
| 384 | + Writes data to an I2C device
|
| 385 | + <bus> the bus index
|
| 386 | + <slave> the slave address
|
| 387 | + <addr> the start address on the I2C device
|
| 388 | + <db1> ... <dbN> the data in single bytes, seperated by whitespaces,
|
| 389 | + eg. 0x37 0x56 0x45 0x12
|
| 390 | + """
|
| 391 | + bus = self._hexint(bus)
|
| 392 | + slave = self._hexint(slave)
|
| 393 | + addr = self._hexint(addr)
|
| 394 | + data = []
|
| 395 | + for arg in args:
|
| 396 | + data.append(self._hexint(arg))
|
| 397 | + raise NotImplementedError
|
| 398 | +
|
| 399 | + @command
|
| 400 | + def readusbconsole(self, size, outtype):
|
| 401 | + """
|
| 402 | + Reads data from the USB console.
|
| 403 | + <size>: the number of bytes to read
|
| 404 | + <outtype>: defines how to output the result:
|
| 405 | + 'file': writes the result to file <file>
|
| 406 | + 'printstring': writes the result as string to the console window
|
| 407 | + 'printhex': writes the result in hexedit notation to the console window
|
| 408 | + <file>: the file to write the result to, can be omitted
|
| 409 | + if <outtype> is not 'file'
|
| 410 | + """
|
| 411 | + size = self._hexint(size)
|
| 412 | + raise NotImplementedError
|
| 413 | +
|
| 414 | +
|
| 415 | + @command
|
| 416 | + def writeusbconsole_file(self, file, offset=0, length=None):
|
| 417 | + """
|
| 418 | + Writes the file <file> to the USB console.
|
| 419 | + Optional params <offset> <length>: specify the range in <file> to write
|
| 420 | + """
|
| 421 | + # We don't care about file here, this is done when opening it
|
| 422 | + offset = self._hexint(offset)
|
| 423 | + length = self._hexint(length)
|
| 424 | + raise NotImplementedError
|
| 425 | +
|
| 426 | + @command
|
| 427 | + def writeusbconsole_direct(self, *args):
|
| 428 | + """
|
| 429 | + Writes the strings <db1> ... <dbN> to the USB console."
|
| 430 | + """
|
| 431 | + raise NotImplementedError
|
| 432 | +
|
| 433 | + @command
|
| 434 | + def readdevconsole(self, bitmask, size, outtype, file=None):
|
| 435 | + """
|
| 436 | + Reads data from one or more of the device's consoles.
|
| 437 | + <bitmask>: the bitmask of the consoles to read from
|
| 438 | + <size>: the number of bytes to read
|
| 439 | + <outtype>: defines how to output the result:
|
| 440 | + 'file': writes the result to file <file>
|
| 441 | + 'printstring': writes the result as string to the console window
|
| 442 | + 'printhex': writes the result in hexedit notation to the console window
|
| 443 | + <file>: the file to write the result to, can be omitted
|
| 444 | + if <outtype> is not 'file'
|
| 445 | + """
|
| 446 | + bitmask = self._hexint(bitmask)
|
| 447 | + size = self._hexint(size)
|
| 448 | + outtype = self._strcheck(['file', 'printstring', 'printhex'])
|
| 449 | + raise NotImplementedError
|
| 450 | +
|
| 451 | + @command
|
| 452 | + def writedevconsole_file(self, bitmask, file, offset=0, length=None):
|
| 453 | + """
|
| 454 | + Writes the file <file> to the device consoles specified by <bitmask>
|
| 455 | + Optional params <offset> <length>: specify the range in <file> to write
|
| 456 | + """
|
| 457 | + bitmask = self._hexint(bitmask)
|
| 458 | + # We don't care about file here, this is done when opening it
|
| 459 | + offset = self._hexint(offset)
|
| 460 | + length = self._hexint(length)
|
| 461 | + raise NotImplementedError
|
| 462 | +
|
| 463 | + @command
|
| 464 | + def writedevconsole_direct(self, bitmask, *args):
|
| 465 | + """
|
| 466 | + Writes the integers <db1> ... <dbN> to the device consoles specified
|
| 467 | + by <bitmask>
|
| 468 | + """
|
| 469 | + bitmask = self._hexint(bitmask)
|
| 470 | + data = []
|
| 471 | + for arg in args:
|
| 472 | + data.append(self._hexint(arg))
|
| 473 | + raise NotImplementedError
|
| 474 | +
|
| 475 | + @command
|
| 476 | + def flushconsolebuffers(self, bitmask):
|
| 477 | + """
|
| 478 | + flushes one or more of the device consoles' buffers.
|
| 479 | + <bitmask>: the bitmask of the consoles to be flushed
|
| 480 | + """
|
| 481 | + bitmask = self._hexint(bitmask)
|
| 482 | + raise NotImplementedError
|
| 483 | +
|
| 484 | + @command
|
| 485 | + def getprocinfo(self):
|
| 486 | + """
|
| 487 | + Fetches data on the currently running processes
|
| 488 | + ATTENTION: this function will be print the information to the console window.
|
| 489 | + If several threads are running this might overflow the window,
|
| 490 | + causing not everything to be shown.
|
| 491 | + """
|
| 492 | + raise NotImplementedError
|
| 493 | +
|
| 494 | + @command
|
| 495 | + def lockscheduler(self):
|
| 496 | + """
|
| 497 | + Locks (freezes) the scheduler
|
| 498 | + """
|
| 499 | + raise NotImplementedError
|
| 500 | +
|
| 501 | + @command
|
| 502 | + def unlockscheduler(self):
|
| 503 | + """
|
| 504 | + Unlocks (unfreezes) the scheduler
|
| 505 | + """
|
| 506 | + raise NotImplementedError
|
| 507 | +
|
| 508 | + @command
|
| 509 | + def suspendthread(self, threadid):
|
| 510 | + """
|
| 511 | + Suspends/resumes the thread with thread ID <threadid>
|
| 512 | + """
|
| 513 | + threadid = self._hexint(threadid)
|
| 514 | + raise NotImplementedError
|
| 515 | +
|
| 516 | + @command
|
| 517 | + def resumethread(self, threadid):
|
| 518 | + """
|
| 519 | + Resumes the thread with thread ID <threadid>
|
| 520 | + """
|
| 521 | + threadid = self._hexint(threadid)
|
| 522 | + raise NotImplementedError
|
| 523 | +
|
| 524 | + @command
|
| 525 | + def killthread(self, threadid):
|
| 526 | + """
|
| 527 | + Kills the thread with thread ID <threadid>
|
| 528 | + """
|
| 529 | + threadid = self._hexint(threadid)
|
| 530 | + raise NotImplementedError
|
| 531 | +
|
| 532 | + @command
|
| 533 | + def createthread(self, nameptr, entrypoint, stackptr, stacksize, threadtype, priority, state):
|
| 534 | + """
|
| 535 | + Creates a new thread and returns its thread ID
|
| 536 | + <namepointer> a pointer to the thread's name
|
| 537 | + <entrypoint> a pointer to the entrypoint of the thread
|
| 538 | + <stackpointer> a pointer to the stack of the thread
|
| 539 | + <stacksize> the size of the thread's stack
|
| 540 | + <type> the thread type, vaild are: 0 => user thread, 1 => system thread
|
| 541 | + <priority> the priority of the thread, from 1 to 255
|
| 542 | + <state> the thread's initial state, valid are: 1 => ready, 0 => suspended
|
| 543 | + """
|
| 544 | + nameptr = self._hexint(nameptr)
|
| 545 | + entrypoint = self._hexint(entrypoint)
|
| 546 | + stackpointer = self._hexint(stackpointer)
|
| 547 | + stacksize = self._hexint(stacksize)
|
| 548 | + priority = self._hexint(priority)
|
| 549 | + self.embios.createthread(nameptr, entrypoint, stackptr, stacksize, type, priority, state)
|
| 550 | +
|
| 551 | + @command
|
| 552 | + def run(self, address):
|
| 553 | + """
|
| 554 | + Executes the emBIOS application at <address>.
|
| 555 | + """
|
| 556 | + address = self._hexint(address)
|
| 557 | + raise NotImplementedError
|
| 558 | +
|
| 559 | + @command
|
| 560 | + def readrawbootflash(self, addr_flash, addr_mem, size):
|
| 561 | + """
|
| 562 | + Reads <size> bytes from bootflash to memory.
|
| 563 | + <addr_bootflsh>: the address in bootflash to read from
|
| 564 | + <addr_mem>: the address in memory to copy the data to
|
| 565 | + """
|
| 566 | + addr_flash = self._hexint(addr_flash)
|
| 567 | + addr_mem = self._hexint(addr_mem)
|
| 568 | + size = self._hexint(size)
|
| 569 | + raise NotImplementedError
|
| 570 | +
|
| 571 | + @command
|
| 572 | + def writerawbootflash(self, addr_flash, addr_mem, size):
|
| 573 | + """
|
| 574 | + Writes <size> bytes from memory to bootflash.
|
| 575 | + ATTENTION: Don't call this unless you really know what you're doing!
|
| 576 | + This may BRICK your device (unless it has a good recovery option)
|
| 577 | + <addr_mem>: the address in memory to copy the data from
|
| 578 | + <addr_bootflsh>: the address in bootflash to write to
|
| 579 | + """
|
| 580 | + addr_flash = self._hexint(addr_flash)
|
| 581 | + addr_mem = self._hexint(addr_mem)
|
| 582 | + size = self._hexint(size)
|
| 583 | + raise NotImplementedError
|
| 584 | +
|
| 585 | + @command
|
| 586 | + def flushcaches(self):
|
| 587 | + """
|
| 588 | + Flushes the CPUs data and instruction caches.
|
| 589 | + """
|
| 590 | + raise NotImplementedError
|
374 | 591 |
|
375 | | - elif argv[1] == "execimage":
|
376 | | - if len(argv) != 3: usage()
|
377 | | - dev.execimage(int(argv[2], 16))
|
| 592 | + @command
|
| 593 | + def aesencrypt(self, addr, size, keyindex):
|
| 594 | + """
|
| 595 | + Encrypt a buffer using a hardware key
|
| 596 | + """
|
| 597 | + addr = self._hexint(addr)
|
| 598 | + size = self._hexint(size)
|
| 599 | + keyindex = self._hexint(keyindex)
|
| 600 | + self.embios.aesencrypt(addr, size, keyindex)
|
378 | 601 |
|
379 | | - elif argv[1] == "execfirmware":
|
380 | | - if len(argv) != 3: usage()
|
381 | | - dev.execfirmware(int(argv[2], 16))
|
382 | | -
|
383 | | - elif argv[1] == "readrawbootflash":
|
384 | | - if len(argv) != 5: usage()
|
385 | | - dev.readrawbootflash(int(argv[2], 16), int(argv[3], 16), int(argv[4], 16))
|
386 | | -
|
387 | | - elif argv[1] == "writerawbootflash":
|
388 | | - if len(argv) != 5: usage()
|
389 | | - dev.writerawbootflash(int(argv[2], 16), int(argv[3], 16), int(argv[4], 16))
|
390 | | -
|
391 | | -
|
392 | | - elif argv[1] == "flushcaches":
|
393 | | - if len(argv) != 2: usage()
|
394 | | - dev.flushcaches()
|
395 | | -
|
396 | | - else: usage()
|
| 602 | + @command
|
| 603 | + def aesdecrypt(self, addr, size, keyindex):
|
| 604 | + """
|
| 605 | + Decrypt a buffer using a hardware key
|
| 606 | + """
|
| 607 | + addr = self._hexint(addr)
|
| 608 | + size = self._hexint(size)
|
| 609 | + keyindex = self._hexint(keyindex)
|
| 610 | + self.embios.aesdecrypt(addr, size, keyindex)
|
397 | 611 |
|
398 | | -dev = libembios.embios()
|
399 | | -parsecommand(dev, sys.argv)
|
| 612 | +if __name__ == "__main__":
|
| 613 | + if len(sys.argv) < 2:
|
| 614 | + usage("No command specified")
|
| 615 | + interface = Commandline()
|
| 616 | + interface._parsecommand(sys.argv[1], sys.argv[2:]) |
\ No newline at end of file |
Index: embios/trunk/tools/libembiosdata.py |
— | — | @@ -0,0 +1,19 @@ |
| 2 | +hwtypes = {
|
| 3 | + 0: "invalid",
|
| 4 | + 0x47324e49: "iPod nano 2g",
|
| 5 | + 0x47334e49: "iPod nano 3g",
|
| 6 | + 0x47344e49: "iPod nano 4g",
|
| 7 | + 0x4c435049: "iPod classic"
|
| 8 | +}
|
| 9 | +
|
| 10 | +swtypes = {
|
| 11 | + 0: "invalid",
|
| 12 | + 1: "emBIOS Debugger"
|
| 13 | +}
|
| 14 | +
|
| 15 | +responsecodes = {
|
| 16 | + 0: "invalid",
|
| 17 | + 1: "ok",
|
| 18 | + 2: "unsupported",
|
| 19 | + 3: "busy"
|
| 20 | +} |
\ No newline at end of file |
Index: embios/trunk/tools/libembios.py |
— | — | @@ -1,7 +1,7 @@ |
2 | 2 | #!/usr/bin/env python
|
3 | 3 | #
|
4 | 4 | #
|
5 | | -# Copyright 2010 TheSeven, benedikt93
|
| 5 | +# Copyright 2010 TheSeven, benedikt93, Farthen
|
6 | 6 | #
|
7 | 7 | #
|
8 | 8 | # This file is part of emBIOS.
|
— | — | @@ -21,996 +21,440 @@ |
22 | 22 | #
|
23 | 23 | #
|
24 | 24 |
|
25 | | -# note: handles commands 1 to 21
|
26 | | -
|
27 | 25 | import sys
|
28 | | -import math
|
29 | 26 | import struct
|
30 | | -import time
|
31 | | -import usb
|
| 27 | +import usb.core
|
| 28 | +import libembiosdata
|
32 | 29 |
|
| 30 | +class Error(Exception):
|
| 31 | + def __init__(self, value=None):
|
| 32 | + self.value = value
|
| 33 | + def __str__(self):
|
| 34 | + if self.value != None:
|
| 35 | + return repr(self.value)
|
33 | 36 |
|
34 | | -class embios:
|
35 | | - def __init__(self, devtype = 0, type = 0):
|
36 | | - busses = usb.busses()
|
37 | | -
|
38 | | - for bus in busses:
|
39 | | - devices = bus.devices
|
40 | | - for dev in devices:
|
41 | | - if dev.idVendor == 0xffff and dev.idProduct == 0xe000:
|
42 | | - # get endpoints
|
43 | | - self.__coutep = dev.configurations[0].interfaces[0][0].endpoints[0].address
|
44 | | - self.__cinep = dev.configurations[0].interfaces[0][0].endpoints[1].address
|
45 | | - self.__doutep = dev.configurations[0].interfaces[0][0].endpoints[2].address
|
46 | | - self.__dinep = dev.configurations[0].interfaces[0][0].endpoints[3].address
|
47 | | -
|
48 | | - handle = dev.open()
|
49 | | - handle.setConfiguration(1)
|
50 | | - handle.claimInterface(0)
|
51 | | -
|
52 | | - # get version info
|
53 | | - handle.bulkWrite(self.__coutep, struct.pack("<IIII", 1, 0, 0, 0))
|
54 | | - response = self.__getbulk(handle, self.__cinep, 0x10)
|
55 | | - self.__checkstatus(response)
|
56 | | - i = struct.unpack("<IIBBBBI", response)
|
57 | | -
|
58 | | - if devtype in [0, i[6]] and type in [0, i[5]]:
|
59 | | - # correct device
|
60 | | - self.handle = handle
|
61 | | - self.dev = dev
|
62 | | -
|
63 | | - self.svnrev, self.major, self.minor, self.patch, self.type, self.devtype = i[1:]
|
64 | | - self.__myprint("Connected to emBIOS %s v%d.%d.%d (SVN revision: %d) on %s, USB version %s\n" \
|
65 | | - % (self.type2name(self.type), self.major, self.minor, self.patch, self.svnrev, \
|
66 | | - self.devtype2name(self.devtype), dev.deviceVersion))
|
67 | | -
|
68 | | - # get packet size info
|
69 | | - self.getinfo("packetsize", 1)
|
70 | | -
|
71 | | - return
|
72 | | -
|
73 | | - # wrong device
|
74 | | - handle.releaseInterface()
|
| 37 | +class ArgumentError(Error):
|
| 38 | + pass
|
75 | 39 |
|
76 | | - raise Exception("Could not find specified device (devtype = %d, type = %d)" % (devtype, type))
|
| 40 | +class DeviceNotFoundError(Error):
|
| 41 | + pass
|
77 | 42 |
|
| 43 | +class DeviceError(Error):
|
| 44 | + pass
|
78 | 45 |
|
79 | | -#=====================================================================================
|
80 | | -
|
81 | | -
|
82 | | - @staticmethod
|
83 | | - def __myprint(data, silent = 0):
|
84 | | - if not silent:
|
85 | | - sys.stdout.write(data)
|
86 | | - sys.stdout.flush()
|
| 46 | +class SendError(Error):
|
| 47 | + pass
|
87 | 48 |
|
88 | | -
|
89 | | - @staticmethod
|
90 | | - def __gethexviewprintout(data, title, showaddr):
|
91 | | - printout_temp = struct.unpack("%dB" % (len(data)), data)
|
92 | | -
|
93 | | - printout = title + ":\n"
|
94 | | - pointer = 0
|
95 | | - pointer2 = 0
|
96 | | -
|
97 | | - while (pointer < len(printout_temp)):
|
98 | | - pointer2 = 0
|
99 | | - if (showaddr): printout += "0x%08x " % (pointer)
|
100 | | - while (pointer2 < 0x10) and (pointer < len(printout_temp)):
|
101 | | - printout += ("%2x " % (printout_temp[pointer]))
|
102 | | - pointer += 1
|
103 | | - pointer2 += 1
|
104 | | - printout += "\n"
|
105 | | -
|
106 | | - if (pointer2 != 0x10):
|
107 | | - printout += "\n"
|
108 | | -
|
109 | | - return printout
|
| 49 | +class ReceiveError(Error):
|
| 50 | + pass
|
110 | 51 |
|
111 | | -
|
112 | | - @staticmethod
|
113 | | - def __getbulk(handle, endpoint, size):
|
114 | | - data = handle.bulkRead(endpoint, size, 1000)
|
115 | | - return struct.pack("%dB" % len(data), *data)
|
116 | 52 |
|
117 | | -
|
118 | | - @staticmethod
|
119 | | - def __checkstatus(data):
|
120 | | - errorcode = struct.unpack("<I", data[:4])[0]
|
121 | | - if errorcode == 1:
|
122 | | - # everything went fine
|
123 | | - return
|
124 | | - elif errorcode == 2:
|
125 | | - print("\nError: Device doesn't support this function!")
|
126 | | - raise Exception("emBIOS device doesn't support this function!")
|
127 | | - elif errorcode == 3:
|
128 | | - print("\nError: Device is busy!")
|
129 | | - raise Exception("emBIOS device is busy!")
|
130 | | - else:
|
131 | | - print("\nUnknown error %d" % errorcode)
|
132 | | - raise Exception("Unknown emBIOS error %d" % errorcode)
|
133 | | -
|
134 | | -
|
135 | | - @staticmethod
|
136 | | - def type2name(type):
|
137 | | - if type == 1: return "Debugger"
|
138 | | - else: return "UNKNOWN (0x%08x)" % type
|
139 | | -
|
140 | | -
|
141 | | - @staticmethod
|
142 | | - def devtype2name(devtype):
|
143 | | - if devtype == 0x47324e49: return "iPod Nano 2G"
|
144 | | - if devtype == 0x47334e49: return "iPod Nano 3G"
|
145 | | - if devtype == 0x47344e49: return "iPod Nano 4G"
|
146 | | - if devtype == 0x4c435049: return "iPod Classic"
|
147 | | - else: return "UNKNOWN (0x%08x)" % devtype
|
148 | | -
|
149 | | -
|
150 | | -#=====================================================================================
|
151 | | -
|
152 | | -
|
153 | | - def getinfo (self, infotype, silent = 0):
|
154 | | - if (infotype == "version"):
|
155 | | - self.handle.bulkWrite(self.__coutep, struct.pack("<IIII", 1, 0, 0, 0))
|
156 | | - response = self.__getbulk(self.handle, self.__cinep, 0x10)
|
157 | | - self.__checkstatus(response)
|
158 | | -
|
159 | | - i = struct.unpack("<IIBBBBI", response)
|
160 | | -
|
161 | | - self.svnrev, self.major, self.minor, self.patch, self.type, self.devtype = i[1:]
|
162 | | -
|
163 | | - self.__myprint("emBIOS %s v%d.%d.%d (SVN revision: %d) on %s, USB version %s\n" \
|
164 | | - % (self.type2name(self.type), self.major, self.minor, self.patch, self.svnrev, \
|
165 | | - self.devtype2name(self.devtype), self.dev.deviceVersion)\
|
166 | | - , silent)
|
167 | | -
|
168 | | - elif (infotype == "packetsize"):
|
169 | | - self.handle.bulkWrite(self.__coutep, struct.pack("<IIII", 1, 1, 0, 0))
|
170 | | - response = self.__getbulk(self.handle, self.__cinep, 0x10)
|
171 | | - self.__checkstatus(response)
|
172 | | -
|
173 | | - i = struct.unpack("<IHHII", response)
|
174 | | -
|
175 | | - self.cout_maxsize = i[1]
|
176 | | - self.cin_maxsize = i[2]
|
177 | | - self.dout_maxsize = i[3]
|
178 | | - self.din_maxsize = i[4]
|
179 | | -
|
180 | | - self.__myprint("Maximum packet sizes:\n Command out: %d bytes\n Command in: %d bytes\n Data out: %d bytes\n Data in: %d bytes\n" \
|
181 | | - % (self.cout_maxsize, self.cin_maxsize, self.dout_maxsize, self.din_maxsize)
|
182 | | - , silent)
|
183 | | -
|
184 | | - elif (infotype == "usermemrange"):
|
185 | | - self.handle.bulkWrite(self.__coutep, struct.pack("<IIII", 1, 1, 0, 0))
|
186 | | - response = self.__getbulk(self.handle, self.__cinep, 0x10)
|
187 | | - self.__checkstatus(response)
|
188 | | -
|
189 | | - i = struct.unpack("<IIII", response)
|
190 | | -
|
191 | | - self.usermem_lower = i[1]
|
192 | | - self.usermem_upper = i[2]
|
193 | | -
|
194 | | - self.__myprint("User memory range:\n Lower bound (inclusive): %x\n Upper bound (exclusive) %x\n" \
|
195 | | - % (self.usermem_lower, self.usermem_upper)
|
196 | | - , silent)
|
197 | | -
|
198 | | - else:
|
199 | | - self.__myprint("Unsupported type of info: %d" % (infotype))
|
200 | | -
|
201 | | -
|
202 | | - def reset(self, force, silent = 0):
|
203 | | - """ Resets the device.
|
204 | | - <force>: if 0, the reset will be gracefully, otherwise it will be forced.
|
205 | | - <silent>: if not 0, nothing will be printed to the console window
|
| 53 | +class Bunch(dict):
|
206 | 54 | """
|
207 | | - if (force == 0):
|
208 | | - force = 1
|
209 | | - else:
|
210 | | - force = 0
|
211 | | -
|
212 | | - self.__myprint("Resetting device...", silent)
|
213 | | - self.handle.bulkWrite(self.__coutep, struct.pack("<IIII", 2, force, 0, 0))
|
214 | | -
|
215 | | - if (force == 1):
|
216 | | - # reset not forced
|
217 | | - response = self.__getbulk(self.handle, self.__cinep, 0x10)
|
218 | | - self.__checkstatus(response)
|
219 | | -
|
220 | | - self.__myprint(" done\n", silent)
|
221 | | -
|
222 | | -
|
223 | | - def poweroff(self, force, silent = 0):
|
224 | | - """ Powers the device off.
|
225 | | - <force>: if 0, the poweroff will be gracefully, otherwise it will be forced.
|
226 | | - <silent>: if not 0, nothing will be printed to the console window
|
| 55 | + This is a dict whose items can also be accessed with
|
| 56 | + bunchinstance.something.
|
227 | 57 | """
|
228 | | - if (force == 0):
|
229 | | - force = 1
|
230 | | - else:
|
231 | | - force = 0
|
232 | | -
|
233 | | - self.__myprint("Powering device off...", silent)
|
234 | | - self.handle.bulkWrite(self.__coutep, struct.pack("<IIII", 3, force, 0, 0))
|
| 58 | + def __init__(self, **kw):
|
| 59 | + dict.__init__(self, kw)
|
| 60 | + self.__dict__ = self
|
235 | 61 |
|
236 | | - if (force == 1):
|
237 | | - # shutdown not forced
|
238 | | - response = self.__getbulk(self.handle, self.__cinep, 0x10)
|
239 | | - self.__checkstatus(response)
|
| 62 | + def __getstate__(self):
|
| 63 | + return self
|
240 | 64 |
|
241 | | - self.__myprint(" done\n", silent)
|
242 | | -
|
243 | | -
|
244 | | -#=====================================================================================
|
245 | | -
|
246 | | -
|
247 | | - def write(self, offset, data, usedma, freezesched, *range):
|
248 | | - boffset = 0
|
249 | | -
|
250 | | - size = len(data)
|
251 | | -
|
252 | | - if len(range) > 0:
|
253 | | - boffset = range[0]
|
254 | | - if len(range) > 1:
|
255 | | - size = range[1]
|
256 | | -
|
257 | | - if (size == 0):
|
258 | | - return
|
259 | | -
|
260 | | - # correct alignment
|
261 | | - while (offset & 0xF) != 0:
|
262 | | - blocklen = size
|
263 | | -
|
264 | | - if (blocklen > size):
|
265 | | - blocklen = size
|
266 | | - if (blocklen > self.cout_maxsize - 0x10):
|
267 | | - blocklen = self.cout_maxsize - 0x10
|
268 | | -
|
269 | | - blocklen = (blocklen & 0xFFFFFFF0) + (offset & 0xF)
|
270 | | -
|
271 | | - self.handle.bulkWrite(self.__coutep, struct.pack("<IIII", 5, offset, blocklen, 0) + data[boffset:boffset+blocklen])
|
272 | | - response = self.__getbulk(self.handle, self.__cinep, 0x10)
|
273 | | - self.__checkstatus(response)
|
274 | | -
|
275 | | - offset += blocklen
|
276 | | - boffset += blocklen
|
277 | | - size -= blocklen
|
| 65 | + def __setstate__(self, state):
|
| 66 | + self.update(state)
|
| 67 | + self.__dict__ = self
|
278 | 68 |
|
279 | | - # write data with DMA, if it makes sense (-> much data) and isn't forbidden
|
280 | | - if (usedma) and (size > 2 * (self.cout_maxsize - 16)):
|
281 | | - if (freezesched):
|
282 | | - self.freezescheduler(1, 0)
|
283 | | -
|
284 | | - while (size > (self.cout_maxsize - 16)):
|
285 | | - blocklen = size
|
286 | | -
|
287 | | - if (blocklen > self.dout_maxsize):
|
288 | | - blocklen = self.dout_maxsize
|
289 | | -
|
290 | | - self.handle.bulkWrite(self.__coutep, struct.pack("<IIII", 7, offset, blocklen, 0))
|
291 | | - response = self.__getbulk(self.handle, self.__cinep, 0x10)
|
292 | | - self.__checkstatus(response)
|
293 | | -
|
294 | | - self.handle.bulkWrite(self.__doutep, data[boffset:boffset+blocklen])
|
295 | | -
|
296 | | - offset += blocklen
|
297 | | - boffset += blocklen
|
298 | | - size -= blocklen
|
299 | | -
|
300 | | - if (freezesched):
|
301 | | - self.freezescheduler(0, 0)
|
302 | | -
|
303 | | - # write rest of data
|
304 | | - while (size > 0):
|
305 | | - blocklen = size
|
306 | | -
|
307 | | - if (blocklen > self.cout_maxsize - 0x10):
|
308 | | - blocklen = self.cout_maxsize - 0x10
|
309 | | -
|
310 | | - self.handle.bulkWrite(self.__coutep, struct.pack("<IIII", 5, offset, blocklen, 0) + data[boffset:boffset+blocklen])
|
311 | | - response = self.__getbulk(self.handle, self.__cinep, 0x10)
|
312 | | - self.__checkstatus(response)
|
313 | | -
|
314 | | - offset += blocklen
|
315 | | - boffset += blocklen
|
316 | | - size -= blocklen
|
317 | | -
|
318 | 69 |
|
319 | | - def read(self, offset, size, usedma, freezesched):
|
320 | | - if (size == 0):
|
321 | | - return
|
| 70 | +class Embios(object):
|
| 71 | + def __init__(self):
|
| 72 | + self.lib = Lib(self)
|
322 | 73 |
|
323 | | - data = ""
|
| 74 | + @staticmethod
|
| 75 | + def _alignsplit(addr, size, blksize, align):
|
| 76 | + end = addr + size
|
| 77 | + if addr & (align - 1):
|
| 78 | + bodyaddr = (addr + min(size, blksize)) & ~(align - 1)
|
| 79 | + else: bodyaddr = addr
|
| 80 | + headsize = bodyaddr - addr
|
| 81 | + if (size - headsize) & (align - 1):
|
| 82 | + tailaddr = (end - min(end - bodyaddr, blksize) + align - 1) & ~(align - 1)
|
| 83 | + else: tailaddr = end
|
| 84 | + tailsize = end - tailaddr
|
| 85 | + return (headsize, tailaddr - bodyaddr, tailsize)
|
324 | 86 |
|
325 | | - # correct alignment
|
326 | | - while (offset & 0xF) != 0:
|
327 | | - blocklen = size
|
328 | | -
|
329 | | - if (blocklen > size):
|
330 | | - blocklen = size
|
331 | | - if (blocklen > self.cin_maxsize - 0x10):
|
332 | | - blocklen = self.cin_maxsize - 0x10
|
333 | | -
|
334 | | - blocklen = (blocklen & 0xFFFFFFF0) + (offset & 0xF)
|
335 | | -
|
336 | | - self.handle.bulkWrite(self.__coutep, struct.pack("<IIII", 4, offset, blocklen, 0))
|
337 | | - response = self.__getbulk(self.handle, self.__cinep, 0x10 + blocklen)
|
338 | | - self.__checkstatus(response)
|
339 | | -
|
340 | | - data += response[0x10:]
|
341 | | -
|
342 | | - offset += blocklen
|
343 | | - size -= blocklen
|
344 | | -
|
345 | | - # read data with DMA, if it makes sense (-> much data) and isn't forbidden
|
346 | | - if (usedma) and (size > 2 * (self.cin_maxsize - 16)):
|
347 | | - if (freezesched):
|
348 | | - self.freezescheduler(1, 0)
|
349 | | -
|
350 | | - while (size > (self.cin_maxsize - 16)):
|
351 | | - blocklen = size
|
352 | | -
|
353 | | - if (blocklen > self.din_maxsize):
|
354 | | - blocklen = self.din_maxsize
|
355 | | -
|
356 | | - self.handle.bulkWrite(self.__coutep, struct.pack("<IIII", 6, offset, blocklen, 0))
|
357 | | - response = self.__getbulk(self.handle, self.__cinep, 0x10)
|
358 | | - self.__checkstatus(response)
|
359 | | -
|
360 | | - data += self.__getbulk(self.handle, self.__doutep, blocklen)
|
361 | | -
|
362 | | - offset += blocklen
|
363 | | - size -= blocklen
|
364 | | -
|
365 | | - if (freezesched):
|
366 | | - self.freezescheduler(0, 0)
|
367 | | -
|
368 | | - # read rest of data
|
369 | | - while (size > 0):
|
370 | | - blocklen = size
|
371 | | -
|
372 | | - if (blocklen > self.cin_maxsize - 0x10):
|
373 | | - blocklen = self.cin_maxsize - 0x10
|
| 87 | + def getversioninfo(self):
|
| 88 | + """ This returns the emBIOS version and device information. """
|
| 89 | + return self.lib.monitorcommand(struct.pack("IIII", 1, 0, 0, 0), "IBBBBI", ("revision", "majorv", "minorv", "patchv", "swtypeid", "hwtypeid"))
|
374 | 90 |
|
375 | | - self.handle.bulkWrite(self.__coutep, struct.pack("<IIII", 4, offset, blocklen, 0))
|
376 | | - response = self.__getbulk(self.handle, self.__cinep, 0x10 + blocklen)
|
377 | | - self.__checkstatus(response)
|
378 | | -
|
379 | | - data += response[0x10:]
|
380 | | -
|
381 | | - offset += blocklen
|
382 | | - size -= blocklen
|
383 | | -
|
384 | | - return data
|
385 | | -
|
386 | | -
|
387 | | - def uploadfile(self, offset, file, usedma = 1, freezesched = 0, silent = 0):
|
388 | | - self.__myprint("Uploading %s to 0x%08x..." % (file, offset), silent)
|
389 | | - f = open(file, "rb")
|
390 | | -
|
391 | | - while True:
|
392 | | - data = f.read(262144)
|
393 | | - if data == "": break
|
394 | | - self.write(offset, data, usedma, freezesched)
|
395 | | - offset += len(data)
|
396 | | - self.__myprint(".")
|
397 | | -
|
398 | | - self.__myprint(" done\n", silent)
|
| 91 | + def getpacketsizeinfo(self):
|
| 92 | + """ This returns the emBIOS max packet size information.
|
| 93 | + It also sets the properties of the device object accordingly.
|
| 94 | + """
|
| 95 | + resp = self.lib.monitorcommand(struct.pack("IIII", 1, 1, 0, 0), "HHII", ("coutmax", "cinmax", "doutmax", "dinmax"))
|
| 96 | + self.lib.dev.packetsizelimit['cout'] = resp.coutmax
|
| 97 | + self.lib.dev.packetsizelimit['cin'] = resp.cinmax
|
| 98 | + self.lib.dev.packetsizelimit['din'] = resp.dinmax
|
| 99 | + self.lib.dev.packetsizelimit['dout'] = resp.doutmax
|
| 100 | + return resp
|
399 | 101 |
|
400 | | -
|
401 | | - def downloadfile(self, offset, size, file, usedma = 1, freezesched = 0, silent = 0):
|
402 | | - self.__myprint("Downloading 0x%x bytes from 0x%08x to %s..." % (size, offset, file), silent)
|
403 | | - f = open(file, "wb")
|
404 | | -
|
405 | | - while True:
|
406 | | - blocklen = size
|
407 | | - if blocklen == 0: break
|
408 | | - if blocklen > 262144: blocklen = 262144
|
409 | | - f.write(self.read(offset, blocklen, usedma, freezesched))
|
410 | | - offset += blocklen
|
411 | | - size -= blocklen
|
412 | | - self.__myprint(".")
|
413 | | -
|
414 | | - self.__myprint(" done\n", silent)
|
| 102 | + def getusermemrange(self):
|
| 103 | + """ This returns the memory range the user has access to. """
|
| 104 | + return self.lib.monitorcommand(struct.pack("IIII", 1, 2, 0, 0), "III", ("lower", "upper", None))
|
415 | 105 |
|
| 106 | + def reset(self, force=False):
|
| 107 | + """ Reboot the device """
|
| 108 | + if force:
|
| 109 | + return self.lib.monitorcommand(struct.pack("IIII", 2, 0, 0, 0))
|
| 110 | + else:
|
| 111 | + return self.lib.monitorcommand(struct.pack("IIII", 2, 1, 0, 0), "III", (None, None, None))
|
416 | 112 |
|
417 | | - def uploadint(self, offset, data, silent = 0):
|
418 | | - self.__myprint("Uploading 0x%08x to 0x%08x..." % (data, offset), silent)
|
419 | | - data = struct.pack('<I', data)
|
420 | | - self.write(offset, data, 0, 0)
|
421 | | - self.__myprint(" done\n", silent)
|
422 | | -
|
423 | | -
|
424 | | - def downloadint(self, offset, silent = 0):
|
425 | | - self.__myprint("Downloading an integer from 0x%08x..." % (offset), silent)
|
426 | | - data = self.read(offset, 4, 0, 0)
|
427 | | - number = struct.unpack('<I', data)
|
428 | | - self.__myprint(" done\nValue was: 0x%08x\n" % (number), silent)
|
| 113 | + def poweroff(self, force=False):
|
| 114 | + """ Powers the device off. """
|
| 115 | + if force:
|
| 116 | + return self.lib.monitorcommand(struct.pack("IIII", 3, 0, 0, 0))
|
| 117 | + else:
|
| 118 | + return self.lib.monitorcommand(struct.pack("IIII", 3, 1, 0, 0), "III", (None, None, None))
|
429 | 119 |
|
430 | | - return data
|
| 120 | + def read(self, addr, size):
|
| 121 | + """ Reads the memory from location 'addr' with size 'size'
|
| 122 | + from the device. This cares about too long packages
|
| 123 | + and decides whether to use DMA or not.
|
| 124 | + """
|
| 125 | + if not self.lib.connected:
|
| 126 | + self.lib.connect()
|
| 127 | + cin_maxsize = self.lib.dev.packetsizelimit["cin"] - 0x10
|
| 128 | + din_maxsize = self.lib.dev.packetsizelimit["din"]
|
| 129 | + data = ""
|
| 130 | + (headsize, bodysize, tailsize) = self._alignsplit(addr, size, cin_maxsize, 16)
|
| 131 | + if headsize != 0:
|
| 132 | + data += self.readmem(addr, headsize)
|
| 133 | + addr += headsize
|
| 134 | + while bodysize > 0:
|
| 135 | + if bodysize >= 2 * cin_maxsize:
|
| 136 | + readsize = min(bodysize, din_maxsize)
|
| 137 | + data += self.readdma(addr, readsize)
|
| 138 | + else:
|
| 139 | + readsize = min(bodysize, cin_maxsize)
|
| 140 | + data += self.readmem(addr, readsize)
|
| 141 | + addr += readsize
|
| 142 | + bodysize -= readsize
|
| 143 | + if tailsize != 0:
|
| 144 | + data += self.readmem(addr, tailsize)
|
| 145 | + return data
|
431 | 146 |
|
| 147 | + def write(self, addr, data):
|
| 148 | + """ Writes the data in 'data' to the location 'addr'
|
| 149 | + in the memory of the device. This cares about too long packages
|
| 150 | + and decides whether to use DMA or not.
|
| 151 | + """
|
| 152 | + if not self.lib.connected:
|
| 153 | + self.lib.connect()
|
| 154 | + cout_maxsize = self.lib.dev.packetsizelimit["cout"] - 0x10
|
| 155 | + dout_maxsize = self.lib.dev.packetsizelimit["dout"]
|
| 156 | + (headsize, bodysize, tailsize) = self._alignsplit(addr, len(data), cout_maxsize, 16)
|
| 157 | + offset = 0
|
| 158 | + if headsize != 0:
|
| 159 | + self.writemem(addr, headsize)
|
| 160 | + offset += headsize
|
| 161 | + addr += headsize
|
| 162 | + while bodysize > 0:
|
| 163 | + if bodysize >= 2 * cout_maxsize:
|
| 164 | + writesize = min(bodysize, dout_maxsize)
|
| 165 | + self.writedma(addr, data[offset:offset+writesize])
|
| 166 | + else:
|
| 167 | + writesize = min(bodysize, cout_maxsize)
|
| 168 | + self.writemem(addr, data[offset:offset+writesize])
|
| 169 | + offset += writesize
|
| 170 | + addr += writesize
|
| 171 | + bodysize -= writesize
|
| 172 | + if tailsize != 0:
|
| 173 | + self.writemem(addr, data[offset:offset+tailsize])
|
| 174 | + return data
|
432 | 175 |
|
433 | | -#=====================================================================================
|
| 176 | + def readmem(self, addr, size):
|
| 177 | + """ Reads the memory from location 'addr' with size 'size'
|
| 178 | + from the device.
|
| 179 | + """
|
| 180 | + resp = self.lib.monitorcommand(struct.pack("IIII", 4, addr, size, 0), "III%ds" % size, (None, None, None, "data"))
|
| 181 | + return resp.data
|
| 182 | +
|
| 183 | + def writemem(self, addr, data):
|
| 184 | + """ Writes the data in 'data' to the location 'addr'
|
| 185 | + in the memory of the device.
|
| 186 | + """
|
| 187 | + return self.lib.monitorcommand(struct.pack("IIII%ds" % len(data), 5, addr, len(data), 0, data), "III", (None, None, None))
|
434 | 188 |
|
| 189 | + def readdma(self, addr, size):
|
| 190 | + """ Reads the memory from location 'addr' with size 'size'
|
| 191 | + from the device. This uses DMA and the data in endpoint.
|
| 192 | + """
|
| 193 | + self.lib.monitorcommand(struct.pack("IIII", 6, addr, size, 0), "III", (None, None, None))
|
| 194 | + return struct.unpack("%ds" % size, self.lib.dev.din(size))[0]
|
435 | 195 |
|
436 | | - def i2crecv(self, bus, slave, addr, size, silent = 0):
|
437 | | - if (size > self.cin_maxsize - 0x10) or (size > 0xFF):
|
438 | | - raise Exception ("The data exceeds the maximum amount that can be received with this instruction.")
|
439 | | -
|
440 | | - self.__myprint("Reading 0x%2x bytes from 0x%2x at I2C device at bus 0x%2x, slave adress 0x%2x ..." % (size, addr, bus, slave), silent)
|
| 196 | + def writedma(self, addr, data):
|
| 197 | + """ Writes the data in 'data' to the location 'addr'
|
| 198 | + in the memory of the device. This uses DMA and the data out endpoint.
|
| 199 | + """
|
| 200 | + self.lib.monitorcommand(struct.pack("IIII", 7, addr, len(data), 0), "III", (None, None, None))
|
| 201 | + return self.lib.dev.dout(data)
|
441 | 202 |
|
442 | | - self.handle.bulkWrite(self.__coutep, struct.pack("<IBBBBII", 8, bus, slave, addr, size, 0, 0))
|
443 | | - data = self.__getbulk(self.handle, self.__cinep, 0x10 + size)
|
444 | | - self.__checkstatus(response)
|
| 203 | + def i2cread(self, index, slaveaddr, startaddr, size):
|
| 204 | + """ Reads data from an i2c slave """
|
445 | 205 |
|
446 | | - self.__myprint(" done\n data was:\n%s\n" % (self.__gethexviewprintout(data[16:])), silent)
|
| 206 | + def i2cwrite(self, index, slaveaddr, startaddr, data):
|
| 207 | + """ Writes data to an i2c slave """
|
447 | 208 |
|
448 | | - return data[16:]
|
449 | | -
|
450 | | -
|
451 | | - def i2csend(self, bus, slave, addr, data, silent = 0):
|
452 | | - size = len(data)
|
453 | | - if (size > self.cout_maxsize - 0x10) or (size > 0xFF):
|
454 | | - raise Exception ("The data exceeds the maximum amount that can be send with this instruction.")
|
455 | | -
|
456 | | - self.__myprint("Writing 0x%2x bytes to 0x%2x at I2C device at bus 0x%2x, slave adress 0x%2x ..." % (size, addr, bus, slave), silent)
|
457 | | -
|
458 | | - self.handle.bulkWrite(self.__coutep, struct.pack("<IBBBBII", 9, bus, slave, addr, size, 0, 0) + data)
|
459 | | - response = self.__getbulk(self.handle, self.__cinep, 0x10)
|
460 | | - self.__checkstatus(response)
|
| 209 | + def usbcread(self, size):
|
| 210 | + """ Reads data with size 'size' from the USB console """
|
461 | 211 |
|
462 | | - self.__myprint(" done\n", silent)
|
| 212 | + def usbcwrite(self, data):
|
| 213 | + """ Writes data to the USB console """
|
463 | 214 |
|
464 | | -
|
465 | | -#=====================================================================================
|
| 215 | + def cread(self, size, bitmask):
|
| 216 | + """ Reads data with the specified size from the device consoles
|
| 217 | + identified with the specified bitmask
|
| 218 | + """
|
466 | 219 |
|
467 | | - def readusbcon(self, size, outtype = "", file = "", silent = 0):
|
468 | | - """ reads from USB console
|
469 | | - <size>: number of bytes to be read, if its length exceeds the Command In endpoint packet size - 0x10, it will be read in several steps
|
470 | | - <outtype>: how the data will be put out
|
471 | | - "file" => writes data to file <file>
|
472 | | - "printstring" => prints data as a string to the console window
|
473 | | - "printhex" => prints a hexview view of the data to the console window
|
474 | | - "" => only returns the data
|
475 | | - <silent>: if 0, nothing will be written to the console window (even if <outtype> defines something else)
|
476 | | -
|
477 | | - in every case, the data will be returned in an array with additional information
|
478 | | - [len, buffersize, datainbuffer, data]
|
479 | | - where len is the length of the data actually read,
|
480 | | - buffersize is the on-device read buffer size,
|
481 | | - datainbuffer is the number of bytes still left in the on device buffer,
|
482 | | - data is the actual data
|
483 | | -
|
484 | | - in case that within 5 secs, it's not possible to read <size> bytes, a timeout will occur
|
485 | | - """
|
486 | | - out_data = ""
|
487 | | - readbytes = 0
|
488 | | - buffersize = 0
|
489 | | - bytesleft = 0
|
490 | | - timeoutcounter = 0
|
| 220 | + def cwrite(self, data):
|
| 221 | + """ Writes data to the device consoles
|
| 222 | + identified with the specified bitmask.
|
| 223 | + """
|
491 | 224 |
|
492 | | - self.__myprint("Reading 0x%x bytes from USB console..." % (size), silent)
|
| 225 | + def cflush(self, bitmask):
|
| 226 | + """ Flushes the consoles specified with 'bitmask' """
|
| 227 | + return self.lib.monitorcommand(struct.pack("IIII", 14, bitmask, 0, 0), "III", (None, None, None))
|
493 | 228 |
|
494 | | - while size > 0 and timoutcounter < 50:
|
495 | | - blocklen = size
|
496 | | -
|
497 | | - if size > self.cin_maxsize - 0x10:
|
498 | | - blocklen = self.cin_maxsize - 0x10
|
499 | | -
|
500 | | - self.handle.bulkWrite(self.__coutep, struct.pack("<IIII", 10, blocklen, 0, 0))
|
501 | | - response = self.__getbulk(self.handle, self.__cinep, blocklen + 0x10)
|
502 | | - self.__checkstatus(response)
|
503 | | -
|
504 | | - readbytes, buffersize, bytesleft = struct.unpack("<III", response[4:])
|
505 | | - out_data += response[0x10:0x10+readbytes]
|
506 | | - size -= blocklen
|
507 | | -
|
508 | | - if not bytesleft > 0: # no data left to read => wait a bit and prevent an infinite loop trying to read data when there is none
|
509 | | - timeoutcounter += 1
|
510 | | - time.sleep(0.1)
|
511 | | - else:
|
512 | | - timeoutcounter -= 3
|
513 | | - if timeoutcounter < 0:
|
514 | | - timeoutcounter = 0
|
515 | | -
|
516 | | - self.__myprint(" done\n", silent)
|
517 | | - self.__myprint("\nBytes read: 0x%x\nOn-device buffersize: 0x%x\nBytes still in device's buffer: 0x%x\n\n"\
|
518 | | - % (len(out_data), buffersize, bytesleft)
|
519 | | - , silent)
|
| 229 | + def getprocinfo(self, offset, size):
|
| 230 | + """ Gets current state of the scheduler """
|
520 | 231 |
|
521 | | - if (outtype == "file"):
|
522 | | - f = open(file, "wb")
|
523 | | - f.write(out_data)
|
524 | | -
|
525 | | - elif (outtype == "printstring"):
|
526 | | - self.__myprint(out_data, silent)
|
527 | | - self.__myprint("\n\n", silent)
|
528 | | -
|
529 | | - elif (outtype == "printhex"):
|
530 | | - self.__myprint(self.__gethexviewprintout(out_data, "", 1), silent)
|
531 | | - self.__myprint("\n\n", silent)
|
| 232 | + def freezescheduler(self, freeze=True):
|
| 233 | + """ Freezes/Unfreezes the scheduler """
|
| 234 | + return self.lib.monitorcommand(struct.pack("IIII", 16, 1 if freeze else 0, 0, 0), "III", ("before", None, None))
|
532 | 235 |
|
533 | | - elif (outtype == ""):
|
534 | | - pass # return only
|
535 | | -
|
536 | | - else:
|
537 | | - raise Exception ("Invalid argument for <outtype>: '%s'." % (outtype))
|
| 236 | + def unfreezescheduler(self):
|
| 237 | + """ Unfreezes the scheduler """
|
| 238 | + return self.lib.monitorcommand(struct.pack("IIII", 16, 0, 0, 0), "III", ("before", None, None))
|
538 | 239 |
|
539 | | - return [len(out_data), buffersize, bytesleft, out_data]
|
| 240 | + def suspendthread(self, id, suspend=True):
|
| 241 | + """ Suspends the thread with the specified id """
|
| 242 | + return self.lib.monitorcommand(struct.pack("IIII", 17, 1 if suspend else 0, id, 0), "III", ("before", None, None))
|
540 | 243 |
|
| 244 | + def unsuspendthread(self, id):
|
| 245 | + """ Suspends the thread with the specified id """
|
| 246 | + return self.lib.monitorcommand(struct.pack("IIII", 17, 0, id, 0), "III", ("before", None, None))
|
541 | 247 |
|
542 | | - def writeusbcon(self, data, silent = 0, *range):
|
543 | | - """ writes to USB console
|
544 | | - <data>: the data to be written
|
545 | | - <range>: the range in <data> that should be written, in the from [offset, length]
|
546 | | - <silent>: if 0, nothing will be written to the console window
|
547 | | -
|
548 | | - if the data to be written exceeds the Command Out endpoint packet size - 0x10, it will be written in several steps
|
549 | | - """
|
550 | | - size = len(data)
|
551 | | - boffset = 0
|
| 248 | + def killthread(self, id):
|
| 249 | + """ Kills the thread with the specified id """
|
| 250 | + return self.lib.monitorcommand(struct.pack("IIII", 18, id, 0, 0), "III", ("before", None, None))
|
552 | 251 |
|
553 | | - if len(range) > 0:
|
554 | | - boffset = range[0]
|
555 | | - if len(range) > 1:
|
556 | | - size = range[1]
|
| 252 | + def createthread(self, nameptr, entrypoint, stackptr, stacksize, threadtype, priority, state):
|
| 253 | + """ Creates a thread with the specified attributes """
|
| 254 | + if threadtype == "user":
|
| 255 | + threadtype = 0
|
| 256 | + elif threadtype == "system":
|
| 257 | + threadtype = 1
|
| 258 | + else:
|
| 259 | + raise SyntaxError("Threadtype must be either 'system' or 'user'")
|
| 260 | + if priority > 256 or priority < 0:
|
| 261 | + raise SyntaxError("Priority must be a number between 0 and 256")
|
| 262 | + if state == "ready":
|
| 263 | + state = 0
|
| 264 | + elif state == "suspended":
|
| 265 | + state = 1
|
| 266 | + else:
|
| 267 | + raise SyntaxError("State must be either 'ready' or 'suspended'")
|
| 268 | + resp = self.lib.monitorcommand(struct.pack("IIIIIIII", 19, nameptr, entrypoint, stackptr, stacksize, threadtype, priority, state), "III", (id, None, None))
|
| 269 | + if resp.id < 0:
|
| 270 | + raise DeviceError("The device returned the error code "+str(resp.id))
|
| 271 | + return resp
|
557 | 272 |
|
558 | | - self.__myprint("Writing 0x%x bytes to USB console..." % (size), silent)
|
| 273 | + def flushcpucache(self):
|
| 274 | + """ Flushes the CPU instruction and data cache """
|
| 275 | + return self.lib.monitorcommand(struct.pack("IIII", 20, 0, 0, 0), "III", (None, None, None))
|
559 | 276 |
|
560 | | - timeoutcounter = 0
|
| 277 | + def run(self, addr):
|
| 278 | + """ Runs the emBIOS app at 'addr' """
|
| 279 | + return self.lib.monitorcommand(struct.pack("IIII", 21, addr, 0, 0), "III", ("excecimage", None, None))
|
561 | 280 |
|
562 | | - while (size > 0) and (timeoutcounter < 50):
|
563 | | - blocklen = size
|
564 | | - if blocklen > self.cout_maxsize - 0x10:
|
565 | | - blocklen = self.cout_maxsize - 0x10
|
| 281 | + def bootflashread(self, memaddr, flashaddr, size):
|
| 282 | + """ Copies the data in the bootflash at 'flashaddr' of the specified size
|
| 283 | + to the memory at addr 'memaddr'
|
| 284 | + """
|
566 | 285 |
|
567 | | - self.handle.bulkWrite(self.__coutep, struct.pack("<IIII", 11, size, 0, 0) + data[boffset:boffset+blocklen])
|
568 | | - response = self.__getbulk(self.handle, self.__cinep, 0x10)
|
569 | | - self.__checkstatus(response)
|
570 | | -
|
571 | | - sendbytes = struct.unpack("<I", response[4:])[0]
|
572 | | - if sendbytes < blocklen: # not everything has been written, need to resent some stuff but wait a bit before doing so
|
573 | | - time.sleep(0.1)
|
574 | | - timeoutcounter += 1
|
575 | | - elif timeoutcounter > 0: # lower timeoutcounter again
|
576 | | - timeoutcounter -= 3
|
577 | | - if timeoutcounter < 0:
|
578 | | - timeoutcounter = 0
|
579 | | -
|
580 | | - size -= sendbytes
|
581 | | - boffset += sendbytes
|
582 | | -
|
583 | | -
|
584 | | - if (timeoutcounter >=50):
|
585 | | - raise Exception("Timeout, 0x%x bytes couldn't be send." % size)
|
| 286 | + def bootflashwrite(self, memaddr, flashaddr, size):
|
| 287 | + """ Copies the data in the memory at 'memaddr' of the specified size
|
| 288 | + to the boot flash at addr 'flashaddr'
|
| 289 | + """
|
586 | 290 |
|
587 | | - self.__myprint(" done\n", silent)
|
| 291 | + def execfirmware(self, addr):
|
| 292 | + """ Executes the firmware at 'addr' and passes all control to it. """
|
| 293 | + return self.lib.monitorcommand(struct.pack("IIII", 24, addr, 0, 0), "III", (None, None, None))
|
588 | 294 |
|
589 | | - return size # number of bytes that have not been sent
|
| 295 | + def aesencrypt(self, addr, size, keyindex):
|
| 296 | + """ Encrypts the buffer at 'addr' with the specified size
|
| 297 | + with the hardware AES key index 'keyindex'
|
| 298 | + """
|
| 299 | + return self.lib.monitorcommand(struct.pack("IBBHII", 25, 1, 0, keyindex, addr, size), "III", (None, None, None))
|
590 | 300 |
|
591 | | -
|
592 | | - def readdevcon(self, bitmask, size, outtype = "", file = "", silent = 0):
|
593 | | - """ reads from one or more of the device's consoles
|
594 | | - <bitmask>: bitmask of consoles to be read from
|
595 | | - <size>: number of bytes to be read, if its length exceeds the Command In endpoint packet size - 0x10, it will be read in several steps
|
596 | | - <outtype>: how the data will be put out
|
597 | | - "file" => writes data to file <file>
|
598 | | - "printstring" => prints data as a string to the console window
|
599 | | - "printhex" => prints a hexview view of the data to the console window
|
600 | | - "" => only returns the data
|
601 | | - <silent>: if 0, nothing will be written to the console window (even if <outtype> defines something else)
|
602 | | -
|
603 | | - in every case, the data will be returned
|
604 | | -
|
605 | | - in case that within 5 secs, it's not possible to read <size> bytes, a timeout will occur
|
606 | | - """
|
607 | | - out_data = ""
|
608 | | - readbytes = 0
|
609 | | - timeoutcounter = 0
|
| 301 | + def aesdecrypt(self, addr, size, keyindex):
|
| 302 | + """ Decrypts the buffer at 'addr' with the specified size
|
| 303 | + with the hardware AES key index 'keyindex'
|
| 304 | + """
|
| 305 | + return self.lib.monitorcommand(struct.pack("IBBHII", 25, 0, 0, keyindex, addr, size), "III", (None, None, None))
|
610 | 306 |
|
611 | | - self.__myprint("Reading 0x%x bytes from device's console(s)..." % (size), silent)
|
612 | | -
|
613 | | - while size > 0 and timoutcounter < 50:
|
614 | | - blocklen = size
|
615 | | -
|
616 | | - if size > self.cin_maxsize - 0x10:
|
617 | | - blocklen = self.cin_maxsize - 0x10
|
618 | | -
|
619 | | - self.handle.bulkWrite(self.__coutep, struct.pack("<IIII", 13, bitmask, blocklen, 0))
|
620 | | - response = self.__getbulk(self.handle, self.__cinep, blocklen + 0x10)
|
621 | | - self.__checkstatus(response)
|
622 | | -
|
623 | | - readbytes = struct.unpack("<III", response[4:])[0]
|
624 | | - out_data += response[0x10:0x10+readbytes]
|
625 | | - size -= blocklen
|
626 | | -
|
627 | | - if not readbytes > 0: # no data read => wait a bit and prevent an infinite loop trying to read data when there is none
|
628 | | - timeoutcounter += 1
|
629 | | - time.sleep(0.1)
|
630 | | - else:
|
631 | | - timeoutcounter -= 3
|
632 | | - if timeoutcounter < 0:
|
633 | | - timeoutcounter = 0
|
634 | | -
|
635 | | - self.__myprint(" done\n", silent)
|
636 | | - self.__myprint("\nBytes read: 0x%x\n\n" % (len(out_data)), silent)
|
637 | | -
|
638 | | - if (outtype == "file"):
|
639 | | - f = open(file, "wb")
|
640 | | - f.write(out_data)
|
641 | | -
|
642 | | - elif (outtype == "printstring"):
|
643 | | - self.__myprint(out_data, silent)
|
644 | | - self.__myprint("\n\n", silent)
|
645 | | -
|
646 | | - elif (outtype == "printhex"):
|
647 | | - self.__myprint(self.__gethexviewprintout(out_data, "", 1), silent)
|
648 | | - self.__myprint("\n\n", silent)
|
649 | | -
|
650 | | - elif (outtype == ""):
|
651 | | - pass # return only
|
652 | | -
|
653 | | - else:
|
654 | | - raise Exception ("Invalid argument for <outtype>: '%s'." % (outtype))
|
655 | | -
|
656 | | - return out_data
|
657 | | -
|
658 | | -
|
659 | | - def writedevcon(self, bitmask, data, silent = 0, *range):
|
660 | | - """ writes to USB console
|
661 | | - <bitmask>: bitmask of consoles to be written to
|
662 | | - <data>: the data to be written
|
663 | | - <range>: the range in <data> that should be written, in the from [offset, length]
|
664 | | - <silent>: if 0, nothing will be written to the console window
|
665 | | -
|
666 | | - if the data to be written exceeds the Command Out endpoint packet size - 0x10, it will be written in several steps
|
667 | | - """
|
668 | | - size = len(data)
|
669 | | - boffset = 0
|
670 | | -
|
671 | | - if len(range) > 0:
|
672 | | - boffset = range[0]
|
673 | | - if len(range) > 1:
|
674 | | - size = range[1]
|
675 | | -
|
676 | | - self.__myprint("Writing 0x%x bytes to device's console(s)..." % (size), silent)
|
677 | | -
|
678 | | - timeoutcounter = 0
|
679 | | -
|
680 | | - while size > 0:
|
681 | | - blocklen = size
|
682 | | - if blocklen > self.cout_maxsize - 0x10:
|
683 | | - blocklen = self.cout_maxsize - 0x10
|
684 | | -
|
685 | | - self.handle.bulkWrite(self.__coutep, struct.pack("<IIII", 12, bitmask, size, 0) + data[boffset:boffset+blocklen])
|
686 | | - response = self.__getbulk(self.handle, self.__cinep, 0x10)
|
687 | | - self.__checkstatus(response)
|
688 | | -
|
689 | | - size -= blocklen
|
690 | | - boffset += blocklen
|
691 | | -
|
692 | | - self.__myprint(" done\n", silent)
|
693 | | -
|
694 | | -
|
695 | | - def flushconsolebuffers(self, bitmask, silent = 0):
|
696 | | - self.__myprint("Flushing device console('s) buffer('s)...")
|
697 | | -
|
698 | | - self.handle.bulkWrite(self.__coutep, struct.pack("<IIII", 14, bitmask, 0, 0))
|
699 | | - response = self.__getbulk(self.handle, self.__cinep, 0x10)
|
700 | | - self.__checkstatus(response)
|
701 | | -
|
702 | | - self.__myprint(" done\n")
|
| 307 | + def hmac_sha1(self, addr, size, destination):
|
| 308 | + """ Generates a HMAC-SHA1 hash of the buffer and saves it to 'destination' """
|
| 309 | + return self.lib.monitorcommand(struct.pack("IIII", 26, addr, size, destination), "III", (None, None, None))
|
703 | 310 |
|
704 | | -
|
705 | | -#=====================================================================================
|
706 | 311 |
|
707 | | -
|
708 | | - def freezescheduler(self, freeze, silent = 0):
|
709 | | - if (freeze):
|
710 | | - self.__myprint("Freezing scheduler...", silent)
|
711 | | - freeze = 1
|
712 | | - else:
|
713 | | - self.__myprint("Unfreezing scheduler...", silent)
|
714 | | - freeze = 0
|
715 | | -
|
716 | | - self.handle.bulkWrite(self.__coutep, struct.pack("<IIII", 16, freeze, 0, 0))
|
717 | | - response = self.__getbulk(self.handle, self.__cinep, 0x10)
|
718 | | - self.__checkstatus(response)
|
| 312 | +class Lib(object):
|
| 313 | + def __init__(self, embios):
|
| 314 | + self.idVendor = 0xFFFF
|
| 315 | + self.idProduct = 0xE000
|
| 316 | +
|
| 317 | + self.embios = embios
|
| 318 | + self.connected = False
|
719 | 319 |
|
720 | | - self.__myprint(" done\n", silent)
|
| 320 | + def connect(self):
|
| 321 | + self.dev = Dev(self.idVendor, self.idProduct)
|
| 322 | + self.connected = True
|
| 323 | + self.embios.getpacketsizeinfo()
|
721 | 324 |
|
722 | | -
|
723 | | - def suspendthread(self, suspend, threadid, silent = 0):
|
724 | | - if (suspend):
|
725 | | - self.__myprint("Suspending thread 0x%08x..." % threadid, silent)
|
726 | | - suspend = 1
|
727 | | - else:
|
728 | | - self.__myprint("Unsuspending thread 0x%08x..." % threadid, silent)
|
729 | | - suspend = 0
|
730 | | -
|
731 | | - self.handle.bulkWrite(self.__coutep, struct.pack("<IIII", 17, suspend, threadid, 0))
|
732 | | - response = self.__getbulk(self.handle, self.__cinep, 0x10)
|
733 | | - self.__checkstatus(response)
|
734 | | -
|
735 | | - self.__myprint(" done\n", silent)
|
| 325 | + def monitorcommand(self, cmd, rcvdatatypes=None, rcvstruct=None):
|
| 326 | + if not self.connected:
|
| 327 | + self.connect()
|
| 328 | + self.dev.cout(cmd)
|
| 329 | + if rcvdatatypes:
|
| 330 | + rcvdatatypes = "I" + rcvdatatypes # add the response
|
| 331 | + data = self.dev.cin(struct.calcsize(rcvdatatypes))
|
| 332 | + data = struct.unpack(rcvdatatypes, data)
|
| 333 | + response = data[0]
|
| 334 | + if libembiosdata.responsecodes[response] == "ok":
|
| 335 | + if rcvstruct:
|
| 336 | + datadict = Bunch()
|
| 337 | + counter = 1 # start with 1, 0 is the id
|
| 338 | + for item in rcvstruct:
|
| 339 | + if item != None: # else the data is undefined
|
| 340 | + datadict[item] = data[counter]
|
| 341 | + counter += 1
|
| 342 | + return datadict
|
| 343 | + else:
|
| 344 | + return data
|
| 345 | + elif libembiosdata.responsecodes[response] == "unsupported":
|
| 346 | + raise DeviceError("The device does not support this command.")
|
| 347 | + elif libembiosdata.responsecodes[response] == "invalid":
|
| 348 | + raise DeviceError("Invalid command! This should NOT happen!")
|
| 349 | + elif libembiosdata.responsecodes[response] == "busy":
|
| 350 | + raise DeviceError("Device busy")
|
736 | 351 |
|
737 | 352 |
|
738 | | - def killthread(self, threadid, silent = 0):
|
739 | | - self.__myprint("Killing thread 0x%08x..." % threadid, silent)
|
740 | | -
|
741 | | - self.handle.bulkWrite(self.__coutep, struct.pack("<IIII", 18, threadid, 0, 0))
|
742 | | - response = self.__getbulk(self.handle, self.__cinep, 0x10)
|
743 | | - self.__checkstatus(response)
|
744 | | -
|
745 | | - self.__myprint(" done\n", silent)
|
746 | | -
|
747 | | -
|
748 | | - def createthread(self, namepointer, entrypoint, stackpointer, stacksize, type, priority, state, silent = 0):
|
749 | | - self.__myprint("Creating thread...", silent)
|
750 | | -
|
751 | | - self.handle.bulkWrite(self.__coutep, struct.pack("<IIIIIIII", 19, namepointer, entrypoint, stackpointer, stacksize, type, priority, state))
|
752 | | - response = self.__getbulk(self.handle, self.__cinep, 0x10)
|
753 | | - self.__checkstatus(response)
|
754 | | -
|
755 | | - if (struct.unpack("<i", response[4:8])[0] < 0):
|
756 | | - self.__myprint(" failed, error code: 0x%x" % (struct.unpack("<i", response[4:8])[0]), silent)
|
757 | | - else:
|
758 | | - self.__myprint(" done\n, thread ID: 0x%x" % (struct.unpack("<I", response[4:8])[0]), silent)
|
759 | | -
|
760 | | -
|
761 | | - def getprocinfo(self, silent = 0):
|
762 | | - """
|
763 | | - printout on console window:
|
764 | | - <silent> = 0: Process information struct version, Process information table size
|
765 | | - <silent> = 1: nothing
|
766 | | - """
|
767 | | - # inline functions ----------------------------------------------
|
768 | | - def procinfotolist(processinfo, structver):
|
769 | | - if (structver == 1): # Process information struct version == 1
|
770 | | - ptr = 0
|
771 | | - process_n = 0
|
772 | | - retval = []
|
773 | | - while ptr < len(processinfo):
|
774 | | - if struct.unpack("<I", processinfo[ptr + 68:ptr + 72])[0] == 0: # THREAD_FREE
|
775 | | - ptr += 120
|
776 | | - process_n += 1
|
777 | | - continue
|
778 | | -
|
779 | | - retval.append({})
|
780 | | -
|
781 | | - retval[process_n]['regs'] = struct.unpack("<IIIIIIIIIIIIIIII", processinfo[ptr:ptr + 64])
|
782 | | - ptr += 16 * 0x4
|
783 | | - retval[process_n]['cpsr'] = struct.unpack("<I", processinfo[ptr:ptr + 4])[0]
|
784 | | - ptr += 1 * 0x4
|
785 | | - retval[process_n]['state'] = struct.unpack("<I", processinfo[ptr:ptr + 4])[0]
|
786 | | - ptr += 1 * 0x4
|
787 | | - retval[process_n]['name_ptr'] = struct.unpack("<I", processinfo[ptr:ptr + 4])[0]
|
788 | | - ptr += 1 * 0x4
|
789 | | - retval[process_n]['cputime_current'] = struct.unpack("<I", processinfo[ptr:ptr + 4])[0]
|
790 | | - ptr += 1 * 0x4
|
791 | | - retval[process_n]['cputime_total'] = struct.unpack("<Q", processinfo[ptr:ptr + 8])[0]
|
792 | | - ptr += 1 * 0x8
|
793 | | - retval[process_n]['startusec'] = struct.unpack("<I", processinfo[ptr:ptr + 4])[0]
|
794 | | - ptr += 1 * 0x4
|
795 | | - retval[process_n]['queue_next_ptr'] = struct.unpack("<I", processinfo[ptr:ptr + 4])[0]
|
796 | | - ptr += 1 * 0x4
|
797 | | - retval[process_n]['timeout'] = struct.unpack("<I", processinfo[ptr:ptr + 4])[0]
|
798 | | - ptr += 1 * 0x4
|
799 | | - retval[process_n]['blocked_since'] = struct.unpack("<I", processinfo[ptr:ptr + 4])[0]
|
800 | | - ptr += 1 * 0x4
|
801 | | - retval[process_n]['blocked_by_ptr'] = struct.unpack("<I", processinfo[ptr:ptr + 4])[0]
|
802 | | - ptr += 1 * 0x4
|
803 | | - retval[process_n]['stack_ptr'] = struct.unpack("<I", processinfo[ptr:ptr + 4])[0]
|
804 | | - ptr += 1 * 0x4
|
805 | | - retval[process_n]['err_no'] = struct.unpack("<I", processinfo[ptr:ptr + 4])[0]
|
806 | | - ptr += 1 * 0x4
|
807 | | - retval[process_n]['block_type'] = struct.unpack("<B", processinfo[ptr:ptr + 1])[0]
|
808 | | - ptr += 1 * 0x1
|
809 | | - retval[process_n]['thread_type'] = struct.unpack("<B", processinfo[ptr:ptr + 1])[0]
|
810 | | - ptr += 1 * 0x1
|
811 | | - retval[process_n]['priority'] = struct.unpack("<B", processinfo[ptr:ptr + 1])[0]
|
812 | | - ptr += 1 * 0x1
|
813 | | - retval[process_n]['cpuload'] = struct.unpack("<B", processinfo[ptr:ptr + 1])[0]
|
814 | | - ptr += 1 * 0x1
|
815 | | -
|
816 | | - process_n += 1
|
817 | | -
|
818 | | - return retval
|
819 | | -
|
820 | | -
|
821 | | - def state2name(state, structver):
|
822 | | - if structver == 1:
|
823 | | - if state == 0: return "THREAD_FREE"
|
824 | | - elif state == 1: return "THREAD_SUSPENDED"
|
825 | | - elif state == 2: return "THREAD_READY"
|
826 | | - elif state == 3: return "THREAD_RUNNING"
|
827 | | - elif state == 4: return "THREAD_BLOCKED"
|
828 | | - elif state == 5: return "THREAD_DEFUNCT"
|
829 | | - elif state == 6: return "THREAD_DEFUNCT_ACK"
|
830 | | - else: return "UNKNOWN"
|
831 | | - else: return "UNKNOWN"
|
832 | | -
|
833 | | - def blocktype2name(blocktype, structver):
|
834 | | - if structver == 1:
|
835 | | - if blocktype == 0: return "THREAD_NOT_BLOCKED"
|
836 | | - elif blocktype == 1: return "THREAD_BLOCK_SLEEP"
|
837 | | - elif blocktype == 2: return "THREAD_BLOCK_MUTEX"
|
838 | | - elif blocktype == 3: return "THREAD_BLOCK_WAKEUP"
|
839 | | - elif blocktype == 4: return "THREAD_DEFUNCT_STKOV"
|
840 | | - elif blocktype == 5: return "THREAD_DEFUNCT_PANIC"
|
841 | | - else: return "UNKNOWN"
|
842 | | - else: return "UNKNOWN"
|
843 | | -
|
844 | | - def threadtype2name (threadtype, structver):
|
845 | | - if structver == 1:
|
846 | | - if threadtype == 0: return "USER_THREAD"
|
847 | | - elif threadtype == 1: return "OS_THREAD"
|
848 | | - elif threadtype == 2: return "CORE_THREAD"
|
849 | | - else: return "UNKNOWN"
|
850 | | - else: return "UNKNOWN"
|
851 | | -
|
852 | | - def procinfotostring(procinfolist, structver):
|
853 | | - processinfoprint = ""
|
854 | | - ptr = 0
|
855 | | - while structver == 1 and ptr < len(procinfolist): # Process information struct version == 1
|
856 | | - processinfoprint += "--------------------------------------------------------------------------------\n"
|
857 | | - processinfoprint += "R0: 0x%08x, R1: 0x%08x, R2: 0x%08x, R3: 0x%08x,\n"\
|
858 | | - % (procinfolist[ptr]['regs'][0], procinfolist[ptr]['regs'][1], procinfolist[ptr]['regs'][2], procinfolist[ptr]['regs'][3])\
|
859 | | - + "R4: 0x%08x, R5: 0x%08x, R6: 0x%08x, R7: 0x%08x,\n"\
|
860 | | - % (procinfolist[ptr]['regs'][4], procinfolist[ptr]['regs'][5], procinfolist[ptr]['regs'][6], procinfolist[ptr]['regs'][7])\
|
861 | | - + "R8: 0x%08x, R9: 0x%08x, R10: 0x%08x, R11: 0x%08x,\n"\
|
862 | | - % (procinfolist[ptr]['regs'][8], procinfolist[ptr]['regs'][9], procinfolist[ptr]['regs'][10], procinfolist[ptr]['regs'][11])\
|
863 | | - + "R12: 0x%08x, SP: 0x%08x, LR: 0x%08x, PC: 0x%08x\n" \
|
864 | | - % (procinfolist[ptr]['regs'][12], procinfolist[ptr]['regs'][13], procinfolist[ptr]['regs'][14], procinfolist[ptr]['regs'][15])
|
865 | | - processinfoprint += "cpsr: 0x%08x " % (procinfolist[ptr]['cpsr'])
|
866 | | - processinfoprint += "state: %s " % (state2name([procinfolist[ptr]['state']], structver))
|
867 | | - processinfoprint += "nameptr: 0x%08x\n" % (procinfolist[ptr]['name_ptr'])
|
868 | | - processinfoprint += "current cpu time: 0x%08x " % (procinfolist[ptr]['cputime_current'])
|
869 | | - processinfoprint += "total cpu time: 0x%016x\n" % (procinfolist[ptr]['cputime_total'])
|
870 | | - processinfoprint += "startusec: 0x%08x " % (procinfolist[ptr]['startusec'])
|
871 | | - processinfoprint += "queue next ptr: 0x%08x\n" % (procinfolist[ptr]['queue_next_ptr'])
|
872 | | - processinfoprint += "timeout: 0x%08x\n" % (procinfolist[ptr]['timeout'])
|
873 | | - processinfoprint += "blocked since: 0x%08x " % (procinfolist[ptr]['blocked_since'])
|
874 | | - processinfoprint += "blocked by ptr: 0x%08x\n" % (procinfolist[ptr]['blocked_by_ptr'])
|
875 | | - processinfoprint += "err_no: 0x%08x " % (procinfolist[ptr]['err_no'])
|
876 | | - processinfoprint += "block type: %s\n" % (blocktype2name([procinfolist[ptr]['block_type']], structver))
|
877 | | - processinfoprint += "thread type: %s\n" % (threadtype2name([procinfolist[ptr]['thread_type']], structver))
|
878 | | - processinfoprint += "priority: 0x%02x " % (procinfolist[ptr]['priority'])
|
879 | | - processinfoprint += "cpu load: 0x%02x\n" % (procinfolist[ptr]['cpuload'])
|
880 | | -
|
881 | | - ptr += 1
|
| 353 | +class Dev(object):
|
| 354 | + def __init__(self, idVendor, idProduct):
|
| 355 | + self.idVendor = idVendor
|
| 356 | + self.idProduct = idProduct
|
882 | 357 |
|
883 | | - processinfoprint += "--------------------------------------------------------------------------------\n"
|
| 358 | + self.interface = 0
|
| 359 | + self.timeout = 100
|
884 | 360 |
|
885 | | - return processinfoprint
|
886 | | -
|
887 | | - # reading code --------------------------------------------------
|
888 | | - self.__myprint("Retrieving process information...", silent)
|
| 361 | + self.connect()
|
| 362 | + self.findEndpoints()
|
| 363 | +
|
| 364 | + self.packetsizelimit = {}
|
| 365 | + self.packetsizelimit['cout'] = None
|
| 366 | + self.packetsizelimit['cin'] = None
|
| 367 | + self.packetsizelimit['dout'] = None
|
| 368 | + self.packetsizelimit['din'] = None
|
889 | 369 |
|
890 | | - offset = 0
|
891 | | - blocklen = tablesize = self.cin_maxsize - 0x10
|
892 | | - procinfo = ""
|
893 | | - structversion = 0
|
| 370 | + def __del__(self):
|
| 371 | + self.disconnect()
|
894 | 372 |
|
895 | | - # reading loop
|
896 | | - while (offset < tablesize):
|
897 | | - self.handle.bulkWrite(self.__coutep, struct.pack("<IIII", 15, offset, blocklen, 0))
|
898 | | - response = self.__getbulk(self.handle, self.__cinep, blocklen + 0x10)
|
899 | | - self.__checkstatus(response)
|
900 | | -
|
901 | | - tablesize = struct.unpack("<I", response[8:12])[0]
|
902 | | -
|
903 | | - if tablesize <= offset + blocklen:
|
904 | | - blocklen = tablesize - offset
|
905 | | - procinfo += response[0x10:0x10 + blocklen]
|
906 | | - structversion = struct.unpack("<I", response[4:8])[0]
|
907 | | - tablesize = struct.unpack("<I", response[8:12])[0]
|
908 | | - else:
|
909 | | - procinfo += response[0x10:0x10 + blocklen]
|
910 | | -
|
911 | | - offset += blocklen
|
912 | | -
|
913 | | - blocklen = self.cin_maxsize - 0x10
|
914 | | - if blocklen > tablesize - offset:
|
915 | | - blocklen = tablesize - offset
|
| 373 | + def findEndpoints(self):
|
| 374 | + epcounter = 0
|
| 375 | + self.endpoint = {}
|
| 376 | + for cfg in self.dev:
|
| 377 | + for intf in cfg:
|
| 378 | + for ep in intf:
|
| 379 | + if epcounter == 0:
|
| 380 | + self.endpoint['cout'] = ep.bEndpointAddress
|
| 381 | + elif epcounter == 1:
|
| 382 | + self.endpoint['cin'] = ep.bEndpointAddress
|
| 383 | + elif epcounter == 2:
|
| 384 | + self.endpoint['dout'] = ep.bEndpointAddress
|
| 385 | + elif epcounter == 3:
|
| 386 | + self.endpoint['din'] = ep.bEndpointAddress
|
| 387 | + epcounter += 1
|
| 388 | + if epcounter <= 3:
|
| 389 | + raise DeviceError("Not all endpoints found in the descriptor. Only "+str(epcounter)+" found, we need 4")
|
916 | 390 |
|
| 391 | + def connect(self):
|
| 392 | + self.dev = usb.core.find(idVendor=self.idVendor, idProduct=self.idProduct)
|
| 393 | + if self.dev is None:
|
| 394 | + raise DeviceNotFoundError()
|
| 395 | + self.dev.set_configuration()
|
917 | 396 |
|
918 | | - out = (structversion, tablesize, procinfotolist(procinfo, structversion))
|
919 | | -
|
920 | | - self.__myprint(" done\n"\
|
921 | | - + "Process information struct version: 0x%08x\n" % out[0]\
|
922 | | - + "Total size of process information table: 0x%08x\n" % out[1]\
|
923 | | - + procinfotostring(out[2], 1)\
|
924 | | - + "\n\n")
|
| 397 | + def disconnect(self):
|
| 398 | + pass
|
925 | 399 |
|
926 | | - return out
|
927 | | -
|
| 400 | + def send(self, endpoint, data):
|
| 401 | + size = self.dev.write(endpoint, data, self.interface, self.timeout)
|
| 402 | + if size != len(data):
|
| 403 | + raise SendError
|
| 404 | + return len
|
928 | 405 |
|
929 | | - def execimage(self, offset, silent = 0):
|
930 | | - self.__myprint("Executing emBIOS executable image at 0x%08x..." % offset, silent)
|
931 | | -
|
932 | | - self.handle.bulkWrite(self.__coutep, struct.pack("<IIII", 21, offset, 0, 0))
|
933 | | - response = self.__getbulk(self.handle, self.__cinep, 0x10)
|
934 | | - self.__checkstatus(response)
|
| 406 | + def receive(self, endpoint, size):
|
| 407 | + read = self.dev.read(endpoint, size, self.interface, self.timeout)
|
| 408 | + if len(read) != size:
|
| 409 | + raise ReceiveError
|
| 410 | + return read
|
935 | 411 |
|
936 | | - self.__myprint(" done\n execimage() return code: 0x%08x\n" % struct.unpack("<I", response[4:8])[0], silent)
|
| 412 | + def cout(self, data):
|
| 413 | + if self.packetsizelimit['cout'] and len(data) > self.packetsizelimit['cout']:
|
| 414 | + raise SendError("Packet too big")
|
| 415 | + return self.send(self.endpoint['cout'], data)
|
937 | 416 |
|
938 | | - return struct.unpack("<I", response[4:8])[0]
|
| 417 | + def cin(self, size):
|
| 418 | + if self.packetsizelimit['cin'] and size > self.packetsizelimit['cin']:
|
| 419 | + raise ReceiveError("Packet too big")
|
| 420 | + return self.receive(self.endpoint['cin'], size)
|
939 | 421 |
|
| 422 | + def dout(self, data):
|
| 423 | + if self.packetsizelimit['dout'] and len(data) > self.packetsizelimit['dout']:
|
| 424 | + raise SendError("Packet too big")
|
| 425 | + return self.send(self.endpoint['dout'], data)
|
940 | 426 |
|
941 | | - def execfirmware(self, offset, silent = 0):
|
942 | | - self.__myprint("Executing firmware image at 0x%08x..." % offset, silent)
|
943 | | -
|
944 | | - self.handle.bulkWrite(self.__coutep, struct.pack("<IIII", 24, offset, 0, 0))
|
945 | | - response = self.__getbulk(self.handle, self.__cinep, 0x10)
|
946 | | - self.__checkstatus(response)
|
947 | | -
|
948 | | - self.__myprint(" done\n", silent)
|
949 | | -
|
950 | | - return
|
951 | | -
|
952 | | -
|
953 | | -#=====================================================================================
|
| 427 | + def din(self, size):
|
| 428 | + if self.packetsizelimit['din'] and size > self.packetsizelimit['din']:
|
| 429 | + raise ReceiveError("Packet too big")
|
| 430 | + return self.receive(self.endpoint['din'], size)
|
954 | 431 |
|
955 | 432 |
|
956 | | - def readrawbootflash(self, addr_bootflsh, addr_mem, size, silent = 0):
|
957 | | - self.__myprint("Reading 0x%x bytes from 0x%08x at bootflash to 0x%08x..." % (size, addr_bootflsh, addr_mem), silent)
|
958 | | -
|
959 | | - self.handle.bulkWrite(self.__coutep, struct.pack("<IIII", 22, addr_mem, addr_bootflsh, size))
|
960 | | - response = self.__getbulk(self.handle, self.__cinep, 0x10)
|
961 | | - self.__checkstatus(response)
|
962 | | -
|
963 | | - self.__myprint(" done\n", silent)
|
964 | | -
|
965 | | -
|
966 | | - def writerawbootflash(self, addr_mem, addr_bootflsh, size, silent = 0):
|
967 | | - self.__myprint("Writing 0x%x bytes from 0x%08x to bootflash at 0x%08x..." % (size, addr_fmem, addr_bootflsh), silent)
|
968 | | -
|
969 | | - self.handle.bulkWrite(self.__coutep, struct.pack("<IIII", 23, addr_mem, addr_bootflsh, size))
|
970 | | - response = self.__getbulk(self.handle, self.__cinep, 0x10)
|
971 | | - self.__checkstatus(response)
|
972 | | -
|
973 | | - self.__myprint(" done\n", silent)
|
974 | | -
|
975 | | -
|
976 | | -#=====================================================================================
|
977 | | -
|
978 | | -
|
979 | | - def flushcaches(self, silent = 0):
|
980 | | - self.__myprint("Flushing caches...", silent)
|
981 | | -
|
982 | | - self.handle.bulkWrite(self.__coutep, struct.pack("<IIII", 20, 0, 0, 0))
|
983 | | - response = self.__getbulk(self.handle, self.__cinep, 0x10)
|
984 | | - self.__checkstatus(response)
|
985 | | -
|
986 | | - self.__myprint(" done\n", silent)
|
987 | | -
|
988 | | -
|
989 | | -#======================================================================================
|
990 | | -# backlight control, remnant from libibugger adjusted to work with libembios ==========
|
991 | | -
|
992 | | -
|
993 | | - def backlighton(self, fade, brightness, silent = 0):
|
994 | | - self.__myprint("Turning on backlight...", silent)
|
995 | | - if self.devtype == 2:
|
996 | | - self.i2csend(0, 0xe6, 0x2b, struct.pack("<B", fade), 1)
|
997 | | - self.i2csend(0, 0xe6, 0x28, struct.pack("<B", int(brightness * 46)), 1)
|
998 | | - self.i2csend(0, 0xe6, 0x29, struct.pack("<B", 1), 1)
|
999 | | - self.__myprint(" done\n", silent)
|
1000 | | - elif self.devtype == 4:
|
1001 | | - self.i2csend(0, 0xe6, 0x30, struct.pack("<B", int(brightness * 250)), 1)
|
1002 | | - self.i2csend(0, 0xe6, 0x31, struct.pack("<B", 3), 1)
|
1003 | | - self.__myprint(" done\n", silent)
|
1004 | | - else: self.__myprint(" unsupported (%s)\n" % self.devtype2name(self.devtype), silent)
|
1005 | | -
|
1006 | | -
|
1007 | | - def backlightoff(self, fade, silent = 0):
|
1008 | | - self.__myprint("Turning off backlight...", silent)
|
1009 | | - if self.devtype == 2:
|
1010 | | - self.i2csend(0, 0xe6, 0x2b, struct.pack("<B", fade), 1)
|
1011 | | - self.i2csend(0, 0xe6, 0x29, struct.pack("<B", 0), 1)
|
1012 | | - self.__myprint(" done\n", silent)
|
1013 | | - elif self.devtype == 4:
|
1014 | | - self.i2csend(0, 0xe6, 0x31, struct.pack("<B", 2), 1)
|
1015 | | - self.__myprint(" done\n", silent)
|
1016 | | - else: self.__myprint(" unsupported (%s)\n" % self.devtype2name(self.devtype), silent)
|
1017 | | -
|
| 433 | +if __name__ == "__main__":
|
| 434 | + # Some tests
|
| 435 | + import sys
|
| 436 | + embios = Embios()
|
| 437 | + resp = embios.getversioninfo()
|
| 438 | + sys.stdout.write("Embios device version information: " + libembiosdata.swtypes[resp.swtypeid] + " v" + str(resp.majorv) + "." + str(resp.minorv) +
|
| 439 | + "." + str(resp.patchv) + " r" + str(resp.revision) + " running on " + libembiosdata.hwtypes[resp.hwtypeid] + "\n")
|
| 440 | + resp = embios.getusermemrange()
|
| 441 | + sys.stdout.write("Usermemrange: "+hex(resp.lower)+" - "+hex(resp.upper)+"\n")
|
| 442 | + memaddr = resp.lower
|
| 443 | + maxlen = resp.upper - resp.lower
|
| 444 | + f = open("./embios.py", "rb")
|
| 445 | + sys.stdout.write("Loading test file (embios.py) to send over USB...\n")
|
| 446 | + datastr = f.read()[:maxlen]
|
| 447 | + sys.stdout.write("Sending data...\n")
|
| 448 | + embios.write(memaddr, datastr)
|
| 449 | + sys.stdout.write("Encrypting data with the hardware key...\n")
|
| 450 | + embios.aesencrypt(memaddr, len(datastr), 0)
|
| 451 | + sys.stdout.write("Reading data back and saving it to 'libembios-test-encrypted.bin'...\n")
|
| 452 | + f = open("./libembios-test-encrypted.bin", "wb")
|
| 453 | + f.write(embios.read(memaddr, len(datastr)))
|
| 454 | + sys.stdout.write("Decrypting the data again...\n")
|
| 455 | + embios.aesdecrypt(memaddr, len(datastr), 0)
|
| 456 | + sys.stdout.write("Reading data back from device...\n")
|
| 457 | + readdata = embios.read(memaddr, len(datastr))
|
| 458 | + if readdata == datastr:
|
| 459 | + sys.stdout.write("Data matches!")
|
| 460 | + else:
|
| 461 | + sys.stdout.write("Data does NOT match. Something got wrong") |
\ No newline at end of file |