| 82 |
benedikt93 |
1 |
#!/usr/bin/env python
|
| 64 |
benedikt93 |
2 |
#
|
|
|
3 |
#
|
| 171 |
farthen |
4 |
# Copyright 2010 TheSeven, benedikt93, Farthen
|
| 64 |
benedikt93 |
5 |
#
|
|
|
6 |
#
|
| 82 |
benedikt93 |
7 |
# This file is part of emBIOS.
|
| 64 |
benedikt93 |
8 |
#
|
| 82 |
benedikt93 |
9 |
# emBIOS is free software: you can redistribute it and/or
|
| 64 |
benedikt93 |
10 |
# modify it under the terms of the GNU General Public License as
|
|
|
11 |
# published by the Free Software Foundation, either version 2 of the
|
|
|
12 |
# License, or (at your option) any later version.
|
|
|
13 |
#
|
| 82 |
benedikt93 |
14 |
# emBIOS is distributed in the hope that it will be useful,
|
| 64 |
benedikt93 |
15 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
16 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
17 |
# See the GNU General Public License for more details.
|
|
|
18 |
#
|
| 82 |
benedikt93 |
19 |
# You should have received a copy of the GNU General Public License
|
|
|
20 |
# along with emBIOS. If not, see <http://www.gnu.org/licenses/>.
|
| 64 |
benedikt93 |
21 |
#
|
|
|
22 |
#
|
|
|
23 |
|
| 171 |
farthen |
24 |
import sys
|
|
|
25 |
import os
|
|
|
26 |
import inspect
|
|
|
27 |
import re
|
| 176 |
farthen |
28 |
import time
|
| 215 |
theseven |
29 |
import struct
|
| 346 |
theseven |
30 |
import locale
|
| 64 |
benedikt93 |
31 |
|
| 176 |
farthen |
32 |
from functools import wraps
|
|
|
33 |
|
| 64 |
benedikt93 |
34 |
import libembios
|
| 171 |
farthen |
35 |
from libembios import Error
|
|
|
36 |
import libembiosdata
|
| 64 |
benedikt93 |
37 |
|
| 236 |
farthen |
38 |
|
| 171 |
farthen |
39 |
class NotImplementedError(Error):
|
|
|
40 |
pass
|
| 64 |
benedikt93 |
41 |
|
| 171 |
farthen |
42 |
class ArgumentError(Error):
|
|
|
43 |
pass
|
| 64 |
benedikt93 |
44 |
|
| 171 |
farthen |
45 |
class ArgumentTypeError(Error):
|
|
|
46 |
def __init__(self, expected, seen=False):
|
|
|
47 |
self.expected = expected
|
|
|
48 |
self.seen = seen
|
|
|
49 |
def __str__(self):
|
|
|
50 |
if self.seen:
|
|
|
51 |
return "Expected " + str(self.expected) + " but saw " + str(self.seen)
|
|
|
52 |
else:
|
|
|
53 |
return "Expected " + str(self.expected) + ", but saw something else"
|
| 64 |
benedikt93 |
54 |
|
|
|
55 |
|
| 171 |
farthen |
56 |
def usage(errormsg=None, specific=False):
|
|
|
57 |
"""
|
|
|
58 |
Prints the usage information.
|
|
|
59 |
It is auto generated from various places.
|
|
|
60 |
"""
|
|
|
61 |
logger = Logger()
|
|
|
62 |
cmddict= Commandline.cmddict
|
|
|
63 |
doc = {}
|
|
|
64 |
# This sorts the output of various internal functions
|
|
|
65 |
# and puts everything in easy readable form
|
|
|
66 |
for function in cmddict:
|
|
|
67 |
function = cmddict[function].func
|
|
|
68 |
docinfo = {}
|
|
|
69 |
name = function.__name__
|
|
|
70 |
args = inspect.getargspec(function)[0]
|
|
|
71 |
docinfo['varargs'] = False
|
|
|
72 |
if inspect.getargspec(function)[1]:
|
|
|
73 |
docinfo['varargs'] = True
|
|
|
74 |
kwargvalues = inspect.getargspec(function)[3]
|
|
|
75 |
kwargs = {}
|
|
|
76 |
if args:
|
|
|
77 |
if kwargvalues:
|
|
|
78 |
argnum = len(args) - len(kwargvalues)
|
|
|
79 |
kwargnum = len(kwargvalues)
|
|
|
80 |
kwargs = dict(zip(args[argnum:], kwargvalues))
|
|
|
81 |
else:
|
|
|
82 |
argnum = len(args)
|
|
|
83 |
else:
|
|
|
84 |
argnum = 0
|
|
|
85 |
docinfo['args'] = args[1:argnum]
|
|
|
86 |
docinfo['kwargs'] = kwargs
|
|
|
87 |
if function.__doc__:
|
|
|
88 |
# strip unneccessary whitespace
|
|
|
89 |
docinfo['documentation'] = re.sub(r'\n ', '\n', function.__doc__)
|
|
|
90 |
else:
|
|
|
91 |
docinfo['documentation'] = None
|
|
|
92 |
doc[name] = docinfo
|
| 64 |
benedikt93 |
93 |
|
| 171 |
farthen |
94 |
if not specific:
|
|
|
95 |
logger.log("Please provide a command and (if needed) parameters as command line arguments\n\n")
|
|
|
96 |
logger.log("Available commands:\n\n")
|
| 82 |
benedikt93 |
97 |
else:
|
| 171 |
farthen |
98 |
logger.log("\n")
|
|
|
99 |
for function in sorted(doc.items()):
|
|
|
100 |
function = function[0]
|
|
|
101 |
if specific == False or specific == function:
|
|
|
102 |
logger.log(" " + function + " ")
|
|
|
103 |
for arg in doc[function]['args']:
|
|
|
104 |
logger.log("<" + arg + "> ")
|
|
|
105 |
if doc[function]['kwargs']:
|
|
|
106 |
for kwarg in doc[function]['kwargs']:
|
|
|
107 |
logger.log("[" + kwarg + "] ")
|
|
|
108 |
if doc[function]['varargs']:
|
|
|
109 |
logger.log("<db1> ... <dbN>")
|
|
|
110 |
if doc[function]['documentation']:
|
|
|
111 |
logger.log(doc[function]['documentation']+"\n")
|
| 64 |
benedikt93 |
112 |
|
| 171 |
farthen |
113 |
logger.log("\n")
|
|
|
114 |
|
|
|
115 |
if errormsg:
|
|
|
116 |
logger.error(str(errormsg)+"\n")
|
|
|
117 |
exit(2)
|
|
|
118 |
|
|
|
119 |
|
|
|
120 |
class Logger(object):
|
|
|
121 |
"""
|
|
|
122 |
Simple stdout logger.
|
| 382 |
farthen |
123 |
Loglevel 4 is most verbose, Loglevel 0: Only say something if there is an error.
|
|
|
124 |
The log function doesn't care about the loglevel and always logs to stdout.
|
| 171 |
farthen |
125 |
"""
|
|
|
126 |
def __init__(self):
|
|
|
127 |
# Possible values: 0 (only errors), 1 (warnings), 2 (info, recommended for production use), 3 and more (debug)
|
|
|
128 |
self.loglevel = 3
|
|
|
129 |
|
|
|
130 |
def log(self, text):
|
|
|
131 |
sys.stdout.write(text)
|
| 67 |
benedikt93 |
132 |
|
| 171 |
farthen |
133 |
def debug(self, text):
|
|
|
134 |
if self.loglevel >= 3:
|
| 382 |
farthen |
135 |
self.log("DEBUG: " + text)
|
| 119 |
benedikt93 |
136 |
|
| 171 |
farthen |
137 |
def info(self, text):
|
|
|
138 |
if self.loglevel >= 2:
|
|
|
139 |
self.log(text)
|
| 82 |
benedikt93 |
140 |
|
| 382 |
farthen |
141 |
def warn(self, text):
|
| 171 |
farthen |
142 |
if self.loglevel >= 1:
|
|
|
143 |
self.log("WARNING: " + text)
|
| 119 |
benedikt93 |
144 |
|
| 171 |
farthen |
145 |
def error(self, text):
|
|
|
146 |
self.log("ERROR: " + text)
|
|
|
147 |
|
|
|
148 |
|
|
|
149 |
def command(func):
|
|
|
150 |
"""
|
|
|
151 |
Decorator for all commands.
|
|
|
152 |
The decorated function is called with (self, all, other, arguments, ...)
|
|
|
153 |
"""
|
| 176 |
farthen |
154 |
@wraps(func)
|
| 172 |
farthen |
155 |
def decorator(*args):
|
| 171 |
farthen |
156 |
return func(args[0], *args[1:])
|
|
|
157 |
func._command = True
|
|
|
158 |
decorator.func = func
|
|
|
159 |
return decorator
|
|
|
160 |
|
|
|
161 |
|
|
|
162 |
def commandClass(cls):
|
|
|
163 |
"""
|
|
|
164 |
Decorator for the class. Sets the self.cmddict of the class
|
|
|
165 |
to all functions decorated with @command
|
|
|
166 |
"""
|
|
|
167 |
cls.cmddict = {}
|
|
|
168 |
for attr, value in cls.__dict__.iteritems():
|
|
|
169 |
if getattr(value, 'func', False):
|
|
|
170 |
if getattr(value.func, '_command', False):
|
|
|
171 |
cls.cmddict[value.func.__name__] = value
|
|
|
172 |
return cls
|
|
|
173 |
|
|
|
174 |
|
|
|
175 |
@commandClass
|
|
|
176 |
class Commandline(object):
|
|
|
177 |
"""
|
|
|
178 |
If you want to create a new commandline function you just need to
|
|
|
179 |
create a function with the name of it in this class and decorate
|
|
|
180 |
it with the decorator @command. If you don't want to call the desired
|
|
|
181 |
function (wrong arguments etc) just raise ArgumentError with or
|
| 341 |
farthen |
182 |
without an error message.
|
| 171 |
farthen |
183 |
"""
|
|
|
184 |
def __init__(self):
|
|
|
185 |
self.logger = Logger()
|
|
|
186 |
try:
|
|
|
187 |
self.embios = libembios.Embios()
|
|
|
188 |
except libembios.DeviceNotFoundError:
|
|
|
189 |
self.logger.error("No emBIOS device found!")
|
| 176 |
farthen |
190 |
exit(1)
|
|
|
191 |
self.getinfo("version")
|
| 171 |
farthen |
192 |
|
|
|
193 |
def _parsecommand(self, func, args):
|
|
|
194 |
# adds self to the commandline args.
|
|
|
195 |
# this is needed because the functions need access to their class.
|
|
|
196 |
args.insert(0, self)
|
|
|
197 |
if func in self.cmddict:
|
|
|
198 |
try:
|
| 172 |
farthen |
199 |
self.cmddict[func](*args)
|
| 341 |
farthen |
200 |
except (ArgumentError, libembios.ArgumentError), e:
|
| 176 |
farthen |
201 |
usage(e, specific=func)
|
| 341 |
farthen |
202 |
except (ArgumentError, libembios.ArgumentError):
|
| 176 |
farthen |
203 |
usage("Syntax Error in function '" + func + "'", specific=func)
|
| 171 |
farthen |
204 |
except ArgumentTypeError, e:
|
| 176 |
farthen |
205 |
usage(e, specific=func)
|
| 171 |
farthen |
206 |
except NotImplementedError:
|
|
|
207 |
self.logger.error("This function is not implemented yet!")
|
|
|
208 |
except libembios.DeviceError, e:
|
|
|
209 |
self.logger.error(str(e))
|
|
|
210 |
except TypeError, e:
|
| 341 |
farthen |
211 |
# Only act on TypeErrors for the function we called, not on TypeErrors raised by another function.
|
| 171 |
farthen |
212 |
if str(e).split(" ", 1)[0] == func + "()":
|
|
|
213 |
self.logger.error(usage("Argument Error in '" + func + "': Wrong argument count", specific=func))
|
|
|
214 |
else:
|
|
|
215 |
raise
|
| 176 |
farthen |
216 |
except libembios.usb.core.USBError:
|
| 341 |
farthen |
217 |
self.logger.error("There is a problem with the USB connection.")
|
| 171 |
farthen |
218 |
else:
|
|
|
219 |
usage("No such command")
|
| 67 |
benedikt93 |
220 |
|
| 171 |
farthen |
221 |
@staticmethod
|
|
|
222 |
def _bool(something):
|
|
|
223 |
"""
|
|
|
224 |
Converts quite everything into bool.
|
|
|
225 |
"""
|
|
|
226 |
if type(something) == bool:
|
|
|
227 |
return something
|
|
|
228 |
elif type(something) == int or type(something) == long:
|
|
|
229 |
return bool(something)
|
|
|
230 |
elif type(something == str):
|
|
|
231 |
truelist = ['true', '1', 't', 'y', 'yes']
|
|
|
232 |
falselist = ['false', '0', 'f', 'n', 'no']
|
|
|
233 |
if something.lower() in truelist:
|
|
|
234 |
return True
|
|
|
235 |
elif something.lower() in falselist:
|
|
|
236 |
return False
|
|
|
237 |
raise ArgumentTypeError("bool", "'"+str(something)+"'")
|
|
|
238 |
|
|
|
239 |
@staticmethod
|
|
|
240 |
def _hexint(something):
|
|
|
241 |
"""
|
|
|
242 |
Converts quite everything to a hexadecimal represented integer.
|
|
|
243 |
This works for default arguments too, because it returns
|
|
|
244 |
None when it found that it got a NoneType object.
|
|
|
245 |
"""
|
|
|
246 |
if type(something) == int or type(something) == long:
|
|
|
247 |
return something
|
|
|
248 |
elif type(something) == str:
|
|
|
249 |
try:
|
|
|
250 |
return int(something, 16)
|
|
|
251 |
except ValueError:
|
|
|
252 |
raise ArgumentTypeError("hexadecimal coded integer", "'"+str(something)+"'")
|
|
|
253 |
elif type(something) == NoneType:
|
|
|
254 |
return None
|
|
|
255 |
else:
|
|
|
256 |
raise ArgumentTypeError("hexadecimal coded integer", "'"+str(something)+"'")
|
| 64 |
benedikt93 |
257 |
|
| 173 |
farthen |
258 |
@staticmethod
|
|
|
259 |
def _hex(integer):
|
|
|
260 |
return "0x%x" % integer
|
| 64 |
benedikt93 |
261 |
|
| 171 |
farthen |
262 |
@command
|
|
|
263 |
def getinfo(self, infotype):
|
|
|
264 |
"""
|
|
|
265 |
Get info on the running emBIOS.
|
|
|
266 |
<infotype> may be either of 'version', 'packetsize', 'usermemrange'.
|
|
|
267 |
"""
|
|
|
268 |
if infotype == "version":
|
| 271 |
farthen |
269 |
try:
|
| 343 |
farthen |
270 |
hwtype = libembiosdata.hwtypes[self.embios.lib.dev.hwtypeid]
|
| 271 |
farthen |
271 |
except KeyError:
|
| 343 |
farthen |
272 |
hwtype = "UNKNOWN (ID = " + self._hex(self.embios.lib.dev.hwtypeid) + ")"
|
| 382 |
farthen |
273 |
self.logger.info("Connected to " + \
|
|
|
274 |
libembiosdata.swtypes[self.embios.lib.dev.swtypeid] + \
|
|
|
275 |
" v" + str(self.embios.lib.dev.version.majorv) + \
|
|
|
276 |
"." + str(self.embios.lib.dev.version.minorv) + \
|
|
|
277 |
"." + str(self.embios.lib.dev.version.patchv) + \
|
|
|
278 |
" r" + str(self.embios.lib.dev.version.revision) + \
|
|
|
279 |
" running on " + hwtype + "\n")
|
| 343 |
farthen |
280 |
|
| 171 |
farthen |
281 |
elif infotype == "packetsize":
|
| 382 |
farthen |
282 |
self.logger.info("Maximum packet sizes: \n command out: " + str(self.embios.lib.dev.packetsizelimit.cout) + \
|
|
|
283 |
"\n command in: " + str(self.embios.lib.dev.packetsizelimit.cin) + \
|
|
|
284 |
"\n data in: " + str(self.embios.lib.dev.packetsizelimit.din) + \
|
|
|
285 |
"\n data out: " + str(self.embios.lib.dev.packetsizelimit.dout))
|
| 343 |
farthen |
286 |
|
| 171 |
farthen |
287 |
elif infotype == "usermemrange":
|
|
|
288 |
resp = self.embios.getusermemrange()
|
| 382 |
farthen |
289 |
self.logger.info("The user memory range is " + \
|
|
|
290 |
self._hex(self.embios.lib.dev.usermem.lower) + \
|
|
|
291 |
" - " + \
|
|
|
292 |
self._hex(self.embios.lib.dev.usermem.upper - 1))
|
|
|
293 |
|
| 171 |
farthen |
294 |
else:
|
|
|
295 |
raise ArgumentTypeError("one out of 'version', 'packetsize', 'usermemrange'", infotype)
|
| 64 |
benedikt93 |
296 |
|
| 171 |
farthen |
297 |
@command
|
|
|
298 |
def reset(self, force=False):
|
|
|
299 |
"""
|
|
|
300 |
Resets the device"
|
|
|
301 |
If <force> is 1, the reset will be forced, otherwise it will be gracefully,
|
|
|
302 |
which may take some time.
|
|
|
303 |
"""
|
|
|
304 |
force = self._bool(force)
|
|
|
305 |
if force: self.logger.info("Resetting forcefully...\n")
|
|
|
306 |
else: self.logger.info("Resetting...\n")
|
|
|
307 |
self.embios.reset(force)
|
| 64 |
benedikt93 |
308 |
|
| 171 |
farthen |
309 |
@command
|
|
|
310 |
def poweroff(self, force=False):
|
|
|
311 |
"""
|
|
|
312 |
Powers the device off
|
|
|
313 |
If <force> is 1, the poweroff will be forced, otherwise it will be gracefully,
|
|
|
314 |
which may take some time.
|
|
|
315 |
"""
|
|
|
316 |
force = self._bool(force)
|
| 281 |
farthen |
317 |
if force: self.logger.info("Powering off forcefully...\n")
|
|
|
318 |
else: self.logger.info("Powering off...\n")
|
|
|
319 |
self.embios.poweroff(force)
|
| 64 |
benedikt93 |
320 |
|
| 171 |
farthen |
321 |
@command
|
|
|
322 |
def uploadfile(self, addr, filename):
|
|
|
323 |
"""
|
|
|
324 |
Uploads a file to the device
|
|
|
325 |
<offset>: the address to upload the file to
|
|
|
326 |
<filename>: the path to the file
|
|
|
327 |
"""
|
|
|
328 |
addr = self._hexint(addr)
|
|
|
329 |
try:
|
|
|
330 |
f = open(filename, 'rb')
|
|
|
331 |
except IOError:
|
|
|
332 |
raise ArgumentError("File not readable. Does it exist?")
|
| 382 |
farthen |
333 |
self.logger.info("Writing file '" + filename + \
|
|
|
334 |
"' to memory at " + self._hex(addr) + "...")
|
| 171 |
farthen |
335 |
with f:
|
|
|
336 |
self.embios.write(addr, f.read())
|
| 178 |
farthen |
337 |
f.close()
|
| 171 |
farthen |
338 |
self.logger.info("done\n")
|
| 176 |
farthen |
339 |
|
| 171 |
farthen |
340 |
@command
|
|
|
341 |
def downloadfile(self, addr, size, filename):
|
|
|
342 |
"""
|
|
|
343 |
Uploads a file to the device
|
|
|
344 |
<offset>: the address to upload the file to
|
|
|
345 |
<size>: the number of bytes to be read
|
|
|
346 |
<filename>: the path to the file
|
|
|
347 |
"""
|
|
|
348 |
addr = self._hexint(addr)
|
|
|
349 |
size = self._hexint(size)
|
|
|
350 |
try:
|
|
|
351 |
f = open(filename, 'wb')
|
|
|
352 |
except IOError:
|
|
|
353 |
raise ArgumentError("Can not open file for write!")
|
| 382 |
farthen |
354 |
self.logger.info("Reading data from address " + self._hex(addr) + \
|
|
|
355 |
" with the size " + self._hex(size) + \
|
|
|
356 |
" to '"+filename+"'...")
|
| 171 |
farthen |
357 |
with f:
|
|
|
358 |
f.write(self.embios.read(addr, size))
|
| 178 |
farthen |
359 |
f.close()
|
| 171 |
farthen |
360 |
self.logger.info("done\n")
|
|
|
361 |
|
|
|
362 |
@command
|
|
|
363 |
def uploadint(self, addr, integer):
|
|
|
364 |
"""
|
|
|
365 |
Uploads a single integer to the device
|
| 260 |
theseven |
366 |
<addr>: the address to upload the integer to
|
|
|
367 |
<integer>: the integer to upload
|
| 171 |
farthen |
368 |
"""
|
|
|
369 |
addr = self._hexint(addr)
|
|
|
370 |
integer = self._hexint(integer)
|
|
|
371 |
if integer > 0xFFFFFFFF:
|
|
|
372 |
raise ArgumentError("Specified integer too long")
|
| 260 |
theseven |
373 |
data = struct.pack("I", integer)
|
| 178 |
farthen |
374 |
self.embios.write(addr, data)
|
| 382 |
farthen |
375 |
self.logger.info("Integer '" + self._hex(integer) + \
|
|
|
376 |
"' written successfully to " + self._hex(addr) + "\n")
|
| 171 |
farthen |
377 |
|
|
|
378 |
@command
|
|
|
379 |
def downloadint(self, addr):
|
|
|
380 |
"""
|
|
|
381 |
Downloads a single integer from the device and prints it to the console window
|
| 236 |
farthen |
382 |
<addr>: the address to download the integer from
|
| 171 |
farthen |
383 |
"""
|
|
|
384 |
addr = self._hexint(addr)
|
| 260 |
theseven |
385 |
data = self.embios.read(addr, 4)
|
|
|
386 |
integer = struct.unpack("I", data)[0]
|
| 382 |
farthen |
387 |
self.logger.info("Integer '" + self._hex(integer) + \
|
|
|
388 |
"' read from address " + self._hex(addr) + "\n")
|
| 171 |
farthen |
389 |
|
|
|
390 |
@command
|
| 176 |
farthen |
391 |
def i2cread(self, bus, slave, addr, size):
|
| 171 |
farthen |
392 |
"""
|
|
|
393 |
Reads data from an I2C device
|
|
|
394 |
<bus> the bus index
|
|
|
395 |
<slave> the slave address
|
|
|
396 |
<addr> the start address on the I2C device
|
|
|
397 |
<size> the number of bytes to read
|
|
|
398 |
"""
|
|
|
399 |
bus = self._hexint(bus)
|
|
|
400 |
slave = self._hexint(slave)
|
|
|
401 |
addr = self._hexint(addr)
|
|
|
402 |
size = self._hexint(size)
|
| 236 |
farthen |
403 |
data = self.embios.i2cread(bus, slave, addr, size)
|
|
|
404 |
bytes = struct.unpack("%dB" % len(data), data)
|
|
|
405 |
self.logger.info("Data read from I2C:\n")
|
|
|
406 |
for index, byte in enumerate(bytes):
|
|
|
407 |
self.logger.info("%02X: %02X\n" % (index, byte))
|
| 171 |
farthen |
408 |
|
|
|
409 |
@command
|
| 176 |
farthen |
410 |
def i2cwrite(self, bus, slave, addr, *args):
|
| 171 |
farthen |
411 |
"""
|
|
|
412 |
Writes data to an I2C device
|
|
|
413 |
<bus> the bus index
|
|
|
414 |
<slave> the slave address
|
|
|
415 |
<addr> the start address on the I2C device
|
| 176 |
farthen |
416 |
<db1> ... <dbN> the data in single bytes, encoded in hex,
|
| 236 |
farthen |
417 |
seperated by whitespaces, eg. 37 5A 4F EB
|
| 171 |
farthen |
418 |
"""
|
|
|
419 |
bus = self._hexint(bus)
|
|
|
420 |
slave = self._hexint(slave)
|
|
|
421 |
addr = self._hexint(addr)
|
| 176 |
farthen |
422 |
data = ""
|
| 171 |
farthen |
423 |
for arg in args:
|
| 176 |
farthen |
424 |
data += chr(self._hexint(arg))
|
| 236 |
farthen |
425 |
self.logger.info("Writing data to I2C...\n")
|
| 176 |
farthen |
426 |
self.embios.i2cwrite(bus, slave, addr, data)
|
| 236 |
farthen |
427 |
self.logger.info("done\n")
|
| 171 |
farthen |
428 |
|
|
|
429 |
@command
|
| 176 |
farthen |
430 |
def console(self):
|
| 171 |
farthen |
431 |
"""
|
| 176 |
farthen |
432 |
Reads data from the USB console continuously
|
| 171 |
farthen |
433 |
"""
|
| 176 |
farthen |
434 |
while True:
|
|
|
435 |
resp = self.embios.usbcread()
|
|
|
436 |
self.logger.log(resp.data)
|
|
|
437 |
time.sleep(0.1 / resp.maxsize * (resp.maxsize - len(resp.data)))
|
| 171 |
farthen |
438 |
|
|
|
439 |
@command
|
| 176 |
farthen |
440 |
def writeusbconsole(self, *args):
|
| 171 |
farthen |
441 |
"""
|
| 176 |
farthen |
442 |
Writes the string <db1> ... <dbN> to the USB console.
|
| 171 |
farthen |
443 |
"""
|
| 176 |
farthen |
444 |
text = ""
|
|
|
445 |
for word in args:
|
|
|
446 |
text += word + " "
|
|
|
447 |
text = text[:-1]
|
| 236 |
farthen |
448 |
self.logger.info("Writing '"+ text +"' to the usb console\n")
|
| 176 |
farthen |
449 |
self.embios.usbcwrite(text)
|
| 171 |
farthen |
450 |
|
|
|
451 |
@command
|
| 176 |
farthen |
452 |
def readdevconsole(self, bitmask):
|
| 171 |
farthen |
453 |
"""
|
| 176 |
farthen |
454 |
Reads data continuously from one or more of the device's consoles.
|
|
|
455 |
<bitmask>: the bitmask of the consoles to read from.
|
| 171 |
farthen |
456 |
"""
|
|
|
457 |
bitmask = self._hexint(bitmask)
|
| 176 |
farthen |
458 |
while True:
|
|
|
459 |
resp = self.embios.cread()
|
|
|
460 |
self.logger.log(resp.data)
|
|
|
461 |
time.sleep(0.1 / resp.maxsize * (resp.maxsize - len(resp.data)))
|
|
|
462 |
|
| 171 |
farthen |
463 |
@command
|
| 176 |
farthen |
464 |
def writedevconsole(self, bitmask, *args):
|
| 171 |
farthen |
465 |
"""
|
| 176 |
farthen |
466 |
Writes the string <db1> ... <dbN> to one or more of the device's consoles.
|
|
|
467 |
<bitmask>: the bitmask of the consoles to write to
|
| 171 |
farthen |
468 |
"""
|
|
|
469 |
bitmask = self._hexint(bitmask)
|
| 176 |
farthen |
470 |
text = ""
|
|
|
471 |
for word in args:
|
|
|
472 |
text += word + " "
|
|
|
473 |
text = text[:-1]
|
| 382 |
farthen |
474 |
self.logger.info("Writing '" + text + \
|
|
|
475 |
"' to the device consoles identified with " + self._hex(bitmask) + "\n")
|
| 176 |
farthen |
476 |
self.embios.cwrite(text, bitmask)
|
| 171 |
farthen |
477 |
|
|
|
478 |
@command
|
|
|
479 |
def flushconsolebuffers(self, bitmask):
|
|
|
480 |
"""
|
|
|
481 |
flushes one or more of the device consoles' buffers.
|
|
|
482 |
<bitmask>: the bitmask of the consoles to be flushed
|
|
|
483 |
"""
|
|
|
484 |
bitmask = self._hexint(bitmask)
|
| 382 |
farthen |
485 |
self.logger.info("Flushing consoles identified with the bitmask " + \
|
|
|
486 |
self._hex(bitmask) + "\n")
|
| 236 |
farthen |
487 |
self.embios.cflush(bitmask)
|
| 171 |
farthen |
488 |
|
|
|
489 |
@command
|
|
|
490 |
def getprocinfo(self):
|
|
|
491 |
"""
|
|
|
492 |
Fetches data on the currently running processes
|
|
|
493 |
"""
|
| 173 |
farthen |
494 |
import datetime
|
|
|
495 |
threads = self.embios.getprocinfo()
|
| 382 |
farthen |
496 |
cpuload = 1
|
|
|
497 |
threadload = 0
|
|
|
498 |
idleload = 0
|
| 173 |
farthen |
499 |
for thread in threads:
|
| 382 |
farthen |
500 |
if thread.priority != 0:
|
|
|
501 |
threadload += (thread.cpuload*100)/255
|
|
|
502 |
else:
|
|
|
503 |
idleload += (thread.cpuload*100)/255
|
|
|
504 |
coreload = 1 - (threadload + idleload)
|
|
|
505 |
cpuload = threadload + coreload
|
|
|
506 |
self.logger.info("The device has " + str(len(threads)) + " running threads.\n" + \
|
|
|
507 |
"It is running at " + str(cpuload * 100) + "% cpu load with a core load of " + \
|
|
|
508 |
str(coreload * 100) + "%, a thread load of " + str(threadload * 100) + "% " + \
|
|
|
509 |
"and an idle load of " + str(idleload * 100) + "%\n\n")
|
|
|
510 |
self.logger.info("Thread dump:\n")
|
|
|
511 |
for thread in threads:
|
| 173 |
farthen |
512 |
self.logger.info(" "+thread.name+":\n")
|
| 382 |
farthen |
513 |
self.logger.info(" Thread id: " + str(thread.id)+"\n")
|
|
|
514 |
self.logger.info(" Thread type: " + thread.type+"\n")
|
|
|
515 |
self.logger.info(" Thread state: " + thread.state+"\n")
|
|
|
516 |
self.logger.info(" Block type: " + thread.block_type+"\n")
|
|
|
517 |
self.logger.info(" Blocked by: " + self._hex(thread.blocked_by_ptr)+"\n")
|
|
|
518 |
self.logger.info(" Priority: " + str(thread.priority)+"/255\n")
|
| 324 |
theseven |
519 |
self.logger.info(" Current CPU load: "+str((thread.cpuload*100)/255)+"%\n")
|
| 173 |
farthen |
520 |
self.logger.info(" CPU time (total): "+str(datetime.timedelta(microseconds=thread.cputime_total))+"\n")
|
| 382 |
farthen |
521 |
self.logger.info(" Stack address: " + self._hex(thread.stackaddr)+"\n")
|
| 173 |
farthen |
522 |
self.logger.info(" Registers:\n")
|
| 177 |
farthen |
523 |
for registerrange in range(4):
|
|
|
524 |
self.logger.info(" ")
|
|
|
525 |
for register in range(registerrange, 16, 4):
|
|
|
526 |
registerrepr = "r"+str(register)
|
| 318 |
theseven |
527 |
self.logger.info("{0:3s}: 0x{1:08X} ".format(registerrepr, thread.regs["r"+str(register)]))
|
| 177 |
farthen |
528 |
self.logger.info("\n")
|
| 318 |
theseven |
529 |
self.logger.info(" cpsr: 0x{0:08X}".format(thread.regs.cpsr))
|
| 173 |
farthen |
530 |
self.logger.info("\n")
|
|
|
531 |
|
| 171 |
farthen |
532 |
@command
|
|
|
533 |
def lockscheduler(self):
|
|
|
534 |
"""
|
|
|
535 |
Locks (freezes) the scheduler
|
|
|
536 |
"""
|
| 176 |
farthen |
537 |
self.logger.info("Will now lock scheduler\n")
|
| 173 |
farthen |
538 |
self.embios.lockscheduler()
|
| 178 |
farthen |
539 |
|
| 171 |
farthen |
540 |
@command
|
|
|
541 |
def unlockscheduler(self):
|
|
|
542 |
"""
|
|
|
543 |
Unlocks (unfreezes) the scheduler
|
|
|
544 |
"""
|
| 176 |
farthen |
545 |
self.logger.info("Will now unlock scheduler\n")
|
| 173 |
farthen |
546 |
self.embios.unlockscheduler()
|
| 178 |
farthen |
547 |
|
| 171 |
farthen |
548 |
@command
|
|
|
549 |
def suspendthread(self, threadid):
|
|
|
550 |
"""
|
|
|
551 |
Suspends/resumes the thread with thread ID <threadid>
|
|
|
552 |
"""
|
|
|
553 |
threadid = self._hexint(threadid)
|
| 236 |
farthen |
554 |
self.logger.info("Suspending the thread with the threadid "+self._hex(threadid)+"\n")
|
|
|
555 |
self.embios.suspendthread(threadid)
|
| 171 |
farthen |
556 |
|
|
|
557 |
@command
|
|
|
558 |
def resumethread(self, threadid):
|
|
|
559 |
"""
|
|
|
560 |
Resumes the thread with thread ID <threadid>
|
|
|
561 |
"""
|
|
|
562 |
threadid = self._hexint(threadid)
|
| 236 |
farthen |
563 |
self.logger.info("Resuming the thread with the threadid "+self._hex(threadid)+"\n")
|
| 173 |
farthen |
564 |
self.embios.resumethread(threadid)
|
| 171 |
farthen |
565 |
|
|
|
566 |
@command
|
|
|
567 |
def killthread(self, threadid):
|
|
|
568 |
"""
|
|
|
569 |
Kills the thread with thread ID <threadid>
|
|
|
570 |
"""
|
|
|
571 |
threadid = self._hexint(threadid)
|
| 236 |
farthen |
572 |
self.logger.info("Killing the thread with the threadid " + self._hex(threadid) + "\n")
|
| 173 |
farthen |
573 |
self.embios.killthread(threadid)
|
| 171 |
farthen |
574 |
|
|
|
575 |
@command
|
|
|
576 |
def createthread(self, nameptr, entrypoint, stackptr, stacksize, threadtype, priority, state):
|
|
|
577 |
"""
|
|
|
578 |
Creates a new thread and returns its thread ID
|
|
|
579 |
<namepointer> a pointer to the thread's name
|
|
|
580 |
<entrypoint> a pointer to the entrypoint of the thread
|
|
|
581 |
<stackpointer> a pointer to the stack of the thread
|
|
|
582 |
<stacksize> the size of the thread's stack
|
|
|
583 |
<type> the thread type, vaild are: 0 => user thread, 1 => system thread
|
|
|
584 |
<priority> the priority of the thread, from 1 to 255
|
|
|
585 |
<state> the thread's initial state, valid are: 1 => ready, 0 => suspended
|
|
|
586 |
"""
|
|
|
587 |
nameptr = self._hexint(nameptr)
|
|
|
588 |
entrypoint = self._hexint(entrypoint)
|
|
|
589 |
stackpointer = self._hexint(stackpointer)
|
|
|
590 |
stacksize = self._hexint(stacksize)
|
|
|
591 |
priority = self._hexint(priority)
|
| 236 |
farthen |
592 |
data = self.embios.createthread(nameptr, entrypoint, stackptr, stacksize, type, priority, state)
|
|
|
593 |
name = self.embios.readstring(nameptr)
|
| 382 |
farthen |
594 |
self.logger.info("Created a thread with the threadid " + data.id + \
|
|
|
595 |
", the name \"" + name + "\"" + \
|
|
|
596 |
", the entrypoint at " + self._hex(entrypoint) + \
|
|
|
597 |
", the stack at " + self._hex(stackpointer) + \
|
|
|
598 |
" with a size of " + self._hex(stacksize) + \
|
|
|
599 |
" and a priority of " + self._hex(priority) + "\n")
|
| 172 |
farthen |
600 |
|
|
|
601 |
@command
|
|
|
602 |
def run(self, filename):
|
|
|
603 |
"""
|
| 173 |
farthen |
604 |
Uploads the emBIOS application <filename> to
|
| 236 |
farthen |
605 |
the memory and executes it
|
| 172 |
farthen |
606 |
"""
|
| 236 |
farthen |
607 |
try:
|
|
|
608 |
f = open(filename, 'rb')
|
|
|
609 |
except IOError:
|
|
|
610 |
raise ArgumentError("File not readable. Does it exist?")
|
| 238 |
farthen |
611 |
with f:
|
|
|
612 |
data = self.embios.run(f.read())
|
|
|
613 |
self.logger.info("Executed emBIOS application \"" + data.name + "\" at address " + self._hex(data.baseaddr))
|
| 171 |
farthen |
614 |
|
|
|
615 |
@command
|
| 173 |
farthen |
616 |
def execimage(self, addr):
|
| 171 |
farthen |
617 |
"""
|
| 173 |
farthen |
618 |
Executes the emBIOS application at <addr>.
|
| 171 |
farthen |
619 |
"""
|
| 172 |
farthen |
620 |
addr = self._hexint(addr)
|
| 173 |
farthen |
621 |
self.logger.info("Starting emBIOS app at "+self._hex(addr)+"\n")
|
| 172 |
farthen |
622 |
self.embios.execimage(addr)
|
| 176 |
farthen |
623 |
|
| 171 |
farthen |
624 |
@command
|
| 176 |
farthen |
625 |
def flushcaches(self):
|
| 171 |
farthen |
626 |
"""
|
| 176 |
farthen |
627 |
Flushes the CPUs data and instruction caches.
|
|
|
628 |
"""
|
|
|
629 |
self.logger.info("Flushing CPU data and instruction caches...")
|
|
|
630 |
self.embios.flushcaches()
|
|
|
631 |
self.logger.info("done\n")
|
|
|
632 |
|
|
|
633 |
@command
|
|
|
634 |
def readbootflash(self, addr_flash, addr_mem, size):
|
|
|
635 |
"""
|
| 171 |
farthen |
636 |
Reads <size> bytes from bootflash to memory.
|
|
|
637 |
<addr_bootflsh>: the address in bootflash to read from
|
|
|
638 |
<addr_mem>: the address in memory to copy the data to
|
|
|
639 |
"""
|
|
|
640 |
addr_flash = self._hexint(addr_flash)
|
|
|
641 |
addr_mem = self._hexint(addr_mem)
|
|
|
642 |
size = self._hexint(size)
|
| 174 |
farthen |
643 |
self.logger.info("Dumping boot flash addresses "+self._hex(addr_flash)+" - "+
|
|
|
644 |
hex(addr_flash+size)+" to "+self._hex(addr_mem)+" - "+self._hex(addr_mem+size)+"\n")
|
| 276 |
theseven |
645 |
self.embios.lib.dev.timeout = 5000
|
|
|
646 |
self.embios.bootflashread(addr_mem, addr_flash, size)
|
| 176 |
farthen |
647 |
|
| 171 |
farthen |
648 |
@command
|
| 176 |
farthen |
649 |
def writebootflash(self, addr_flash, addr_mem, size, force=False):
|
| 171 |
farthen |
650 |
"""
|
|
|
651 |
Writes <size> bytes from memory to bootflash.
|
|
|
652 |
ATTENTION: Don't call this unless you really know what you're doing!
|
|
|
653 |
This may BRICK your device (unless it has a good recovery option)
|
|
|
654 |
<addr_mem>: the address in memory to copy the data from
|
|
|
655 |
<addr_bootflsh>: the address in bootflash to write to
|
| 174 |
farthen |
656 |
<force>: Use this flag to suppress the 5 seconds delay
|
| 171 |
farthen |
657 |
"""
|
|
|
658 |
addr_flash = self._hexint(addr_flash)
|
|
|
659 |
addr_mem = self._hexint(addr_mem)
|
|
|
660 |
size = self._hexint(size)
|
| 174 |
farthen |
661 |
force = self._bool(force)
|
| 382 |
farthen |
662 |
self.logger.warn("Writing boot flash from the memory in "+self._hex(addr_mem)+" - "+
|
| 174 |
farthen |
663 |
hex(addr_mem+size)+" to "+self._hex(addr_flash)+" - "+self._hex(addr_flash+size)+"\n")
|
|
|
664 |
if force == False:
|
| 382 |
farthen |
665 |
self.logger.warn("If this was not what you intended press Ctrl-C NOW")
|
| 176 |
farthen |
666 |
for i in range(10):
|
| 174 |
farthen |
667 |
self.logger.info(".")
|
|
|
668 |
time.sleep(1)
|
|
|
669 |
self.logger.info("\n")
|
| 276 |
theseven |
670 |
self.embios.lib.dev.timeout = 30000
|
|
|
671 |
self.embios.bootflashwrite(addr_mem, addr_flash, size)
|
| 176 |
farthen |
672 |
|
| 171 |
farthen |
673 |
@command
|
| 176 |
farthen |
674 |
def runfirmware(self, addr, filename):
|
| 171 |
farthen |
675 |
"""
|
| 176 |
farthen |
676 |
Uploads the firmware in 'filename' to the beginning of the
|
|
|
677 |
user memory and executes it
|
| 171 |
farthen |
678 |
"""
|
| 176 |
farthen |
679 |
addr = self._hexint(addr)
|
|
|
680 |
self.uploadfile(addr, filename)
|
|
|
681 |
self.execfirmware(addr)
|
| 64 |
benedikt93 |
682 |
|
| 171 |
farthen |
683 |
@command
|
| 176 |
farthen |
684 |
def execfirmware(self, addr):
|
|
|
685 |
"""
|
|
|
686 |
Executes the firmware at addr
|
|
|
687 |
"""
|
|
|
688 |
addr = self._hexint(addr)
|
|
|
689 |
self.logger.info("Running firmware at "+self._hex(addr)+". Bye.")
|
|
|
690 |
self.embios.execfirmware(addr)
|
|
|
691 |
|
|
|
692 |
@command
|
| 171 |
farthen |
693 |
def aesencrypt(self, addr, size, keyindex):
|
|
|
694 |
"""
|
| 172 |
farthen |
695 |
Encrypts a buffer using a hardware key
|
| 171 |
farthen |
696 |
"""
|
|
|
697 |
addr = self._hexint(addr)
|
|
|
698 |
size = self._hexint(size)
|
|
|
699 |
keyindex = self._hexint(keyindex)
|
| 381 |
theseven |
700 |
self.embios.lib.dev.timeout = 30000
|
| 171 |
farthen |
701 |
self.embios.aesencrypt(addr, size, keyindex)
|
| 82 |
benedikt93 |
702 |
|
| 171 |
farthen |
703 |
@command
|
|
|
704 |
def aesdecrypt(self, addr, size, keyindex):
|
|
|
705 |
"""
|
| 172 |
farthen |
706 |
Decrypts a buffer using a hardware key
|
| 171 |
farthen |
707 |
"""
|
|
|
708 |
addr = self._hexint(addr)
|
|
|
709 |
size = self._hexint(size)
|
|
|
710 |
keyindex = self._hexint(keyindex)
|
| 381 |
theseven |
711 |
self.embios.lib.dev.timeout = 30000
|
| 171 |
farthen |
712 |
self.embios.aesdecrypt(addr, size, keyindex)
|
| 172 |
farthen |
713 |
|
|
|
714 |
@command
|
|
|
715 |
def hmac_sha1(self, addr, size, destination):
|
|
|
716 |
"""
|
|
|
717 |
Generates a HMAC-SHA1 hash of the buffer and saves it to 'destination'
|
|
|
718 |
"""
|
|
|
719 |
addr = self._hexint(addr)
|
|
|
720 |
size = self._hexint(size)
|
|
|
721 |
destination = self._hexint(destination)
|
|
|
722 |
sha1size = 0x14
|
| 382 |
farthen |
723 |
self.logger.info("Generating hmac-sha1 hash from the buffer at " + self._hex(addr) + \
|
|
|
724 |
" with the size " + self._hex(size) + " and saving it to " + \
|
|
|
725 |
self._hex(destination) + " - " + self._hex(destination+sha1size) + "...")
|
| 381 |
theseven |
726 |
self.embios.lib.dev.timeout = 30000
|
| 172 |
farthen |
727 |
self.embios.hmac_sha1(addr, size, destination)
|
|
|
728 |
self.logger.info("done\n")
|
| 178 |
farthen |
729 |
data = self.embios.read(destination, sha1size)
|
| 172 |
farthen |
730 |
hash = ord(data)
|
| 173 |
farthen |
731 |
self.logger.info("The generated hash is "+self._hex(hash))
|
| 64 |
benedikt93 |
732 |
|
| 227 |
theseven |
733 |
@command
|
|
|
734 |
def ipodnano2g_getnandinfo(self):
|
|
|
735 |
"""
|
|
|
736 |
Target-specific function: ipodnano2g
|
|
|
737 |
Gathers some information about the NAND chip used
|
|
|
738 |
"""
|
|
|
739 |
data = self.embios.ipodnano2g_getnandinfo()
|
| 382 |
farthen |
740 |
self.logger.info("NAND chip type: " + self._hex(data["type"])+"\n")
|
|
|
741 |
self.logger.info("Number of banks: " + str(data["banks"])+"\n")
|
|
|
742 |
self.logger.info("Number of blocks: " + str(data["blocks"])+"\n")
|
|
|
743 |
self.logger.info("Number of user blocks: " + str(data["userblocks"])+"\n")
|
|
|
744 |
self.logger.info("Pages per block: " + str(data["pagesperblock"]))
|
| 227 |
theseven |
745 |
|
|
|
746 |
@command
|
|
|
747 |
def ipodnano2g_nandread(self, addr, start, count, doecc, checkempty):
|
|
|
748 |
"""
|
|
|
749 |
Target-specific function: ipodnano2g
|
|
|
750 |
Reads data from the NAND chip into memory
|
|
|
751 |
"""
|
|
|
752 |
addr = self._hexint(addr)
|
|
|
753 |
start = self._hexint(start)
|
|
|
754 |
count = self._hexint(count)
|
|
|
755 |
doecc = int(doecc)
|
|
|
756 |
checkempty = int(checkempty)
|
| 382 |
farthen |
757 |
self.logger.info("Reading " + self._hex(count) + " NAND pages starting at " + \
|
|
|
758 |
self._hex(start) + " to " + self._hex(addr) + "...")
|
| 228 |
theseven |
759 |
self.embios.lib.dev.timeout = 30000
|
| 227 |
theseven |
760 |
self.embios.ipodnano2g_nandread(addr, start, count, doecc, checkempty)
|
|
|
761 |
self.logger.info("done\n")
|
|
|
762 |
|
|
|
763 |
@command
|
|
|
764 |
def ipodnano2g_nandwrite(self, addr, start, count, doecc):
|
|
|
765 |
"""
|
|
|
766 |
Target-specific function: ipodnano2g
|
|
|
767 |
Writes data to the NAND chip
|
|
|
768 |
"""
|
|
|
769 |
addr = self._hexint(addr)
|
|
|
770 |
start = self._hexint(start)
|
|
|
771 |
count = self._hexint(count)
|
|
|
772 |
doecc = int(doecc)
|
| 382 |
farthen |
773 |
self.logger.info("Writing " + self._hex(count) + " NAND pages starting at " + \
|
|
|
774 |
self._hex(start) + " from " + self._hex(addr) + "...")
|
| 228 |
theseven |
775 |
self.embios.lib.dev.timeout = 30000
|
| 227 |
theseven |
776 |
self.embios.ipodnano2g_nandwrite(addr, start, count, doecc)
|
|
|
777 |
self.logger.info("done\n")
|
|
|
778 |
|
|
|
779 |
@command
|
|
|
780 |
def ipodnano2g_nanderase(self, addr, start, count):
|
|
|
781 |
"""
|
|
|
782 |
Target-specific function: ipodnano2g
|
|
|
783 |
Erases blocks on the NAND chip and stores the results to memory
|
|
|
784 |
"""
|
|
|
785 |
addr = self._hexint(addr)
|
|
|
786 |
start = self._hexint(start)
|
|
|
787 |
count = self._hexint(count)
|
| 382 |
farthen |
788 |
self.logger.info("Erasing " + self._hex(count) + " NAND blocks starting at " + \
|
|
|
789 |
self._hex(start) + " and logging to " + self._hex(addr) + "...")
|
| 228 |
theseven |
790 |
self.embios.lib.dev.timeout = 30000
|
| 227 |
theseven |
791 |
self.embios.ipodnano2g_nanderase(addr, start, count)
|
|
|
792 |
self.logger.info("done\n")
|
|
|
793 |
|
| 228 |
theseven |
794 |
@command
|
|
|
795 |
def ipodnano2g_dumpnand(self, filenameprefix):
|
|
|
796 |
"""
|
|
|
797 |
Target-specific function: ipodnano2g
|
|
|
798 |
Dumps the whole NAND chip to four files
|
|
|
799 |
"""
|
|
|
800 |
info = self.embios.ipodnano2g_getnandinfo()
|
|
|
801 |
self.logger.info("Dumping NAND contents...")
|
|
|
802 |
try:
|
|
|
803 |
infofile = open(filenameprefix+"_info.txt", 'wb')
|
|
|
804 |
datafile = open(filenameprefix+"_data.bin", 'wb')
|
|
|
805 |
sparefile = open(filenameprefix+"_spare.bin", 'wb')
|
|
|
806 |
statusfile = open(filenameprefix+"_status.bin", 'wb')
|
|
|
807 |
except IOError:
|
|
|
808 |
raise ArgumentError("Can not open file for writing!")
|
| 382 |
farthen |
809 |
infofile.write("NAND chip type: " + self._hex(info["type"]) + "\r\n")
|
|
|
810 |
infofile.write("Number of banks: " + str(info["banks"]) + "\r\n")
|
|
|
811 |
infofile.write("Number of blocks: " + str(info["blocks"]) + "\r\n")
|
|
|
812 |
infofile.write("Number of user blocks: "+ str(info["userblocks"]) + "\r\n")
|
|
|
813 |
infofile.write("Pages per block: " + str(info["pagesperblock"]) + "\r\n")
|
| 228 |
theseven |
814 |
self.embios.lib.dev.timeout = 30000
|
|
|
815 |
for i in range(info["banks"] * info["blocks"] * info["pagesperblock"] / 8192):
|
|
|
816 |
self.logger.info(".")
|
|
|
817 |
self.embios.ipodnano2g_nandread(0x08000000, i * 8192, 8192, 1, 1)
|
|
|
818 |
datafile.write(self.embios.read(0x08000000, 0x01000000))
|
|
|
819 |
sparefile.write(self.embios.read(0x09000000, 0x00080000))
|
|
|
820 |
statusfile.write(self.embios.read(0x09080000, 0x00008000))
|
|
|
821 |
infofile.close()
|
|
|
822 |
datafile.close()
|
|
|
823 |
sparefile.close()
|
|
|
824 |
statusfile.close()
|
|
|
825 |
self.logger.info("done\n")
|
|
|
826 |
|
|
|
827 |
@command
|
|
|
828 |
def ipodnano2g_wipenand(self, filename, force=False):
|
|
|
829 |
"""
|
|
|
830 |
Target-specific function: ipodnano2g
|
|
|
831 |
Wipes the whole NAND chip and logs the result to a file
|
|
|
832 |
<force>: Use this flag to suppress the 5 seconds delay
|
|
|
833 |
"""
|
| 382 |
farthen |
834 |
self.logger.warn("Wiping the whole NAND chip!\n")
|
| 228 |
theseven |
835 |
if force == False:
|
| 382 |
farthen |
836 |
self.logger.warn("If this was not what you intended press Ctrl-C NOW")
|
| 228 |
theseven |
837 |
for i in range(10):
|
|
|
838 |
self.logger.info(".")
|
|
|
839 |
time.sleep(1)
|
|
|
840 |
self.logger.info("\n")
|
|
|
841 |
info = self.embios.ipodnano2g_getnandinfo()
|
|
|
842 |
self.logger.info("Wiping NAND contents...")
|
|
|
843 |
try:
|
|
|
844 |
statusfile = open(filename, 'wb')
|
|
|
845 |
except IOError:
|
|
|
846 |
raise ArgumentError("Can not open file for writing!")
|
|
|
847 |
self.embios.lib.dev.timeout = 30000
|
|
|
848 |
for i in range(info["banks"] * info["blocks"] / 64):
|
|
|
849 |
self.logger.info(".")
|
| 230 |
theseven |
850 |
self.embios.ipodnano2g_nanderase(0x08000000, i * 64, 64)
|
| 228 |
theseven |
851 |
statusfile.write(self.embios.read(0x08000000, 0x00000100))
|
|
|
852 |
statusfile.close()
|
|
|
853 |
self.logger.info("done\n")
|
|
|
854 |
|
| 346 |
theseven |
855 |
@command
|
|
|
856 |
def ipodclassic_writebbt(self, tempaddr, filename):
|
|
|
857 |
"""
|
|
|
858 |
Target-specific function: ipodclassic
|
|
|
859 |
Uploads the bad block table <filename> to
|
|
|
860 |
memory at <tempaddr> and writes it to the hard disk
|
|
|
861 |
"""
|
|
|
862 |
tempaddr = self._hexint(tempaddr)
|
|
|
863 |
try:
|
|
|
864 |
f = open(filename, 'rb')
|
|
|
865 |
except IOError:
|
|
|
866 |
raise ArgumentError("File not readable. Does it exist?")
|
|
|
867 |
self.embios.lib.dev.timeout = 30000
|
|
|
868 |
self.logger.info("Writing bad block table to disk...")
|
|
|
869 |
data = self.embios.ipodclassic_writebbt(f.read(), tempaddr)
|
|
|
870 |
f.close()
|
|
|
871 |
self.logger.info(" done\n")
|
|
|
872 |
|
|
|
873 |
@command
|
| 379 |
theseven |
874 |
def getvolumeinfo(self, volume):
|
|
|
875 |
"""
|
|
|
876 |
Gathers some information about a storage volume used
|
|
|
877 |
"""
|
|
|
878 |
volume = self._hexint(volume)
|
|
|
879 |
data = self.embios.storage_get_info(volume)
|
|
|
880 |
self.logger.info("Sector size: "+str(data["sectorsize"])+"\n")
|
|
|
881 |
self.logger.info("Number of sectors: "+str(data["numsectors"])+"\n")
|
|
|
882 |
self.logger.info("Vendor: "+data["vendor"]+"\n")
|
|
|
883 |
self.logger.info("Product: "+data["product"]+"\n")
|
|
|
884 |
self.logger.info("Revision: "+data["revision"])
|
|
|
885 |
|
|
|
886 |
@command
|
|
|
887 |
def readrawstorage(self, volume, sector, count, addr):
|
|
|
888 |
"""
|
|
|
889 |
Reads <count> sectors starting at <sector> from storage <volume> to memory at <addr>.
|
|
|
890 |
"""
|
|
|
891 |
volume = self._hexint(volume)
|
|
|
892 |
sector = self._hexint(sector)
|
|
|
893 |
count = self._hexint(count)
|
|
|
894 |
addr = self._hexint(addr)
|
|
|
895 |
self.logger.info("Reading volume %s sectors %X - %X to %08X..." % (volume, sector, sector + count - 1, addr))
|
|
|
896 |
self.embios.lib.dev.timeout = 50000
|
|
|
897 |
self.embios.storage_read_sectors_md(volume, sector, count, addr)
|
|
|
898 |
self.logger.info("done\n")
|
|
|
899 |
|
|
|
900 |
@command
|
|
|
901 |
def writerawstorage(self, volume, sector, count, addr):
|
|
|
902 |
"""
|
|
|
903 |
Writes memory contents at <addr> to <count> sectors starting at <sector> on storage <volume>.
|
|
|
904 |
"""
|
|
|
905 |
volume = self._hexint(volume)
|
|
|
906 |
sector = self._hexint(sector)
|
|
|
907 |
count = self._hexint(count)
|
|
|
908 |
addr = self._hexint(addr)
|
|
|
909 |
self.logger.info("Writing %08X to volume %s sectors %X - %X..." % (addr, volume, sector, sector + count - 1))
|
|
|
910 |
self.embios.lib.dev.timeout = 50000
|
|
|
911 |
self.embios.storage_write_sectors_md(volume, sector, count, addr)
|
|
|
912 |
self.logger.info("done\n")
|
|
|
913 |
|
|
|
914 |
@command
|
|
|
915 |
def readrawstoragefile(self, volume, sector, count, file, buffer = False, buffsize = "100000"):
|
|
|
916 |
"""
|
|
|
917 |
Reads <count> sectors starting at <sector> from storage <volume> to file <file>,
|
|
|
918 |
buffering them in memory at <buffer> in chunks of <buffsize> bytes (both optional).
|
|
|
919 |
"""
|
|
|
920 |
volume = self._hexint(volume)
|
|
|
921 |
sector = self._hexint(sector)
|
|
|
922 |
count = self._hexint(count)
|
|
|
923 |
if buffer == False: buffer = self.embios.lib.dev.usermem.lower
|
|
|
924 |
else: buffer = self._hexint(buffer)
|
|
|
925 |
buffsize = self._hexint(buffsize)
|
|
|
926 |
try:
|
|
|
927 |
f = open(file, 'wb')
|
|
|
928 |
except IOError:
|
|
|
929 |
raise ArgumentError("Could not open local file for writing.")
|
|
|
930 |
self.logger.info("Reading volume %s sectors %X - %X to %s..." % (volume, sector, sector + count - 1, file))
|
|
|
931 |
self.embios.lib.dev.timeout = 50000
|
|
|
932 |
storageinfo = self.embios.storage_get_info(volume)
|
|
|
933 |
while count > 0:
|
|
|
934 |
sectors = min(count, int(buffsize / storageinfo.sectorsize))
|
|
|
935 |
self.embios.storage_read_sectors_md(volume, sector, sectors, buffer)
|
|
|
936 |
f.write(self.embios.read(buffer, storageinfo.sectorsize * sectors))
|
|
|
937 |
sector = sector + sectors
|
|
|
938 |
count = count - sectors
|
|
|
939 |
f.close()
|
|
|
940 |
self.logger.info("done\n")
|
|
|
941 |
|
|
|
942 |
@command
|
|
|
943 |
def writerawstoragefile(self, volume, sector, count, file, buffer = False, buffsize = "100000"):
|
|
|
944 |
"""
|
|
|
945 |
Writes contents of <file> to <count> sectors starting at <sector> on storage <volume>,
|
|
|
946 |
buffering them in memory at <buffer> in chunks of <buffsize> bytes (both optional).
|
|
|
947 |
"""
|
|
|
948 |
volume = self._hexint(volume)
|
|
|
949 |
sector = self._hexint(sector)
|
|
|
950 |
count = self._hexint(count)
|
|
|
951 |
if buffer == False: buffer = self.embios.lib.dev.usermem.lower
|
|
|
952 |
else: buffer = self._hexint(buffer)
|
|
|
953 |
buffsize = self._hexint(buffsize)
|
|
|
954 |
try:
|
|
|
955 |
f = open(file, 'rb')
|
|
|
956 |
except IOError:
|
|
|
957 |
raise ArgumentError("Could not open local file for reading.")
|
|
|
958 |
self.logger.info("Writing %s to volume %s sectors %X - %X..." % (file, volume, sector, sector + count - 1))
|
|
|
959 |
self.embios.lib.dev.timeout = 50000
|
|
|
960 |
storageinfo = self.embios.storage_get_info(volume)
|
|
|
961 |
while count > 0:
|
|
|
962 |
sectors = min(count, int(buffsize / storageinfo.sectorsize))
|
|
|
963 |
bytes = storageinfo.sectorsize * sectors
|
|
|
964 |
data = f.read(bytes)
|
|
|
965 |
if len(data) == 0: break
|
|
|
966 |
while len(data) < bytes: data = data + f.read(bytes - len(data))
|
|
|
967 |
self.embios.write(buffer, data)
|
|
|
968 |
self.embios.storage_write_sectors_md(volume, sector, sectors, buffer)
|
|
|
969 |
sector = sector + sectors
|
|
|
970 |
count = count - sectors
|
|
|
971 |
f.close()
|
|
|
972 |
self.logger.info("done\n")
|
|
|
973 |
|
|
|
974 |
@command
|
| 346 |
theseven |
975 |
def mkdir(self, dirname):
|
|
|
976 |
"""
|
|
|
977 |
Creates a directory
|
|
|
978 |
"""
|
|
|
979 |
self.embios.lib.dev.timeout = 30000
|
|
|
980 |
self.logger.info("Creating directory " + dirname + "...")
|
|
|
981 |
self.embios.dir_create(dirname)
|
|
|
982 |
self.logger.info(" done\n")
|
|
|
983 |
|
|
|
984 |
@command
|
|
|
985 |
def rmdir(self, dirname):
|
|
|
986 |
"""
|
|
|
987 |
Removes an empty directory
|
|
|
988 |
"""
|
|
|
989 |
self.embios.lib.dev.timeout = 30000
|
|
|
990 |
self.logger.info("Removing directory " + dirname + "...")
|
|
|
991 |
self.embios.dir_remove(dirname)
|
|
|
992 |
self.logger.info(" done\n")
|
|
|
993 |
|
|
|
994 |
@command
|
| 349 |
theseven |
995 |
def rm(self, filename):
|
| 346 |
theseven |
996 |
"""
|
|
|
997 |
Removes a file
|
|
|
998 |
"""
|
|
|
999 |
self.embios.lib.dev.timeout = 30000
|
|
|
1000 |
self.logger.info("Removing file " + filename + "...")
|
|
|
1001 |
self.embios.file_unlink(filename)
|
|
|
1002 |
self.logger.info(" done\n")
|
|
|
1003 |
|
|
|
1004 |
@command
|
| 352 |
theseven |
1005 |
def mv(self, oldname, newname):
|
| 350 |
theseven |
1006 |
"""
|
| 352 |
theseven |
1007 |
Renames or moves a file or directory
|
| 350 |
theseven |
1008 |
"""
|
|
|
1009 |
self.embios.lib.dev.timeout = 30000
|
|
|
1010 |
self.logger.info("Renaming " + oldname + " to " + newname + "...")
|
|
|
1011 |
self.embios.file_rename(oldname, newname)
|
|
|
1012 |
self.logger.info(" done\n")
|
|
|
1013 |
|
|
|
1014 |
@command
|
| 351 |
theseven |
1015 |
def get(self, remotename, localname, buffer = False, buffsize = "10000"):
|
| 346 |
theseven |
1016 |
"""
|
|
|
1017 |
Downloads a file
|
|
|
1018 |
"""
|
| 351 |
theseven |
1019 |
if buffer == False: buffer = self.embios.lib.dev.usermem.lower
|
|
|
1020 |
else: buffer = self._hexint(buffer)
|
| 346 |
theseven |
1021 |
buffsize = self._hexint(buffsize)
|
|
|
1022 |
try:
|
|
|
1023 |
f = open(localname, 'wb')
|
|
|
1024 |
except IOError:
|
|
|
1025 |
raise ArgumentError("Could not open local file for writing.")
|
|
|
1026 |
self.embios.lib.dev.timeout = 30000
|
|
|
1027 |
self.logger.info("Downloading file " + remotename + " to " + localname + "...")
|
|
|
1028 |
fd = self.embios.file_open(remotename, 0)
|
|
|
1029 |
size = self.embios.file_size(fd)
|
|
|
1030 |
while size > 0:
|
| 370 |
theseven |
1031 |
bytes = self.embios.file_read(fd, buffer, buffsize)
|
| 346 |
theseven |
1032 |
f.write(self.embios.read(buffer, bytes))
|
|
|
1033 |
size = size - bytes
|
|
|
1034 |
self.embios.file_close(fd)
|
|
|
1035 |
f.close()
|
|
|
1036 |
self.logger.info(" done\n")
|
|
|
1037 |
|
|
|
1038 |
@command
|
| 351 |
theseven |
1039 |
def put(self, localname, remotename, buffer = False, buffsize = "10000"):
|
| 346 |
theseven |
1040 |
"""
|
|
|
1041 |
Uploads a file
|
|
|
1042 |
"""
|
| 351 |
theseven |
1043 |
if buffer == False: buffer = self.embios.lib.dev.usermem.lower
|
|
|
1044 |
else: buffer = self._hexint(buffer)
|
| 346 |
theseven |
1045 |
buffsize = self._hexint(buffsize)
|
|
|
1046 |
try:
|
|
|
1047 |
f = open(localname, 'rb')
|
|
|
1048 |
except IOError:
|
|
|
1049 |
raise ArgumentError("Could not open local file for reading.")
|
|
|
1050 |
self.embios.lib.dev.timeout = 30000
|
|
|
1051 |
self.logger.info("Uploading file " + localname + " to " + remotename + "...")
|
|
|
1052 |
fd = self.embios.file_open(remotename, 0x15)
|
|
|
1053 |
while True:
|
|
|
1054 |
data = f.read(buffsize)
|
|
|
1055 |
if len(data) == 0: break
|
|
|
1056 |
self.embios.write(buffer, data)
|
|
|
1057 |
bytes = 0
|
|
|
1058 |
while bytes < len(data):
|
|
|
1059 |
bytes = bytes + self.embios.file_write(fd, buffer + bytes, len(data) - bytes)
|
|
|
1060 |
self.embios.file_close(fd)
|
|
|
1061 |
f.close()
|
|
|
1062 |
self.logger.info(" done\n")
|
|
|
1063 |
|
|
|
1064 |
@command
|
| 351 |
theseven |
1065 |
def ls(self, path = "/"):
|
| 346 |
theseven |
1066 |
"""
|
|
|
1067 |
Lists all files in the specified path
|
|
|
1068 |
"""
|
|
|
1069 |
self.embios.lib.dev.timeout = 30000
|
|
|
1070 |
handle = self.embios.dir_open(path)
|
|
|
1071 |
self.logger.info("Directory listing of " + path + ":\n")
|
|
|
1072 |
while True:
|
|
|
1073 |
try:
|
|
|
1074 |
entry = self.embios.dir_read(handle)
|
|
|
1075 |
if entry.attributes & 0x10: size = "DIR"
|
|
|
1076 |
else: size = locale.format("%d", entry.size, True).rjust(13)
|
|
|
1077 |
self.logger.info(entry.name.ljust(50) + " - " + size + "\n")
|
|
|
1078 |
except: break
|
|
|
1079 |
self.embios.dir_close(handle)
|
|
|
1080 |
|
| 171 |
farthen |
1081 |
if __name__ == "__main__":
|
|
|
1082 |
if len(sys.argv) < 2:
|
|
|
1083 |
usage("No command specified")
|
| 382 |
farthen |
1084 |
try:
|
|
|
1085 |
interface = Commandline()
|
|
|
1086 |
interface._parsecommand(sys.argv[1], sys.argv[2:])
|
|
|
1087 |
except KeyboardInterrupt:
|
|
|
1088 |
sys.exit()
|