Subversion Repositories freemyipod

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
56 benedikt93 1
#!/usr/bin/env python
2
#
3
#
171 farthen 4
#    Copyright 2010 TheSeven, benedikt93, Farthen
56 benedikt93 5
#
6
#
7
#    This file is part of emBIOS.
8
#
9
#    emBIOS is free software: you can redistribute it and/or
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
#
14
#    emBIOS is distributed in the hope that it will be useful,
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
#
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/>.
21
#
22
#
23
 
24
import sys
25
import struct
171 farthen 26
import usb.core
27
import libembiosdata
56 benedikt93 28
 
171 farthen 29
class Error(Exception):
30
    def __init__(self, value=None):
31
        self.value = value
32
    def __str__(self):
33
        if self.value != None:
34
            return repr(self.value)
56 benedikt93 35
 
171 farthen 36
class ArgumentError(Error):
37
    pass
56 benedikt93 38
 
171 farthen 39
class DeviceNotFoundError(Error):
40
    pass
56 benedikt93 41
 
171 farthen 42
class DeviceError(Error):
43
    pass
56 benedikt93 44
 
171 farthen 45
class SendError(Error):
46
    pass
56 benedikt93 47
 
171 farthen 48
class ReceiveError(Error):
49
    pass
56 benedikt93 50
 
51
 
171 farthen 52
class Bunch(dict):
56 benedikt93 53
    """
171 farthen 54
        This is a dict whose items can also be accessed with
55
        bunchinstance.something.
56 benedikt93 56
    """
171 farthen 57
    def __init__(self, **kw):
58
        dict.__init__(self, kw)
59
        self.__dict__ = self
56 benedikt93 60
 
171 farthen 61
    def __getstate__(self):
62
        return self
56 benedikt93 63
 
171 farthen 64
    def __setstate__(self, state):
65
        self.update(state)
66
        self.__dict__ = self
56 benedikt93 67
 
68
 
171 farthen 69
class Embios(object):
176 farthen 70
    """
71
        Class for all embios functions.
72
    """
171 farthen 73
    def __init__(self):
176 farthen 74
        self.lib = Lib()
343 farthen 75
 
76
        self.getversioninfo()
176 farthen 77
        self.getpacketsizeinfo()
343 farthen 78
        self.getusermemrange()
56 benedikt93 79
 
171 farthen 80
    @staticmethod
81
    def _alignsplit(addr, size, blksize, align):
177 farthen 82
        if size <= blksize: return (size, 0, 0)
171 farthen 83
        end = addr + size
84
        if addr & (align - 1):
85
            bodyaddr = (addr + min(size, blksize)) & ~(align - 1)
86
        else: bodyaddr = addr
87
        headsize = bodyaddr - addr
88
        if (size - headsize) & (align - 1):
89
            tailaddr = (end - min(end - bodyaddr, blksize) + align - 1) & ~(align - 1)
90
        else: tailaddr = end
91
        tailsize = end - tailaddr
92
        return (headsize, tailaddr - bodyaddr, tailsize)
56 benedikt93 93
 
178 farthen 94
    def _readmem(self, addr, size):
95
        """ Reads the memory from location 'addr' with size 'size'
96
            from the device.
97
        """
98
        resp = self.lib.monitorcommand(struct.pack("IIII", 4, addr, size, 0), "III%ds" % size, (None, None, None, "data"))
99
        return resp.data
100
 
101
    def _writemem(self, addr, data):
102
        """ Writes the data in 'data' to the location 'addr'
103
            in the memory of the device.
104
        """
105
        return self.lib.monitorcommand(struct.pack("IIII%ds" % len(data), 5, addr, len(data), 0, data), "III", (None, None, None))
106
 
107
    def _readdma(self, addr, size):
108
        """ Reads the memory from location 'addr' with size 'size'
109
            from the device. This uses DMA and the data in endpoint.
110
        """
111
        self.lib.monitorcommand(struct.pack("IIII", 6, addr, size, 0), "III", (None, None, None))
112
        return struct.unpack("%ds" % size, self.lib.dev.din(size))[0]
113
 
114
    def _writedma(self, addr, data):
115
        """ Writes the data in 'data' to the location 'addr'
116
            in the memory of the device. This uses DMA and the data out endpoint.
117
        """
118
        self.lib.monitorcommand(struct.pack("IIII", 7, addr, len(data), 0), "III", (None, None, None))
119
        return self.lib.dev.dout(data)
120
 
171 farthen 121
    def getversioninfo(self):
122
        """ This returns the emBIOS version and device information. """
342 farthen 123
        resp = self.lib.monitorcommand(struct.pack("IIII", 1, 0, 0, 0), "IBBBBI", ("revision", "majorv", "minorv", "patchv", "swtypeid", "hwtypeid"))
124
        self.lib.dev.version.revision = resp.revision
125
        self.lib.dev.version.majorv = resp.majorv
126
        self.lib.dev.version.minorv = resp.minorv
127
        self.lib.dev.version.patchv = resp.patchv
128
        self.lib.dev.swtypeid = resp.swtypeid
129
        self.lib.dev.hwtypeid = resp.hwtypeid
130
        return resp
56 benedikt93 131
 
171 farthen 132
    def getpacketsizeinfo(self):
133
        """ This returns the emBIOS max packet size information.
134
            It also sets the properties of the device object accordingly.
135
        """
136
        resp = self.lib.monitorcommand(struct.pack("IIII", 1, 1, 0, 0), "HHII", ("coutmax", "cinmax", "doutmax", "dinmax"))
343 farthen 137
        self.lib.dev.packetsizelimit.cout = resp.coutmax
138
        self.lib.dev.packetsizelimit.cin = resp.cinmax
139
        self.lib.dev.packetsizelimit.din = resp.dinmax
140
        self.lib.dev.packetsizelimit.dout = resp.doutmax
171 farthen 141
        return resp
56 benedikt93 142
 
171 farthen 143
    def getusermemrange(self):
144
        """ This returns the memory range the user has access to. """
342 farthen 145
        resp = self.lib.monitorcommand(struct.pack("IIII", 1, 2, 0, 0), "III", ("lower", "upper", None))
146
        self.lib.dev.usermem.lower = resp.lower
147
        self.lib.dev.usermem.upper = resp.upper
148
        return resp
56 benedikt93 149
 
171 farthen 150
    def reset(self, force=False):
151
        """ Reboot the device """
152
        if force:
153
            return self.lib.monitorcommand(struct.pack("IIII", 2, 0, 0, 0))
154
        else:
155
            return self.lib.monitorcommand(struct.pack("IIII", 2, 1, 0, 0), "III", (None, None, None))
56 benedikt93 156
 
171 farthen 157
    def poweroff(self, force=False):
158
        """ Powers the device off. """
159
        if force:
160
            return self.lib.monitorcommand(struct.pack("IIII", 3, 0, 0, 0))
161
        else:
162
            return self.lib.monitorcommand(struct.pack("IIII", 3, 1, 0, 0), "III", (None, None, None))
56 benedikt93 163
 
171 farthen 164
    def read(self, addr, size):
165
        """ Reads the memory from location 'addr' with size 'size'
166
            from the device. This cares about too long packages
167
            and decides whether to use DMA or not.
168
        """
343 farthen 169
        cin_maxsize = self.lib.dev.packetsizelimit.cin - self.lib.headersize
170
        din_maxsize = self.lib.dev.packetsizelimit.din
171 farthen 171
        data = ""
172
        (headsize, bodysize, tailsize) = self._alignsplit(addr, size, cin_maxsize, 16)
173
        if headsize != 0:
178 farthen 174
            data += self._readmem(addr, headsize)
171 farthen 175
            addr += headsize
176
        while bodysize > 0:
177
            if bodysize >= 2 * cin_maxsize:
178
                readsize = min(bodysize, din_maxsize)
178 farthen 179
                data += self._readdma(addr, readsize)
171 farthen 180
            else:
181
                readsize = min(bodysize, cin_maxsize)
178 farthen 182
                data += self._readmem(addr, readsize)
171 farthen 183
            addr += readsize
184
            bodysize -= readsize
185
        if tailsize != 0:
178 farthen 186
            data += self._readmem(addr, tailsize)
171 farthen 187
        return data
56 benedikt93 188
 
171 farthen 189
    def write(self, addr, data):
190
        """ Writes the data in 'data' to the location 'addr'
191
            in the memory of the device. This cares about too long packages
192
            and decides whether to use DMA or not.
193
        """
343 farthen 194
        cout_maxsize = self.lib.dev.packetsizelimit.cout - self.lib.headersize
195
        dout_maxsize = self.lib.dev.packetsizelimit.dout
171 farthen 196
        (headsize, bodysize, tailsize) = self._alignsplit(addr, len(data), cout_maxsize, 16)
197
        offset = 0
198
        if headsize != 0:
178 farthen 199
            self._writemem(addr, data[offset:offset+headsize])
171 farthen 200
            offset += headsize
201
            addr += headsize
202
        while bodysize > 0:
203
            if bodysize >= 2 * cout_maxsize:
204
                writesize = min(bodysize, dout_maxsize)
178 farthen 205
                self._writedma(addr, data[offset:offset+writesize])
171 farthen 206
            else:
207
                writesize = min(bodysize, cout_maxsize)
178 farthen 208
                self._writemem(addr, data[offset:offset+writesize])
171 farthen 209
            offset += writesize
210
            addr += writesize
211
            bodysize -= writesize
212
        if tailsize != 0:
178 farthen 213
            self._writemem(addr, data[offset:offset+tailsize])
171 farthen 214
        return data
56 benedikt93 215
 
173 farthen 216
    def readstring(self, addr, maxlength = 256):
217
        """ Reads a zero terminated string from memory 
218
            Reads only a maximum of 'maxlength' chars.
219
        """
343 farthen 220
        cin_maxsize = self.lib.dev.packetsizelimit.cin - self.lib.headersize
173 farthen 221
        string = ""
222
        while (len(string) < maxlength or maxlength < 0):
178 farthen 223
            data = self._readmem(addr, min(maxlength - len(string), cin_maxsize))
173 farthen 224
            length = data.find("\0")
225
            if length >= 0:
226
                string += data[:length]
227
                break
228
            else:
229
                string += data
230
            addr += cin_maxsize
231
        return string
232
 
171 farthen 233
    def i2cread(self, index, slaveaddr, startaddr, size):
234
        """ Reads data from an i2c slave """
236 farthen 235
        data = ""
236
        for i in range(size):
237
            resp = self.lib.monitorcommand(struct.pack("IBBBBII", 8, index, slaveaddr, startaddr + i, 1, 0, 0), "III1s", (None, None, None, "data"))
238
            data += resp.data
239
        return data
56 benedikt93 240
 
171 farthen 241
    def i2cwrite(self, index, slaveaddr, startaddr, data):
242
        """ Writes data to an i2c slave """
176 farthen 243
        size = len(data)
244
        if size > 256 or size < 1:
341 farthen 245
            raise ArgumentError("Size must be a number between 1 and 256")
176 farthen 246
        if size == 256:
247
            size = 0
215 theseven 248
        return self.lib.monitorcommand(struct.pack("IBBBBII%ds" % size, 9, index, slaveaddr, startaddr, size, 0, 0, data), "III", (None, None, None))
56 benedikt93 249
 
176 farthen 250
    def usbcread(self):
251
        """ Reads one packet with the maximal cin size """
343 farthen 252
        cin_maxsize = self.lib.dev.packetsizelimit.cin - self.lib.headersize
176 farthen 253
        resp = self.lib.monitorcommand(struct.pack("IIII", 10, cin_maxsize, 0, 0), "III%ds" % cin_maxsize, ("validsize", "buffersize", "queuesize", "data"))
254
        resp.data = resp.data[:resp.validsize]
255
        resp.maxsize = cin_maxsize
256
        return resp
56 benedikt93 257
 
171 farthen 258
    def usbcwrite(self, data):
259
        """ Writes data to the USB console """
343 farthen 260
        cin_maxsize = self.lib.dev.packetsizelimit.cin - self.lib.headersize
176 farthen 261
        size = len(data)
262
        while len(data) > 0:
263
            writesize = min(cin_maxsize, len(data))
264
            resp = self.lib.monitorcommand(struct.pack("IIII%ds" % writesize, 11, writesize, 0, 0, data[:writesize]), "III", ("validsize", "buffersize", "freesize"))
265
            data = data[resp.validsize:]
266
        return size
56 benedikt93 267
 
176 farthen 268
    def cread(self, bitmask=0x1):
269
        """ Reads one packet with the maximal cin size from the device consoles
171 farthen 270
            identified with the specified bitmask
271
        """
343 farthen 272
        cin_maxsize = self.lib.dev.packetsizelimit.cin - self.lib.headersize
217 theseven 273
        resp = self.lib.monitorcommand(struct.pack("IIII", 13, bitmask, cin_maxsize, 0), "III%ds" % cin_maxsize, ("size", None, None))
176 farthen 274
        resp.data = resp.data[size:]
275
        resp.maxsize = cin_maxsize
276
        return resp
56 benedikt93 277
 
176 farthen 278
    def cwrite(self, data, bitmask=0x1):
171 farthen 279
        """ Writes data to the device consoles 
280
            identified with the specified bitmask.
281
        """
343 farthen 282
        cin_maxsize = self.lib.dev.packetsizelimit.cin - self.lib.headersize
176 farthen 283
        size = len(data)
284
        while len(data) > 0:
285
            writesize = min(cin_maxsize, len(data))
217 theseven 286
            resp = self.lib.monitorcommand(struct.pack("IIII%ds" % writesize, 12, bitmask, writesize, 0, data[:writesize]), "III", (None, None, None))
176 farthen 287
            data = data[writesize:]
288
        return size
56 benedikt93 289
 
171 farthen 290
    def cflush(self, bitmask):
291
        """ Flushes the consoles specified with 'bitmask' """
292
        return self.lib.monitorcommand(struct.pack("IIII", 14, bitmask, 0, 0), "III", (None, None, None))
56 benedikt93 293
 
173 farthen 294
    def getprocinfo(self):
171 farthen 295
        """ Gets current state of the scheduler """
343 farthen 296
        cin_maxsize = self.lib.dev.packetsizelimit.cin - self.lib.headersize
173 farthen 297
        # Get the size
298
        schedulerstate = self.lockscheduler()
299
        resp = self.lib.monitorcommand(struct.pack("IIII", 15, 0, 0, 0), "III", ("structver", "tablesize", None))
300
        tablesize = resp.tablesize
301
        size = tablesize
302
        structver = resp.structver
303
        offset = 0
304
        data = ""
305
        while size > 0:
306
            if size > cin_maxsize:
307
                readsize = cin_maxsize
308
            else:
309
                readsize = size
310
            resp = self.lib.monitorcommand(struct.pack("IIII", 15, offset, readsize, 0), "III%ds" % readsize, ("structver", "tablesize", None, "data"))
311
            data += resp.data
312
            offset += readsize
313
            size -= readsize
314
        self.lockscheduler(schedulerstate)
315
        threadstructsize = 120
316
        registersize = 32
317
        if len(data) % threadstructsize != 0:
318
            raise DeviceError("The thread struct is not a multiple of "+str(threadsturcsize)+"!")
319
        threadcount = len(data) / threadstructsize
320
        threads = []
321
        id = 0
322
        for thread in range(threadcount):
323
            offset = threadstructsize * thread
324
            threaddata = struct.unpack("<16IIIIIQIIIIIIIBBBB", data[offset:offset+threadstructsize])
325
            info = Bunch()
326
            info.id = id
327
            state = threaddata[17]
328
            info.state = libembiosdata.thread_state[state]
329
            if info.state == "THREAD_FREE":
330
                id += 1
331
                continue
332
            info.regs = Bunch()
333
            for register in range(16):
334
                info.regs["r"+str(register)] = threaddata[register]
335
            info.regs.cpsr = threaddata[16]
336
            info.nameptr = threaddata[18]
337
            if info.nameptr == 0:
338
                info.name = "Thread %d" % info.id
339
            else:
340
                info.name = self.readstring(info.nameptr)
341
            info.cputime_current = threaddata[19]
342
            info.cputime_total = threaddata[20]
343
            info.startusec = threaddata[21]
344
            info.queue_next_ptr = threaddata[22]
345
            info.timeout = threaddata[23]
346
            info.blocked_since = threaddata[24]
347
            info.blocked_by_ptr = threaddata[25]
348
            info.stackaddr = threaddata[26]
349
            info.err_no = threaddata[27]
350
            info.block_type = libembiosdata.thread_block[threaddata[28]]
351
            info.type = libembiosdata.thread_type[threaddata[29]]
352
            info.priority = threaddata[30]
353
            info.cpuload = threaddata[31]
354
            threads.append(info)
355
            id += 1
356
        return threads
56 benedikt93 357
 
173 farthen 358
    def lockscheduler(self, freeze=True):
171 farthen 359
        """ Freezes/Unfreezes the scheduler """
173 farthen 360
        resp = self.lib.monitorcommand(struct.pack("IIII", 16, 1 if freeze else 0, 0, 0), "III", ("before", None, None))
361
        return True if resp.before == 1 else False
67 benedikt93 362
 
173 farthen 363
    def unlockscheduler(self):
171 farthen 364
        """ Unfreezes the scheduler """
365
        return self.lib.monitorcommand(struct.pack("IIII", 16, 0, 0, 0), "III", ("before", None, None))
56 benedikt93 366
 
171 farthen 367
    def suspendthread(self, id, suspend=True):
368
        """ Suspends the thread with the specified id """
173 farthen 369
        resp = self.lib.monitorcommand(struct.pack("IIII", 17, 1 if suspend else 0, id, 0), "III", ("before", None, None))
370
        return True if resp.before == 1 else False
56 benedikt93 371
 
173 farthen 372
    def resumethread(self, id):
373
        """ Resumes the thread with the specified id """
171 farthen 374
        return self.lib.monitorcommand(struct.pack("IIII", 17, 0, id, 0), "III", ("before", None, None))
56 benedikt93 375
 
171 farthen 376
    def killthread(self, id):
377
        """ Kills the thread with the specified id """
378
        return self.lib.monitorcommand(struct.pack("IIII", 18, id, 0, 0), "III", ("before", None, None))
56 benedikt93 379
 
171 farthen 380
    def createthread(self, nameptr, entrypoint, stackptr, stacksize, threadtype, priority, state):
381
        """ Creates a thread with the specified attributes """
382
        if threadtype == "user":
383
            threadtype = 0
384
        elif threadtype == "system":
385
            threadtype = 1
386
        else:
341 farthen 387
            raise ArgumentError("Threadtype must be either 'system' or 'user'")
171 farthen 388
        if priority > 256 or priority < 0:
341 farthen 389
            raise ArgumentError("Priority must be a number between 0 and 256")
171 farthen 390
        if state == "ready":
391
            state = 0
392
        elif state == "suspended":
393
            state = 1
394
        else:
341 farthen 395
            raise ArgumentError("State must be either 'ready' or 'suspended'")
171 farthen 396
        resp = self.lib.monitorcommand(struct.pack("IIIIIIII", 19, nameptr, entrypoint, stackptr, stacksize, threadtype, priority, state), "III", (id, None, None))
397
        if resp.id < 0:
398
            raise DeviceError("The device returned the error code "+str(resp.id))
399
        return resp
56 benedikt93 400
 
172 farthen 401
    def flushcaches(self):
171 farthen 402
        """ Flushes the CPU instruction and data cache """
403
        return self.lib.monitorcommand(struct.pack("IIII", 20, 0, 0, 0), "III", (None, None, None))
56 benedikt93 404
 
172 farthen 405
    def execimage(self, addr):
171 farthen 406
        """ Runs the emBIOS app at 'addr' """
346 theseven 407
        return self.lib.monitorcommand(struct.pack("IIII", 21, addr, 0, 0), "III", ("rc", None, None))
56 benedikt93 408
 
238 farthen 409
    def run(self, app):
410
        """ Uploads and runs the emBIOS app in the string 'app' """
411
        try:
412
            appheader = struct.unpack("<8sIIIIIIIIII", app[:48])
413
        except struct.error:
341 farthen 414
            raise ArgumentError("The specified app is not an emBIOS application")
238 farthen 415
        header = appheader[0]
416
        if header != "emBIexec":
341 farthen 417
            raise ArgumentError("The specified app is not an emBIOS application")
238 farthen 418
        baseaddr = appheader[2]
419
        threadnameptr = appheader[8]
420
        nameptr = threadnameptr - baseaddr
421
        name = ""
422
        while True:
423
            char = app[nameptr:nameptr+1]
424
            try:
425
                if ord(char) == 0:
426
                    break
427
            except TypeError:
341 farthen 428
                raise ArgumentError("The specified app is not an emBIOS application")
238 farthen 429
            name += char
430
            nameptr += 1
431
        usermem = self.getusermemrange()
432
        if usermem.lower > baseaddr or usermem.upper < baseaddr + len(app):
433
            raise ArgumentError("The baseaddress of the specified emBIOS application is out of range of the user memory range on the device. Are you sure that this application is compatible with your device?")
434
        self.write(baseaddr, app)
435
        self.execimage(baseaddr)
436
        return Bunch(baseaddr=baseaddr, name=name)
437
 
171 farthen 438
    def bootflashread(self, memaddr, flashaddr, size):
439
        """ Copies the data in the bootflash at 'flashaddr' of the specified size
440
            to the memory at addr 'memaddr'
441
        """
174 farthen 442
        return self.lib.monitorcommand(struct.pack("IIII", 22, memaddr, flashaddr, size), "III", (None, None, None))
82 benedikt93 443
 
171 farthen 444
    def bootflashwrite(self, memaddr, flashaddr, size):
445
        """ Copies the data in the memory at 'memaddr' of the specified size
446
            to the boot flash at addr 'flashaddr'
447
        """
174 farthen 448
        return self.lib.monitorcommand(struct.pack("IIII", 23, memaddr, flashaddr, size), "III", (None, None, None))
56 benedikt93 449
 
171 farthen 450
    def execfirmware(self, addr):
451
        """ Executes the firmware at 'addr' and passes all control to it. """
269 farthen 452
        return self.lib.monitorcommand(struct.pack("IIII", 24, addr, 0, 0))
56 benedikt93 453
 
171 farthen 454
    def aesencrypt(self, addr, size, keyindex):
455
        """ Encrypts the buffer at 'addr' with the specified size
456
            with the hardware AES key index 'keyindex'
457
        """
458
        return self.lib.monitorcommand(struct.pack("IBBHII", 25, 1, 0, keyindex, addr, size), "III", (None, None, None))
82 benedikt93 459
 
171 farthen 460
    def aesdecrypt(self, addr, size, keyindex):
461
        """ Decrypts the buffer at 'addr' with the specified size
462
            with the hardware AES key index 'keyindex'
463
        """
464
        return self.lib.monitorcommand(struct.pack("IBBHII", 25, 0, 0, keyindex, addr, size), "III", (None, None, None))
82 benedikt93 465
 
171 farthen 466
    def hmac_sha1(self, addr, size, destination):
467
        """ Generates a HMAC-SHA1 hash of the buffer and saves it to 'destination' """
468
        return self.lib.monitorcommand(struct.pack("IIII", 26, addr, size, destination), "III", (None, None, None))
56 benedikt93 469
 
227 theseven 470
    def ipodnano2g_getnandinfo(self):
471
        """ Target-specific function: ipodnano2g
472
            Gathers some information about the NAND chip used
473
        """
346 theseven 474
        if self.lib.dev.hwtypeid != 0x47324e49: raise DeviceError("Wrong device for target-specific command.")
227 theseven 475
        return self.lib.monitorcommand(struct.pack("IIII", 0xffff0001, 0, 0, 0), "IHHHH", ("type", "pagesperblock", "banks", "userblocks", "blocks"))
476
 
477
    def ipodnano2g_nandread(self, addr, start, count, doecc, checkempty):
478
        """ Target-specific function: ipodnano2g
479
            Reads data from the NAND chip into memory
480
        """
346 theseven 481
        if self.lib.dev.hwtypeid != 0x47324e49: raise DeviceError("Wrong device for target-specific command.")
227 theseven 482
        return self.lib.monitorcommand(struct.pack("IIII", 0xffff0002, addr | (0x80000000 if doecc != 0 else 0) | (0x40000000 if checkempty != 0 else 0), start, count), "III", (None, None, None))
483
 
484
    def ipodnano2g_nandwrite(self, addr, start, count, doecc):
485
        """ Target-specific function: ipodnano2g
486
            Writes data to the NAND chip
487
        """
346 theseven 488
        if self.lib.dev.hwtypeid != 0x47324e49: raise DeviceError("Wrong device for target-specific command.")
227 theseven 489
        return self.lib.monitorcommand(struct.pack("IIII", 0xffff0003, addr | (0x80000000 if doecc != 0 else 0), start, count), "III", (None, None, None))
490
 
491
    def ipodnano2g_nanderase(self, addr, start, count):
492
        """ Target-specific function: ipodnano2g
493
            Erases blocks on the NAND chip and stores the results to memory
494
        """
346 theseven 495
        if self.lib.dev.hwtypeid != 0x47324e49: raise DeviceError("Wrong device for target-specific command.")
227 theseven 496
        return self.lib.monitorcommand(struct.pack("IIII", 0xffff0004, addr, start, count), "III", (None, None, None))
497
 
346 theseven 498
    def ipodclassic_gethddinfo(self):
499
        """ Target-specific function: ipodclassic
500
            Gather information about the hard disk drive
501
        """
502
        if self.lib.dev.hwtypeid != 0x4c435049: raise DeviceError("Wrong device for target-specific command.")
503
        return self.lib.monitorcommand(struct.pack("IIII", 0xffff0001, 0, 0, 0), "IQQII", ("identifyptr", "totalsectors", "virtualsectors", "bbtptr", "bbtsize"))
504
 
505
    def ipodclassic_hddaccess(self, type, sector, count, addr):
506
        """ Target-specific function: ipodclassic
507
            Access the hard disk, type = 0 (read) / 1 (write)
508
        """
509
        if self.lib.dev.hwtypeid != 0x4c435049: raise DeviceError("Wrong device for target-specific command.")
510
        rc = self.lib.monitorcommand(struct.pack("IIQIIII", 0xffff0002, type, sector, count, addr, 0, 0), "III", ("rc", None, None))
511
        if (rc > 0x80000000):
512
            raise DeviceError("HDD access (type=%d, sector=%d, count=%d, addr=0x%08X) failed with RC 0x%08X" % (type, sector, count, addr, rc))
513
 
514
    def ipodclassic_writebbt(self, bbt, tempaddr):
515
        """ Target-specific function: ipodclassic
516
            Write hard drive bad block table
517
        """
518
        if self.lib.dev.hwtypeid != 0x4c435049: raise DeviceError("Wrong device for target-specific command.")
519
        try:
520
            bbtheader = struct.unpack("<8s2024sQII512I", bbt[:4096])
521
        except struct.error:
522
            raise ArgumentError("The specified file is not an emBIOS hard disk BBT")
523
        if bbtheader[0] != "emBIbbth":
524
            raise ArgumentError("The specified file is not an emBIOS hard disk BBT")
525
        virtualsectors = bbtheader[2]
526
        bbtsectors = bbtheader[3]
527
        self.write(tempaddr, bbt)
528
        sector = 0
529
        count = 1
530
        offset = 0
531
        for i in range(bbtsectors):
532
            if bbtheader[4][i] == sector + count:
533
                count = count + 1
534
            else:
535
                self.ipodclassic_hddaccess(1, sector, count, tempaddr + offset)
536
                offset = offset + count * 4096
537
                sector = bbtheader[4][i]
538
                count = 1
539
        self.ipodclassic_hddaccess(1, sector, count, tempaddr + offset)
540
 
541
    def storage_get_info(self):
542
        """ Get information about a storage device """
543
        result = self.lib.monitorcommand(struct.pack("IIII", 27, 0, 0, 0), "IIIIIIII", ("version", None, None, "sectorsize", "numsectors", "vendorptr", "productptr", "revisionptr"))
544
        if result.version != 1:
545
            raise ValueError("Unknown version of storage_info struct: %d" % result.version)
546
        return result
547
 
548
    def storage_read_sectors_md(self, volume, sector, count, addr):
549
        """ Read sectors from as storage device """
550
        result = self.lib.monitorcommand(struct.pack("IIQIIII", 28, volume, sector, count, addr, 0, 0), "III", ("rc", None, None, None))
551
        if result.rc > 0x80000000:
552
            raise DeviceError("storage_read_sectors_md(volume=%d, sector=%d, count=%d, addr=0x%08X) failed with RC 0x%08X" % (volume, sector, count, addr, rc))
56 benedikt93 553
 
346 theseven 554
    def storage_write_sectors_md(self, volume, sector, count, addr):
555
        """ Read sectors from as storage device """
556
        result = self.lib.monitorcommand(struct.pack("IIQIIII", 29, volume, sector, count, addr, 0, 0), "III", ("rc", None, None, None))
557
        if result.rc > 0x80000000:
558
            raise DeviceError("storage_read_sectors_md(volume=%d, sector=%d, count=%d, addr=0x%08X) failed with RC 0x%08X" % (volume, sector, count, addr, rc))
559
 
560
    def file_open(self, filename, mode):
561
        """ Opens a file and returns the handle """
562
        result = self.lib.monitorcommand(struct.pack("IIII%dsB" % len(filename), 30, mode, 0, 0, filename, 0), "III", ("fd", None, None))
563
        if result.fd > 0x80000000:
564
            raise DeviceError("file_open(filename=\"%s\", mode=0x%X) failed with RC=0x%08X, errno=%d" % (filename, mode, result.fd, self.errno()))
565
        return result.fd
566
 
567
    def file_size(self, fd):
568
        """ Gets the size of a file referenced by a handle """
569
        result = self.lib.monitorcommand(struct.pack("IIII", 31, fd, 0, 0), "III", ("size", None, None))
570
        if result.size > 0x80000000:
571
            raise DeviceError("file_size(fd=%d) failed with RC=0x%08X, errno=%d" % (fd, result.size, self.errno()))
572
        return result.size
573
 
574
    def file_read(self, fd, addr, size):
575
        """ Reads data from a file referenced by a handle """
576
        result = self.lib.monitorcommand(struct.pack("IIII", 32, fd, addr, size), "III", ("rc", None, None))
577
        if result.rc > 0x80000000:
578
            raise DeviceError("file_read(fd=%d, addr=0x%08X, size=0x%08X) failed with RC=0x%08X, errno=%d" % (fd, addr, size, result.rc, self.errno()))
579
        return result.rc
580
 
581
    def file_write(self, fd, addr, size):
582
        """ Writes data from a file referenced by a handle """
583
        result = self.lib.monitorcommand(struct.pack("IIII", 33, fd, addr, size), "III", ("rc", None, None))
584
        if result.rc > 0x80000000:
585
            raise DeviceError("file_write(fd=%d, addr=0x%08X, size=0x%08X) failed with RC=0x%08X, errno=%d" % (fd, addr, size, result.rc, self.errno()))
586
        return result.rc
587
 
588
    def file_seek(self, fd, offset, whence):
589
        """ Seeks the file handle to the specified position in the file """
590
        result = self.lib.monitorcommand(struct.pack("IIII", 34, fd, offset, whence), "III", ("rc", None, None))
591
        if result.rc > 0x80000000:
592
            raise DeviceError("file_seek(fd=%d, offset=0x%08X, whence=%d) failed with RC=0x%08X, errno=%d" % (fd, offset, whence, result.rc, self.errno()))
593
        return result.rc
594
 
595
    def file_truncate(self, fd, length):
596
        """ Truncates a file referenced by a handle to a specified length """
597
        result = self.lib.monitorcommand(struct.pack("IIII", 35, fd, offset, 0), "III", ("rc", None, None))
598
        if result.rc > 0x80000000:
599
            raise DeviceError("file_truncate(fd=%d, length=0x%08X) failed with RC=0x%08X, errno=%d" % (fd, length, result.rc, self.errno()))
600
        return result.rc
601
 
602
    def file_sync(self, fd):
603
        """ Flushes a file handles' buffers """
604
        result = self.lib.monitorcommand(struct.pack("IIII", 36, fd, 0, 0), "III", ("rc", None, None))
605
        if result.rc > 0x80000000:
606
            raise DeviceError("file_sync(fd=%d) failed with RC=0x%08X, errno=%d" % (fd, result.rc, self.errno()))
607
        return result.rc
608
 
609
    def file_close(self, fd):
610
        """ Closes a file handle """
611
        result = self.lib.monitorcommand(struct.pack("IIII", 37, fd, 0, 0), "III", ("rc", None, None))
612
        if result.rc > 0x80000000:
613
            raise DeviceError("file_close(fd=%d) failed with RC=0x%08X, errno=%d" % (fd, result.rc, self.errno()))
614
        return result.rc
615
 
616
    def file_close_all(self):
617
        """ Closes all file handles opened through the debugger """
618
        result = self.lib.monitorcommand(struct.pack("IIII", 38, 0, 0, 0), "III", ("rc", None, None))
619
        if result.rc > 0x80000000:
620
            raise DeviceError("file_close_all() failed with RC=0x%08X, errno=%d" % (result.rc, self.errno()))
621
        return result.rc
622
 
623
    def file_kill_all(self):
624
        """ Kills all file handles (in the whole system) """
625
        result = self.lib.monitorcommand(struct.pack("IIII", 39, 0, 0, 0), "III", ("rc", None, None))
626
        if result.rc > 0x80000000:
627
            raise DeviceError("file_kill_all() failed with RC=0x%08X, errno=%d" % (result.rc, self.errno()))
628
        return result.rc
629
 
630
    def file_unlink(self, filename):
631
        """ Removes a file """
632
        result = self.lib.monitorcommand(struct.pack("IIII%dsB" % len(filename), 40, 0, 0, 0, filename, 0), "III", ("rc", None, None))
633
        if result.rc > 0x80000000:
634
            raise DeviceError("file_unlink(filename=\"%s\") failed with RC=0x%08X, errno=%d" % (filename, result.rc, self.errno()))
635
        return result.rc
636
 
637
    def file_rename(self, oldname, newname):
638
        """ Renames a file """
639
        result = self.lib.monitorcommand(struct.pack("IIII248s%dsB" % min(247, len(newname)), 41, 0, 0, 0, oldname, newname, 0), "III", ("rc", None, None))
640
        if result.rc > 0x80000000:
641
            raise DeviceError("file_rename(oldname=\"%s\", newname=\"%s\") failed with RC=0x%08X, errno=%d" % (oldname, newname, result.rc, self.errno()))
642
        return result.rc
643
 
644
    def dir_open(self, dirname):
645
        """ Opens a directory and returns the handle """
646
        result = self.lib.monitorcommand(struct.pack("IIII%dsB" % len(dirname), 42, 0, 0, 0, dirname, 0), "III", ("handle", None, None))
647
        if result.handle == 0:
648
            raise DeviceError("dir_open(dirname=\"%s\") failed with RC=0x%08X, errno=%d" % (dirname, result.handle, self.errno()))
649
        return result.handle
650
 
651
    def dir_read(self, handle):
652
        """ Reads the next entry from a directory """
653
        result = self.lib.monitorcommand(struct.pack("IIII", 43, handle, 0, 0), "III", ("version", "maxpath", "ptr"))
654
        if result.ptr == 0:
655
            raise DeviceError("dir_read(handle=0x%08X) failed with RC=0x%08X, errno=%d" % (handle, result.ptr, self.errno()))
656
        if result.version != 1:
657
            raise ValueError("Unknown version of dirent struct: %d" % result.version)
658
        dirent = self.read(result.ptr, result.maxpath + 16)
659
        ret = Bunch()
660
        (ret.name, ret.attributes, ret.size, ret.startcluster, ret.wrtdate, ret.wrttime) = struct.unpack("%dsIIIHH" % result.maxpath, dirent)
661
        ret.name = ret.name[:ret.name.index('\x00')]
662
        return ret
663
 
664
    def dir_close(self, handle):
665
        """ Closes a directory handle """
666
        result = self.lib.monitorcommand(struct.pack("IIII", 44, handle, 0, 0), "III", ("rc", None, None))
667
        if result.rc > 0x80000000:
668
            raise DeviceError("dir_close(handle=0x%08X) failed with RC=0x%08X, errno=%d" % (handle, result.rc, self.errno()))
669
        return result.rc
670
 
671
    def dir_close_all(self):
672
        """ Closes all directory handles opened through the debugger """
673
        result = self.lib.monitorcommand(struct.pack("IIII", 45, 0, 0, 0), "III", ("rc", None, None))
674
        if result.rc > 0x80000000:
675
            raise DeviceError("dir_close_all() failed with RC=0x%08X, errno=%d" % (result.rc, self.errno()))
676
        return result.rc
677
 
678
    def dir_kill_all(self):
679
        """ Kills all directory handles (in the whole system) """
680
        result = self.lib.monitorcommand(struct.pack("IIII", 46, 0, 0, 0), "III", ("rc", None, None))
681
        if result.rc > 0x80000000:
682
            raise DeviceError("dir_kill_all() failed with RC=0x%08X, errno=%d" % (result.rc, self.errno()))
683
        return result.rc
684
 
685
    def dir_create(self, dirname):
686
        """ Creates a directory """
687
        result = self.lib.monitorcommand(struct.pack("IIII%dsB" % len(dirname), 47, 0, 0, 0, dirname, 0), "III", ("rc", None, None))
688
        if result.rc > 0x80000000:
689
            raise DeviceError("dir_create(dirname=\"%s\") failed with RC=0x%08X, errno=%d" % (dirname, result.rc, self.errno()))
690
        return result.rc
691
 
692
    def dir_remove(self, dirname):
693
        """ Removes an (empty) directory """
694
        result = self.lib.monitorcommand(struct.pack("IIII%dsB" % len(dirname), 48, 0, 0, 0, dirname, 0), "III", ("rc", None, None))
695
        if result.rc > 0x80000000:
696
            raise DeviceError("dir_remove(dirname=\"%s\") failed with RC=0x%08X, errno=%d" % (dirname, result.rc, self.errno()))
697
        return result.rc
698
 
699
    def errno(self):
700
        """ Returns the number of the last error that happened """
701
        result = self.lib.monitorcommand(struct.pack("IIII", 49, 0, 0, 0), "III", ("errno", None, None))
702
        return result.errno
703
 
704
    def disk_mount(self, volume):
705
        """ Mounts a volume """
706
        result = self.lib.monitorcommand(struct.pack("IIII", 50, volume, 0, 0), "III", ("rc", None, None))
707
        if result.rc > 0x80000000:
708
            raise DeviceError("disk_mount(volume=%d) failed with RC=0x%08X, errno=%d" % (volume, result.rc, self.errno()))
709
        return result.rc
710
 
711
    def disk_unmount(self, volume):
712
        """ Unmounts a volume """
713
        result = self.lib.monitorcommand(struct.pack("IIII", 51, volume, 0, 0), "III", ("rc", None, None))
714
        if result.rc > 0x80000000:
715
            raise DeviceError("disk_unmount(volume=%d) failed with RC=0x%08X, errno=%d" % (volume, result.rc, self.errno()))
716
        return result.rc
717
 
718
 
171 farthen 719
class Lib(object):
176 farthen 720
    def __init__(self):
171 farthen 721
        self.idVendor = 0xFFFF
722
        self.idProduct = 0xE000
176 farthen 723
 
724
        self.headersize = 0x10
725
 
726
        self.connect()
56 benedikt93 727
 
171 farthen 728
    def connect(self):
729
        self.dev = Dev(self.idVendor, self.idProduct)
730
        self.connected = True
56 benedikt93 731
 
171 farthen 732
    def monitorcommand(self, cmd, rcvdatatypes=None, rcvstruct=None):
269 farthen 733
        writelen = self.dev.cout(cmd)
171 farthen 734
        if rcvdatatypes:
735
            rcvdatatypes = "I" + rcvdatatypes # add the response
736
            data = self.dev.cin(struct.calcsize(rcvdatatypes))
737
            data = struct.unpack(rcvdatatypes, data)
738
            response = data[0]
739
            if libembiosdata.responsecodes[response] == "ok":
740
                if rcvstruct:
741
                    datadict = Bunch()
742
                    counter = 1 # start with 1, 0 is the id
743
                    for item in rcvstruct:
744
                        if item != None: # else the data is undefined
745
                            datadict[item] = data[counter]
746
                        counter += 1
747
                    return datadict
748
                else:
749
                    return data
750
            elif libembiosdata.responsecodes[response] == "unsupported":
751
                raise DeviceError("The device does not support this command.")
752
            elif libembiosdata.responsecodes[response] == "invalid":
753
                raise DeviceError("Invalid command! This should NOT happen!")
754
            elif libembiosdata.responsecodes[response] == "busy":
755
                raise DeviceError("Device busy")
269 farthen 756
        else:
757
            return writelen
56 benedikt93 758
 
759
 
171 farthen 760
class Dev(object):
761
    def __init__(self, idVendor, idProduct):
762
        self.idVendor = idVendor
763
        self.idProduct = idProduct
67 benedikt93 764
 
171 farthen 765
        self.interface = 0
766
        self.timeout = 100
176 farthen 767
 
171 farthen 768
        self.connect()
769
        self.findEndpoints()
770
 
342 farthen 771
 
772
        # Device properties
343 farthen 773
        self.packetsizelimit = Bunch()
774
        self.packetsizelimit.cout = None
775
        self.packetsizelimit.cin = None
776
        self.packetsizelimit.dout = None
777
        self.packetsizelimit.din = None
342 farthen 778
 
343 farthen 779
        self.version = Bunch()
342 farthen 780
        self.version.revision = None
781
        self.version.majorv = None
782
        self.version.minorv = None
783
        self.version.patchv = None
784
        self.swtypeid = None
785
        self.hwtypeid = None
786
 
343 farthen 787
        self.usermem = Bunch()
342 farthen 788
        self.usermem.lower = None
789
        self.usermem.upper = None
56 benedikt93 790
 
171 farthen 791
    def __del__(self):
792
        self.disconnect()
56 benedikt93 793
 
171 farthen 794
    def findEndpoints(self):
795
        epcounter = 0
343 farthen 796
        self.endpoint = Bunch()
171 farthen 797
        for cfg in self.dev:
798
            for intf in cfg:
799
                for ep in intf:
800
                    if epcounter == 0:
343 farthen 801
                        self.endpoint.cout = ep.bEndpointAddress
171 farthen 802
                    elif epcounter == 1:
343 farthen 803
                        self.endpoint.cin = ep.bEndpointAddress
171 farthen 804
                    elif epcounter == 2:
343 farthen 805
                        self.endpoint.dout = ep.bEndpointAddress
171 farthen 806
                    elif epcounter == 3:
343 farthen 807
                        self.endpoint.din = ep.bEndpointAddress
171 farthen 808
                    epcounter += 1
809
        if epcounter <= 3:
810
            raise DeviceError("Not all endpoints found in the descriptor. Only "+str(epcounter)+" found, we need 4")
56 benedikt93 811
 
171 farthen 812
    def connect(self):
813
        self.dev = usb.core.find(idVendor=self.idVendor, idProduct=self.idProduct)
814
        if self.dev is None:
815
            raise DeviceNotFoundError()
816
        self.dev.set_configuration()
56 benedikt93 817
 
171 farthen 818
    def disconnect(self):
819
        pass
102 benedikt93 820
 
171 farthen 821
    def send(self, endpoint, data):
822
        size = self.dev.write(endpoint, data, self.interface, self.timeout)
823
        if size != len(data):
176 farthen 824
            raise SendError("Not all data was written!")
171 farthen 825
        return len
102 benedikt93 826
 
171 farthen 827
    def receive(self, endpoint, size):
828
        read = self.dev.read(endpoint, size, self.interface, self.timeout)
829
        if len(read) != size:
176 farthen 830
            raise ReceiveError("Requested size and read size don't match!")
171 farthen 831
        return read
56 benedikt93 832
 
171 farthen 833
    def cout(self, data):
343 farthen 834
        if self.packetsizelimit.cout and len(data) > self.packetsizelimit.cout:
171 farthen 835
            raise SendError("Packet too big")
343 farthen 836
        return self.send(self.endpoint.cout, data)
94 benedikt93 837
 
171 farthen 838
    def cin(self, size):
343 farthen 839
        if self.packetsizelimit.cin and size > self.packetsizelimit.cin:
171 farthen 840
            raise ReceiveError("Packet too big")
343 farthen 841
        return self.receive(self.endpoint.cin, size)
94 benedikt93 842
 
171 farthen 843
    def dout(self, data):
343 farthen 844
        if self.packetsizelimit.dout and len(data) > self.packetsizelimit.dout:
171 farthen 845
            raise SendError("Packet too big")
343 farthen 846
        return self.send(self.endpoint.dout, data)
94 benedikt93 847
 
171 farthen 848
    def din(self, size):
343 farthen 849
        if self.packetsizelimit.din and size > self.packetsizelimit.din:
171 farthen 850
            raise ReceiveError("Packet too big")
343 farthen 851
        return self.receive(self.endpoint.din, size)
56 benedikt93 852
 
96 benedikt93 853
 
171 farthen 854
if __name__ == "__main__":
855
    # Some tests
856
    import sys
857
    embios = Embios()
858
    resp = embios.getversioninfo()
859
    sys.stdout.write("Embios device version information: " + libembiosdata.swtypes[resp.swtypeid] + " v" + str(resp.majorv) + "." + str(resp.minorv) + 
860
                     "." + str(resp.patchv) + " r" + str(resp.revision) + " running on " + libembiosdata.hwtypes[resp.hwtypeid] + "\n")
861
    resp = embios.getusermemrange()
862
    sys.stdout.write("Usermemrange: "+hex(resp.lower)+" - "+hex(resp.upper)+"\n")
863
    memaddr = resp.lower
864
    maxlen = resp.upper - resp.lower
865
    f = open("./embios.py", "rb")
866
    sys.stdout.write("Loading test file (embios.py) to send over USB...\n")
867
    datastr = f.read()[:maxlen]
868
    sys.stdout.write("Sending data...\n")
869
    embios.write(memaddr, datastr)
870
    sys.stdout.write("Encrypting data with the hardware key...\n")
871
    embios.aesencrypt(memaddr, len(datastr), 0)
872
    sys.stdout.write("Reading data back and saving it to 'libembios-test-encrypted.bin'...\n")
873
    f = open("./libembios-test-encrypted.bin", "wb")
874
    f.write(embios.read(memaddr, len(datastr)))
875
    sys.stdout.write("Decrypting the data again...\n")
876
    embios.aesdecrypt(memaddr, len(datastr), 0)
877
    sys.stdout.write("Reading data back from device...\n")
878
    readdata = embios.read(memaddr, len(datastr))
879
    if readdata == datastr:
880
        sys.stdout.write("Data matches!")
881
    else:
346 theseven 882
        sys.stdout.write("Data does NOT match. Something went wrong")