Index: embios/trunk/tools/embiosldr.py |
— | — | @@ -0,0 +1,80 @@ |
| 2 | +#!/usr/bin/env python
|
| 3 | +#
|
| 4 | +#
|
| 5 | +# Copyright 2010 TheSeven
|
| 6 | +#
|
| 7 | +#
|
| 8 | +# This file is part of emBIOS.
|
| 9 | +#
|
| 10 | +# emBIOS is free software: you can redistribute it and/or
|
| 11 | +# modify it under the terms of the GNU General Public License as
|
| 12 | +# published by the Free Software Foundation, either version 2 of the
|
| 13 | +# License, or (at your option) any later version.
|
| 14 | +#
|
| 15 | +# emBIOS is distributed in the hope that it will be useful,
|
| 16 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 17 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
| 18 | +# See the GNU General Public License for more details.
|
| 19 | +#
|
| 20 | +# You should have received a copy of the GNU General Public License along
|
| 21 | +# with emBIOS. If not, see <http://www.gnu.org/licenses/>.
|
| 22 | +#
|
| 23 | +#
|
| 24 | +
|
| 25 | +
|
| 26 | +import sys
|
| 27 | +import time
|
| 28 | +import libembiosldr
|
| 29 | +
|
| 30 | +
|
| 31 | +def usage():
|
| 32 | + print ""
|
| 33 | + print "Please provide a command and (if needed) parameters as command line arguments"
|
| 34 | + print ""
|
| 35 | + print "Available commands:"
|
| 36 | + print ""
|
| 37 | + print " upload <address> <file>"
|
| 38 | + print " Uploads the specified file to the specified memory address on the device."
|
| 39 | + print ""
|
| 40 | + print " download <address> <size> <file>"
|
| 41 | + print " Downloads <size> bytes of data from the specified address on the device,"
|
| 42 | + print " and stores it in the specified file."
|
| 43 | + print ""
|
| 44 | + print " execute <address> <stack>"
|
| 45 | + print " Executes code at the specified address in the device's memory."
|
| 46 | + print " The stack pointer will be set to <stack> before jumping to <address>."
|
| 47 | + print " iBugger will probably lose control of the device,"
|
| 48 | + print " if the code isn't explicitly written for it."
|
| 49 | + print ""
|
| 50 | + print " run <file>"
|
| 51 | + print " Loads the specified file to 0x08000000 (SDRAM) and executes it."
|
| 52 | + print " This is what you usually want to do."
|
| 53 | + print ""
|
| 54 | + print "All numbers are hexadecimal!"
|
| 55 | + exit(2)
|
| 56 | +
|
| 57 | +
|
| 58 | +def parsecommand(dev, argv):
|
| 59 | + if len(argv) < 2: usage()
|
| 60 | +
|
| 61 | + elif argv[1] == "upload":
|
| 62 | + if len(argv) != 4: usage()
|
| 63 | + dev.upload(int(argv[2], 16), argv[3])
|
| 64 | +
|
| 65 | + elif argv[1] == "download":
|
| 66 | + if len(argv) != 5: usage()
|
| 67 | + dev.download(int(argv[2], 16), int(argv[3], 16), argv[4])
|
| 68 | +
|
| 69 | + elif argv[1] == "execute":
|
| 70 | + if len(argv) != 4: usage()
|
| 71 | + dev.execute(int(argv[2], 16), int(argv[3], 16))
|
| 72 | +
|
| 73 | + elif argv[1] == "run":
|
| 74 | + if len(argv) != 3: usage()
|
| 75 | + dev.run(argv[2])
|
| 76 | +
|
| 77 | + else: usage()
|
| 78 | +
|
| 79 | +
|
| 80 | +dev = libembiosldr.embiosldr()
|
| 81 | +parsecommand(dev, sys.argv)
|
Index: embios/trunk/tools/libembiosldr.py |
— | — | @@ -0,0 +1,177 @@ |
| 2 | +#!/usr/bin/env python
|
| 3 | +#
|
| 4 | +#
|
| 5 | +# Copyright 2010 TheSeven
|
| 6 | +#
|
| 7 | +#
|
| 8 | +# This file is part of emBIOS.
|
| 9 | +#
|
| 10 | +# emBIOS is free software: you can redistribute it and/or
|
| 11 | +# modify it under the terms of the GNU General Public License as
|
| 12 | +# published by the Free Software Foundation, either version 2 of the
|
| 13 | +# License, or (at your option) any later version.
|
| 14 | +#
|
| 15 | +# emBIOS is distributed in the hope that it will be useful,
|
| 16 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 17 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
| 18 | +# See the GNU General Public License for more details.
|
| 19 | +#
|
| 20 | +# You should have received a copy of the GNU General Public License along
|
| 21 | +# with emBIOS. If not, see <http://www.gnu.org/licenses/>.
|
| 22 | +#
|
| 23 | +#
|
| 24 | +
|
| 25 | +
|
| 26 | +import sys
|
| 27 | +import math
|
| 28 | +import struct
|
| 29 | +import time
|
| 30 | +import usb
|
| 31 | +
|
| 32 | +
|
| 33 | +class embiosldr:
|
| 34 | + def __init__(self, generation = 0):
|
| 35 | + busses = usb.busses()
|
| 36 | +
|
| 37 | + for bus in busses:
|
| 38 | + devices = bus.devices
|
| 39 | + for dev in devices:
|
| 40 | + if dev.idVendor == 0xffff and dev.idProduct == 0xe112:
|
| 41 | + handle = dev.open()
|
| 42 | + handle.setConfiguration(1)
|
| 43 | + handle.claimInterface(0)
|
| 44 | + if generation in [0, 2]:
|
| 45 | + self.devtype = 2;
|
| 46 | + self.maxin = 528;
|
| 47 | + self.maxout = 528
|
| 48 | + self.handle = handle
|
| 49 | + print("Connected to emBIOS Loader Recovery Mode on iPod Nano 2G, USB version %s" % dev.deviceVersion)
|
| 50 | + return
|
| 51 | + handle.releaseInterface()
|
| 52 | +
|
| 53 | + raise Exception("Could not find specified device (generation = %d)" % generation)
|
| 54 | +
|
| 55 | +
|
| 56 | + @staticmethod
|
| 57 | + def __myprint(data):
|
| 58 | + sys.stdout.write(data)
|
| 59 | + sys.stdout.flush()
|
| 60 | +
|
| 61 | +
|
| 62 | + @staticmethod
|
| 63 | + def __getbulk(handle, endpoint, size):
|
| 64 | + data = handle.bulkRead(endpoint, size, 1000)
|
| 65 | + return struct.pack("%dB" % len(data), *data)
|
| 66 | +
|
| 67 | +
|
| 68 | + @staticmethod
|
| 69 | + def __checkstatus(data):
|
| 70 | + errorcode = struct.unpack("<I", data[:4])[0]
|
| 71 | + if errorcode == 1:
|
| 72 | + # everything went fine
|
| 73 | + return
|
| 74 | + elif errorcode == 2:
|
| 75 | + print("\nError: Device doesn't support this function!")
|
| 76 | + raise Exception("Device doesn't support this function!")
|
| 77 | + else:
|
| 78 | + print("\nUnknown error %d" % errorcode)
|
| 79 | + raise Exception("Unknown error %d" % errorcode)
|
| 80 | +
|
| 81 | +
|
| 82 | + def __readstatus(self):
|
| 83 | + return self.__getbulk(self.handle, 0x83, 0x10)
|
| 84 | +
|
| 85 | +
|
| 86 | + @staticmethod
|
| 87 | + def devtype2name(devtype):
|
| 88 | + if devtype == 2: return "iPod Nano 2G"
|
| 89 | + else: return "UNKNOWN (%8x)" % devtype
|
| 90 | +
|
| 91 | +
|
| 92 | + def write(self, offset, data, *range):
|
| 93 | + if offset & 3 != 0 or len(data) & 3 != 0:
|
| 94 | + raise Exception("Unaligned data write!")
|
| 95 | +
|
| 96 | + boffset = 0
|
| 97 | + size = len(data)
|
| 98 | + if len(range) > 0:
|
| 99 | + boffset = range[0]
|
| 100 | + if len(range) > 1:
|
| 101 | + size = range[1]
|
| 102 | +
|
| 103 | + maxblk = self.maxout - 0x10
|
| 104 | +
|
| 105 | + while True:
|
| 106 | + blocklen = size
|
| 107 | + if blocklen == 0: break
|
| 108 | + if blocklen > maxblk: blocklen = maxblk
|
| 109 | + self.handle.bulkWrite(4, struct.pack("<IIII", 2, offset, int(blocklen / 4), 0) \
|
| 110 | + + data[boffset:boffset+blocklen])
|
| 111 | + self.__checkstatus(self.__readstatus())
|
| 112 | + offset += blocklen
|
| 113 | + boffset += blocklen
|
| 114 | + size -= blocklen
|
| 115 | +
|
| 116 | +
|
| 117 | + def read(self, offset, size):
|
| 118 | + if offset & 3 != 0 or size & 3 != 0:
|
| 119 | + raise Exception("Unaligned data read!")
|
| 120 | +
|
| 121 | + maxblk = self.maxin - 0x10
|
| 122 | +
|
| 123 | + data = ""
|
| 124 | +
|
| 125 | + while True:
|
| 126 | + blocklen = size
|
| 127 | + if blocklen == 0: break
|
| 128 | + if blocklen > maxblk: blocklen = maxblk
|
| 129 | + self.handle.bulkWrite(4, struct.pack("<IIII", 1, offset, int(blocklen / 4), 0))
|
| 130 | + block = self.__getbulk(self.handle, 0x83, 0x10 + blocklen)
|
| 131 | + self.__checkstatus(block)
|
| 132 | + offset += blocklen
|
| 133 | + data += block[0x10:]
|
| 134 | + size -= blocklen
|
| 135 | +
|
| 136 | + return data
|
| 137 | +
|
| 138 | +
|
| 139 | + def execute(self, addr, stack):
|
| 140 | + self.__myprint("Passing control to code at 0x%8x..." % addr)
|
| 141 | + self.handle.bulkWrite(4, struct.pack("<IIII", 0, addr, stack, 0))
|
| 142 | + self.__myprint(" done\n")
|
| 143 | +
|
| 144 | +
|
| 145 | + def upload(self, offset, file):
|
| 146 | + self.__myprint("Uploading %s to 0x%8x..." % (file, offset))
|
| 147 | + f = open(file, "rb")
|
| 148 | +
|
| 149 | + while True:
|
| 150 | + data = f.read(65536)
|
| 151 | + if data == "": break
|
| 152 | + self.write(offset, data)
|
| 153 | + offset += len(data)
|
| 154 | + self.__myprint(".")
|
| 155 | +
|
| 156 | + self.__myprint(" done\n")
|
| 157 | +
|
| 158 | +
|
| 159 | + def download(self, offset, size, file):
|
| 160 | + self.__myprint("Downloading 0x%x bytes from 0x%8x to %s..." % (size, offset, file))
|
| 161 | + f = open(file, "wb")
|
| 162 | +
|
| 163 | + while True:
|
| 164 | + blocklen = size
|
| 165 | + if blocklen == 0: break
|
| 166 | + if blocklen > 65536: blocklen = 65536
|
| 167 | + f.write(self.read(offset, blocklen))
|
| 168 | + offset += blocklen
|
| 169 | + size -= blocklen
|
| 170 | + self.__myprint(".")
|
| 171 | +
|
| 172 | + self.__myprint(" done\n")
|
| 173 | +
|
| 174 | +
|
| 175 | + def run(self, file):
|
| 176 | + self.upload(0x08000000, file)
|
| 177 | + self.execute(0x08000000, 0x0a000000)
|
| 178 | +
|