| 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 | + |