Index: embios/trunk/tools/embios.py |
— | — | @@ -180,7 +180,11 @@ |
181 | 181 | except libembios.DeviceNotFoundError:
|
182 | 182 | self.logger.error("No emBIOS device found!")
|
183 | 183 | end(1)
|
184 | | - self.getinfo("version")
|
| 184 | + try:
|
| 185 | + self.getinfo("version")
|
| 186 | + except libembios.DeviceNotFoundError:
|
| 187 | + self.logger.error("Device not found!")
|
| 188 | + exit(2)
|
185 | 189 |
|
186 | 190 | def _parsecommand(self, func, args):
|
187 | 191 | # adds self to the commandline args.
|
— | — | @@ -197,8 +201,6 @@ |
198 | 202 | usage(e)
|
199 | 203 | except NotImplementedError:
|
200 | 204 | self.logger.error("This function is not implemented yet!")
|
201 | | - except libembios.DeviceNotFoundError:
|
202 | | - self.logger.error("Device not found!")
|
203 | 205 | except libembios.DeviceError, e:
|
204 | 206 | self.logger.error(str(e))
|
205 | 207 | except TypeError, e:
|
— | — | @@ -257,6 +259,9 @@ |
258 | 260 | expected = expected[:-2]
|
259 | 261 | raise ArgumentTypeError("one out of " + expected, "'" + string + "'")
|
260 | 262 |
|
| 263 | + @staticmethod
|
| 264 | + def _hex(integer):
|
| 265 | + return "0x%x" % integer
|
261 | 266 |
|
262 | 267 | @command
|
263 | 268 | def getinfo(self, infotype):
|
— | — | @@ -273,7 +278,7 @@ |
274 | 279 | self.logger.info("Maximum packet sizes: "+str(resp))
|
275 | 280 | elif infotype == "usermemrange":
|
276 | 281 | resp = self.embios.getusermemrange()
|
277 | | - self.logger.info("The user memory range is "+hex(resp.lower)+" - "+hex(resp.upper-1))
|
| 282 | + self.logger.info("The user memory range is "+self._hex(resp.lower)+" - "+self._hex(resp.upper-1))
|
278 | 283 | else:
|
279 | 284 | raise ArgumentTypeError("one out of 'version', 'packetsize', 'usermemrange'", infotype)
|
280 | 285 |
|
— | — | @@ -313,7 +318,7 @@ |
314 | 319 | f = open(filename, 'rb')
|
315 | 320 | except IOError:
|
316 | 321 | raise ArgumentError("File not readable. Does it exist?")
|
317 | | - self.logger.info("Writing file '"+filename+"' to memory at "+hex(addr)+"...")
|
| 322 | + self.logger.info("Writing file '"+filename+"' to memory at "+self._hex(addr)+"...")
|
318 | 323 | with f:
|
319 | 324 | self.embios.write(addr, f.read())
|
320 | 325 | self.logger.info("done\n")
|
— | — | @@ -334,7 +339,7 @@ |
335 | 340 | f = open(filename, 'wb')
|
336 | 341 | except IOError:
|
337 | 342 | raise ArgumentError("Can not open file for write!")
|
338 | | - self.logger.info("Reading data from address "+hex(addr)+" with the size "+hex(size)+" to '"+filename+"'...")
|
| 343 | + self.logger.info("Reading data from address "+self._hex(addr)+" with the size "+self._hex(size)+" to '"+filename+"'...")
|
339 | 344 | with f:
|
340 | 345 | f.write(self.embios.read(addr, size))
|
341 | 346 | self.logger.info("done\n")
|
— | — | @@ -352,7 +357,7 @@ |
353 | 358 | raise ArgumentError("Specified integer too long")
|
354 | 359 | data = chr(integer)
|
355 | 360 | self.embios.writemem(addr, data)
|
356 | | - self.logger.info("Integer '"+hex(integer)+"' written successfully to "+hex(addr))
|
| 361 | + self.logger.info("Integer '"+self._hex(integer)+"' written successfully to "+self._hex(addr))
|
357 | 362 |
|
358 | 363 | @command
|
359 | 364 | def downloadint(self, addr):
|
— | — | @@ -363,7 +368,7 @@ |
364 | 369 | addr = self._hexint(addr)
|
365 | 370 | data = self.embios.readmem(addr, 1)
|
366 | 371 | integer = ord(data)
|
367 | | - self.logger.info("Integer '"+hex(integer)+"' read from address "+hex(addr))
|
| 372 | + self.logger.info("Integer '"+self._hex(integer)+"' read from address "+self._hex(addr))
|
368 | 373 |
|
369 | 374 | @command
|
370 | 375 | def i2crecv(self, bus, slave, addr, size):
|
— | — | @@ -420,7 +425,7 @@ |
421 | 426 | Writes the file <file> to the USB console.
|
422 | 427 | Optional params <offset> <length>: specify the range in <file> to write
|
423 | 428 | """
|
424 | | - # We don't care about file here, this is done when opening it
|
| 429 | +
|
425 | 430 | offset = self._hexint(offset)
|
426 | 431 | length = self._hexint(length)
|
427 | 432 | raise NotImplementedError
|
— | — | @@ -457,7 +462,7 @@ |
458 | 463 | Optional params <offset> <length>: specify the range in <file> to write
|
459 | 464 | """
|
460 | 465 | bitmask = self._hexint(bitmask)
|
461 | | - # We don't care about file here, this is done when opening it
|
| 466 | +
|
462 | 467 | offset = self._hexint(offset)
|
463 | 468 | length = self._hexint(length)
|
464 | 469 | raise NotImplementedError
|
— | — | @@ -487,18 +492,30 @@ |
488 | 493 | def getprocinfo(self):
|
489 | 494 | """
|
490 | 495 | Fetches data on the currently running processes
|
491 | | - ATTENTION: this function will be print the information to the console window.
|
492 | | - If several threads are running this might overflow the window,
|
493 | | - causing not everything to be shown.
|
494 | 496 | """
|
495 | | - raise NotImplementedError
|
496 | | -
|
| 497 | + import datetime
|
| 498 | + threads = self.embios.getprocinfo()
|
| 499 | + self.logger.info("The device has "+str(len(threads))+" running threads:\n\n")
|
| 500 | + for thread in threads:
|
| 501 | + self.logger.info(" "+thread.name+":\n")
|
| 502 | + self.logger.info(" Thread id: "+str(thread.id)+"\n")
|
| 503 | + self.logger.info(" Thread type: "+thread.type+"\n")
|
| 504 | + self.logger.info(" Thread state: "+thread.state+"\n")
|
| 505 | + self.logger.info(" Priority: "+str(thread.priority)+"/256\n")
|
| 506 | + self.logger.info(" CPU time (total): "+str(datetime.timedelta(microseconds=thread.cputime_total))+"\n")
|
| 507 | + self.logger.info(" Stack address: "+self._hex(thread.stackaddr)+"\n")
|
| 508 | + self.logger.info(" Registers:\n")
|
| 509 | + for register in range(16):
|
| 510 | + self.logger.info(" r"+str(register)+": "+self._hex(thread.regs["r"+str(register)])+"\n")
|
| 511 | + self.logger.info(" cpsr: "+self._hex(thread.regs.cpsr))
|
| 512 | + self.logger.info("\n")
|
| 513 | +
|
497 | 514 | @command
|
498 | 515 | def lockscheduler(self):
|
499 | 516 | """
|
500 | 517 | Locks (freezes) the scheduler
|
501 | 518 | """
|
502 | | - raise NotImplementedError
|
| 519 | + self.embios.lockscheduler()
|
503 | 520 |
|
504 | 521 | @command
|
505 | 522 | def unlockscheduler(self):
|
— | — | @@ -505,7 +522,7 @@ |
506 | 523 | """
|
507 | 524 | Unlocks (unfreezes) the scheduler
|
508 | 525 | """
|
509 | | - raise NotImplementedError
|
| 526 | + self.embios.unlockscheduler()
|
510 | 527 |
|
511 | 528 | @command
|
512 | 529 | def suspendthread(self, threadid):
|
— | — | @@ -513,7 +530,7 @@ |
514 | 531 | Suspends/resumes the thread with thread ID <threadid>
|
515 | 532 | """
|
516 | 533 | threadid = self._hexint(threadid)
|
517 | | - raise NotImplementedError
|
| 534 | + self.embios.resumethread(threadid)
|
518 | 535 |
|
519 | 536 | @command
|
520 | 537 | def resumethread(self, threadid):
|
— | — | @@ -521,7 +538,7 @@ |
522 | 539 | Resumes the thread with thread ID <threadid>
|
523 | 540 | """
|
524 | 541 | threadid = self._hexint(threadid)
|
525 | | - raise NotImplementedError
|
| 542 | + self.embios.resumethread(threadid)
|
526 | 543 |
|
527 | 544 | @command
|
528 | 545 | def killthread(self, threadid):
|
— | — | @@ -529,7 +546,7 @@ |
530 | 547 | Kills the thread with thread ID <threadid>
|
531 | 548 | """
|
532 | 549 | threadid = self._hexint(threadid)
|
533 | | - raise NotImplementedError
|
| 550 | + self.embios.killthread(threadid)
|
534 | 551 |
|
535 | 552 | @command
|
536 | 553 | def createthread(self, nameptr, entrypoint, stackptr, stacksize, threadtype, priority, state):
|
— | — | @@ -553,8 +570,8 @@ |
554 | 571 | @command
|
555 | 572 | def run(self, filename):
|
556 | 573 | """
|
557 | | - Uploads the emBIOS application to an address in the user memory
|
558 | | - and executes it
|
| 574 | + Uploads the emBIOS application <filename> to
|
| 575 | + the beginning of the user memory and executes it
|
559 | 576 | """
|
560 | 577 | try:
|
561 | 578 | f = open(filename, "rb")
|
— | — | @@ -566,17 +583,17 @@ |
567 | 584 | filesize = os.path.getsize(filename)
|
568 | 585 | if filesize > maxsize:
|
569 | 586 | raise ArgumentError("The file is too big, it doesn't fit into the user memory.")
|
570 | | - self.logger.info("Uploading application to "+hex(addr)+" - "+hex(addr+filesize)+"\n")
|
| 587 | + self.logger.info("Uploading application to "+self._hex(addr)+" - "+self._hex(addr+filesize)+"\n")
|
571 | 588 | self.embios.write(addr, f.read())
|
572 | | - self.execute(addr)
|
| 589 | + self.execimage(addr)
|
573 | 590 |
|
574 | 591 | @command
|
575 | | - def execute(self, addr):
|
| 592 | + def execimage(self, addr):
|
576 | 593 | """
|
577 | | - Executes the emBIOS application at <address>.
|
| 594 | + Executes the emBIOS application at <addr>.
|
578 | 595 | """
|
579 | 596 | addr = self._hexint(addr)
|
580 | | - self.logger.info("Starting emBIOS app at "+hex(addr)+"\n")
|
| 597 | + self.logger.info("Starting emBIOS app at "+self._hex(addr)+"\n")
|
581 | 598 | self.embios.execimage(addr)
|
582 | 599 |
|
583 | 600 | @command
|
— | — | @@ -643,13 +660,13 @@ |
644 | 661 | size = self._hexint(size)
|
645 | 662 | destination = self._hexint(destination)
|
646 | 663 | sha1size = 0x14
|
647 | | - self.logger.info("Generating hmac-sha1 hash from the buffer at "+hex(addr)+" with the size "+hex(size)+
|
648 | | - " and saving it to "+hex(destination)+" - "+hex(destination+sha1size)+"...")
|
| 664 | + self.logger.info("Generating hmac-sha1 hash from the buffer at "+self._hex(addr)+" with the size "+self._hex(size)+
|
| 665 | + " and saving it to "+self._hex(destination)+" - "+self._hex(destination+sha1size)+"...")
|
649 | 666 | self.embios.hmac_sha1(addr, size, destination)
|
650 | 667 | self.logger.info("done\n")
|
651 | 668 | data = self.embios.readmem(destination, sha1size)
|
652 | 669 | hash = ord(data)
|
653 | | - self.logger.info("The generated hash is "+hex(hash))
|
| 670 | + self.logger.info("The generated hash is "+self._hex(hash))
|
654 | 671 |
|
655 | 672 | if __name__ == "__main__":
|
656 | 673 | if len(sys.argv) < 2:
|
Index: embios/trunk/tools/libembiosdata.py |
— | — | @@ -1,3 +1,28 @@ |
| 2 | +thread_state = (
|
| 3 | + "THREAD_FREE",
|
| 4 | + "THREAD_SUSPENDED",
|
| 5 | + "THREAD_READY",
|
| 6 | + "THREAD_RUNNING",
|
| 7 | + "THREAD_BLOCKED",
|
| 8 | + "THREAD_DEFUNCT",
|
| 9 | + "THREAD_DEFUNCT_ACK"
|
| 10 | +)
|
| 11 | +
|
| 12 | +thread_block = (
|
| 13 | + "THREAD_NOT_BLOCKED",
|
| 14 | + "THREAD_BLOCK_SLEEP",
|
| 15 | + "THREAD_BLOCK_MUTEX",
|
| 16 | + "THREAD_BLOCK_WAKEUP",
|
| 17 | + "THREAD_DEFUNCT_STKOV",
|
| 18 | + "THREAD_DEFUNCT_PANIC"
|
| 19 | +)
|
| 20 | +
|
| 21 | +thread_type = (
|
| 22 | + "USER_THREAD",
|
| 23 | + "OS_THREAD",
|
| 24 | + "ORE_THREAD"
|
| 25 | +)
|
| 26 | +
|
2 | 27 | hwtypes = {
|
3 | 28 | 0: "invalid",
|
4 | 29 | 0x47324e49: "iPod nano 2g",
|
Index: embios/trunk/tools/libembios.py |
— | — | @@ -199,6 +199,23 @@ |
200 | 200 | self.lib.monitorcommand(struct.pack("IIII", 7, addr, len(data), 0), "III", (None, None, None))
|
201 | 201 | return self.lib.dev.dout(data)
|
202 | 202 |
|
| 203 | + def readstring(self, addr, maxlength = 256):
|
| 204 | + """ Reads a zero terminated string from memory
|
| 205 | + Reads only a maximum of 'maxlength' chars.
|
| 206 | + """
|
| 207 | + cin_maxsize = self.lib.dev.packetsizelimit["cin"] - 0x10
|
| 208 | + string = ""
|
| 209 | + while (len(string) < maxlength or maxlength < 0):
|
| 210 | + data = self.readmem(addr, min(maxlength - len(string), cin_maxsize))
|
| 211 | + length = data.find("\0")
|
| 212 | + if length >= 0:
|
| 213 | + string += data[:length]
|
| 214 | + break
|
| 215 | + else:
|
| 216 | + string += data
|
| 217 | + addr += cin_maxsize
|
| 218 | + return string
|
| 219 | +
|
203 | 220 | def i2cread(self, index, slaveaddr, startaddr, size):
|
204 | 221 | """ Reads data from an i2c slave """
|
205 | 222 |
|
— | — | @@ -225,23 +242,89 @@ |
226 | 243 | """ Flushes the consoles specified with 'bitmask' """
|
227 | 244 | return self.lib.monitorcommand(struct.pack("IIII", 14, bitmask, 0, 0), "III", (None, None, None))
|
228 | 245 |
|
229 | | - def getprocinfo(self, offset, size):
|
| 246 | + def getprocinfo(self):
|
230 | 247 | """ Gets current state of the scheduler """
|
| 248 | + cin_maxsize = self.lib.dev.packetsizelimit["cin"] - 0x10
|
| 249 | + # Get the size
|
| 250 | + schedulerstate = self.lockscheduler()
|
| 251 | + resp = self.lib.monitorcommand(struct.pack("IIII", 15, 0, 0, 0), "III", ("structver", "tablesize", None))
|
| 252 | + tablesize = resp.tablesize
|
| 253 | + size = tablesize
|
| 254 | + structver = resp.structver
|
| 255 | + offset = 0
|
| 256 | + data = ""
|
| 257 | + while size > 0:
|
| 258 | + if size > cin_maxsize:
|
| 259 | + readsize = cin_maxsize
|
| 260 | + else:
|
| 261 | + readsize = size
|
| 262 | + resp = self.lib.monitorcommand(struct.pack("IIII", 15, offset, readsize, 0), "III%ds" % readsize, ("structver", "tablesize", None, "data"))
|
| 263 | + data += resp.data
|
| 264 | + offset += readsize
|
| 265 | + size -= readsize
|
| 266 | + self.lockscheduler(schedulerstate)
|
| 267 | + threadstructsize = 120
|
| 268 | + registersize = 32
|
| 269 | + if len(data) % threadstructsize != 0:
|
| 270 | + raise DeviceError("The thread struct is not a multiple of "+str(threadsturcsize)+"!")
|
| 271 | + threadcount = len(data) / threadstructsize
|
| 272 | + threads = []
|
| 273 | + id = 0
|
| 274 | + for thread in range(threadcount):
|
| 275 | + offset = threadstructsize * thread
|
| 276 | + threaddata = struct.unpack("<16IIIIIQIIIIIIIBBBB", data[offset:offset+threadstructsize])
|
| 277 | + info = Bunch()
|
| 278 | + info.id = id
|
| 279 | + state = threaddata[17]
|
| 280 | + info.state = libembiosdata.thread_state[state]
|
| 281 | + if info.state == "THREAD_FREE":
|
| 282 | + id += 1
|
| 283 | + continue
|
| 284 | + info.regs = Bunch()
|
| 285 | + for register in range(16):
|
| 286 | + info.regs["r"+str(register)] = threaddata[register]
|
| 287 | + info.regs.cpsr = threaddata[16]
|
| 288 | + info.nameptr = threaddata[18]
|
| 289 | + if info.nameptr == 0:
|
| 290 | + info.name = "Thread %d" % info.id
|
| 291 | + else:
|
| 292 | + info.name = self.readstring(info.nameptr)
|
| 293 | + info.cputime_current = threaddata[19]
|
| 294 | + info.cputime_total = threaddata[20]
|
| 295 | + info.startusec = threaddata[21]
|
| 296 | + info.queue_next_ptr = threaddata[22]
|
| 297 | + info.timeout = threaddata[23]
|
| 298 | + info.blocked_since = threaddata[24]
|
| 299 | + info.blocked_by_ptr = threaddata[25]
|
| 300 | + info.stackaddr = threaddata[26]
|
| 301 | + info.err_no = threaddata[27]
|
| 302 | + info.block_type = libembiosdata.thread_block[threaddata[28]]
|
| 303 | + info.type = libembiosdata.thread_type[threaddata[29]]
|
| 304 | + info.priority = threaddata[30]
|
| 305 | + info.cpuload = threaddata[31]
|
| 306 | + threads.append(info)
|
| 307 | + id += 1
|
| 308 | + return threads
|
| 309 | +
|
| 310 | +
|
| 311 | + return self.lib.monitorcommand(struct.pack("IIII", 15, offset, size, 0), "III%ds" % size, ("structver", "tablesize", None, "data"))
|
231 | 312 |
|
232 | | - def freezescheduler(self, freeze=True):
|
| 313 | + def lockscheduler(self, freeze=True):
|
233 | 314 | """ Freezes/Unfreezes the scheduler """
|
234 | | - return self.lib.monitorcommand(struct.pack("IIII", 16, 1 if freeze else 0, 0, 0), "III", ("before", None, None))
|
| 315 | + resp = self.lib.monitorcommand(struct.pack("IIII", 16, 1 if freeze else 0, 0, 0), "III", ("before", None, None))
|
| 316 | + return True if resp.before == 1 else False
|
235 | 317 |
|
236 | | - def unfreezescheduler(self):
|
| 318 | + def unlockscheduler(self):
|
237 | 319 | """ Unfreezes the scheduler """
|
238 | 320 | return self.lib.monitorcommand(struct.pack("IIII", 16, 0, 0, 0), "III", ("before", None, None))
|
239 | 321 |
|
240 | 322 | def suspendthread(self, id, suspend=True):
|
241 | 323 | """ 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))
|
| 324 | + resp = self.lib.monitorcommand(struct.pack("IIII", 17, 1 if suspend else 0, id, 0), "III", ("before", None, None))
|
| 325 | + return True if resp.before == 1 else False
|
243 | 326 |
|
244 | | - def unsuspendthread(self, id):
|
245 | | - """ Suspends the thread with the specified id """
|
| 327 | + def resumethread(self, id):
|
| 328 | + """ Resumes the thread with the specified id """
|
246 | 329 | return self.lib.monitorcommand(struct.pack("IIII", 17, 0, id, 0), "III", ("before", None, None))
|
247 | 330 |
|
248 | 331 | def killthread(self, id):
|