Subversion Repositories freemyipod

Rev

Go to most recent revision | 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
 
379 theseven 541
    def storage_get_info(self, volume):
346 theseven 542
        """ Get information about a storage device """
379 theseven 543
        result = self.lib.monitorcommand(struct.pack("IIII", 27, volume, 0, 0), "IIIIIIII", ("version", None, None, "sectorsize", "numsectors", "vendorptr", "productptr", "revisionptr"))
346 theseven 544
        if result.version != 1:
545
            raise ValueError("Unknown version of storage_info struct: %d" % result.version)
379 theseven 546
        result.vendor = self.readstring(result.vendorptr)
547
        result.product = self.readstring(result.productptr)
548
        result.revision = self.readstring(result.revisionptr)
346 theseven 549
        return result
550
 
551
    def storage_read_sectors_md(self, volume, sector, count, addr):
552
        """ Read sectors from as storage device """
553
        result = self.lib.monitorcommand(struct.pack("IIQIIII", 28, volume, sector, count, addr, 0, 0), "III", ("rc", None, None, None))
554
        if result.rc > 0x80000000:
555
            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 556
 
346 theseven 557
    def storage_write_sectors_md(self, volume, sector, count, addr):
558
        """ Read sectors from as storage device """
559
        result = self.lib.monitorcommand(struct.pack("IIQIIII", 29, volume, sector, count, addr, 0, 0), "III", ("rc", None, None, None))
560
        if result.rc > 0x80000000:
561
            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))
562
 
563
    def file_open(self, filename, mode):
564
        """ Opens a file and returns the handle """
565
        result = self.lib.monitorcommand(struct.pack("IIII%dsB" % len(filename), 30, mode, 0, 0, filename, 0), "III", ("fd", None, None))
566
        if result.fd > 0x80000000:
567
            raise DeviceError("file_open(filename=\"%s\", mode=0x%X) failed with RC=0x%08X, errno=%d" % (filename, mode, result.fd, self.errno()))
568
        return result.fd
569
 
570
    def file_size(self, fd):
571
        """ Gets the size of a file referenced by a handle """
572
        result = self.lib.monitorcommand(struct.pack("IIII", 31, fd, 0, 0), "III", ("size", None, None))
573
        if result.size > 0x80000000:
574
            raise DeviceError("file_size(fd=%d) failed with RC=0x%08X, errno=%d" % (fd, result.size, self.errno()))
575
        return result.size
576
 
577
    def file_read(self, fd, addr, size):
578
        """ Reads data from a file referenced by a handle """
579
        result = self.lib.monitorcommand(struct.pack("IIII", 32, fd, addr, size), "III", ("rc", None, None))
580
        if result.rc > 0x80000000:
581
            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()))
582
        return result.rc
583
 
584
    def file_write(self, fd, addr, size):
585
        """ Writes data from a file referenced by a handle """
586
        result = self.lib.monitorcommand(struct.pack("IIII", 33, fd, addr, size), "III", ("rc", None, None))
587
        if result.rc > 0x80000000:
588
            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()))
589
        return result.rc
590
 
591
    def file_seek(self, fd, offset, whence):
592
        """ Seeks the file handle to the specified position in the file """
593
        result = self.lib.monitorcommand(struct.pack("IIII", 34, fd, offset, whence), "III", ("rc", None, None))
594
        if result.rc > 0x80000000:
595
            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()))
596
        return result.rc
597
 
598
    def file_truncate(self, fd, length):
599
        """ Truncates a file referenced by a handle to a specified length """
600
        result = self.lib.monitorcommand(struct.pack("IIII", 35, fd, offset, 0), "III", ("rc", None, None))
601
        if result.rc > 0x80000000:
602
            raise DeviceError("file_truncate(fd=%d, length=0x%08X) failed with RC=0x%08X, errno=%d" % (fd, length, result.rc, self.errno()))
603
        return result.rc
604
 
605
    def file_sync(self, fd):
606
        """ Flushes a file handles' buffers """
607
        result = self.lib.monitorcommand(struct.pack("IIII", 36, fd, 0, 0), "III", ("rc", None, None))
608
        if result.rc > 0x80000000:
609
            raise DeviceError("file_sync(fd=%d) failed with RC=0x%08X, errno=%d" % (fd, result.rc, self.errno()))
610
        return result.rc
611
 
612
    def file_close(self, fd):
613
        """ Closes a file handle """
614
        result = self.lib.monitorcommand(struct.pack("IIII", 37, fd, 0, 0), "III", ("rc", None, None))
615
        if result.rc > 0x80000000:
616
            raise DeviceError("file_close(fd=%d) failed with RC=0x%08X, errno=%d" % (fd, result.rc, self.errno()))
617
        return result.rc
618
 
619
    def file_close_all(self):
620
        """ Closes all file handles opened through the debugger """
621
        result = self.lib.monitorcommand(struct.pack("IIII", 38, 0, 0, 0), "III", ("rc", None, None))
622
        if result.rc > 0x80000000:
623
            raise DeviceError("file_close_all() failed with RC=0x%08X, errno=%d" % (result.rc, self.errno()))
624
        return result.rc
625
 
626
    def file_kill_all(self):
627
        """ Kills all file handles (in the whole system) """
628
        result = self.lib.monitorcommand(struct.pack("IIII", 39, 0, 0, 0), "III", ("rc", None, None))
629
        if result.rc > 0x80000000:
630
            raise DeviceError("file_kill_all() failed with RC=0x%08X, errno=%d" % (result.rc, self.errno()))
631
        return result.rc
632
 
633
    def file_unlink(self, filename):
634
        """ Removes a file """
635
        result = self.lib.monitorcommand(struct.pack("IIII%dsB" % len(filename), 40, 0, 0, 0, filename, 0), "III", ("rc", None, None))
636
        if result.rc > 0x80000000:
637
            raise DeviceError("file_unlink(filename=\"%s\") failed with RC=0x%08X, errno=%d" % (filename, result.rc, self.errno()))
638
        return result.rc
639
 
640
    def file_rename(self, oldname, newname):
641
        """ Renames a file """
642
        result = self.lib.monitorcommand(struct.pack("IIII248s%dsB" % min(247, len(newname)), 41, 0, 0, 0, oldname, newname, 0), "III", ("rc", None, None))
643
        if result.rc > 0x80000000:
644
            raise DeviceError("file_rename(oldname=\"%s\", newname=\"%s\") failed with RC=0x%08X, errno=%d" % (oldname, newname, result.rc, self.errno()))
645
        return result.rc
646
 
647
    def dir_open(self, dirname):
648
        """ Opens a directory and returns the handle """
649
        result = self.lib.monitorcommand(struct.pack("IIII%dsB" % len(dirname), 42, 0, 0, 0, dirname, 0), "III", ("handle", None, None))
650
        if result.handle == 0:
651
            raise DeviceError("dir_open(dirname=\"%s\") failed with RC=0x%08X, errno=%d" % (dirname, result.handle, self.errno()))
652
        return result.handle
653
 
654
    def dir_read(self, handle):
655
        """ Reads the next entry from a directory """
656
        result = self.lib.monitorcommand(struct.pack("IIII", 43, handle, 0, 0), "III", ("version", "maxpath", "ptr"))
657
        if result.ptr == 0:
658
            raise DeviceError("dir_read(handle=0x%08X) failed with RC=0x%08X, errno=%d" % (handle, result.ptr, self.errno()))
659
        if result.version != 1:
660
            raise ValueError("Unknown version of dirent struct: %d" % result.version)
661
        dirent = self.read(result.ptr, result.maxpath + 16)
662
        ret = Bunch()
663
        (ret.name, ret.attributes, ret.size, ret.startcluster, ret.wrtdate, ret.wrttime) = struct.unpack("%dsIIIHH" % result.maxpath, dirent)
664
        ret.name = ret.name[:ret.name.index('\x00')]
665
        return ret
666
 
667
    def dir_close(self, handle):
668
        """ Closes a directory handle """
669
        result = self.lib.monitorcommand(struct.pack("IIII", 44, handle, 0, 0), "III", ("rc", None, None))
670
        if result.rc > 0x80000000:
671
            raise DeviceError("dir_close(handle=0x%08X) failed with RC=0x%08X, errno=%d" % (handle, result.rc, self.errno()))
672
        return result.rc
673
 
674
    def dir_close_all(self):
675
        """ Closes all directory handles opened through the debugger """
676
        result = self.lib.monitorcommand(struct.pack("IIII", 45, 0, 0, 0), "III", ("rc", None, None))
677
        if result.rc > 0x80000000:
678
            raise DeviceError("dir_close_all() failed with RC=0x%08X, errno=%d" % (result.rc, self.errno()))
679
        return result.rc
680
 
681
    def dir_kill_all(self):
682
        """ Kills all directory handles (in the whole system) """
683
        result = self.lib.monitorcommand(struct.pack("IIII", 46, 0, 0, 0), "III", ("rc", None, None))
684
        if result.rc > 0x80000000:
685
            raise DeviceError("dir_kill_all() failed with RC=0x%08X, errno=%d" % (result.rc, self.errno()))
686
        return result.rc
687
 
688
    def dir_create(self, dirname):
689
        """ Creates a directory """
690
        result = self.lib.monitorcommand(struct.pack("IIII%dsB" % len(dirname), 47, 0, 0, 0, dirname, 0), "III", ("rc", None, None))
691
        if result.rc > 0x80000000:
692
            raise DeviceError("dir_create(dirname=\"%s\") failed with RC=0x%08X, errno=%d" % (dirname, result.rc, self.errno()))
693
        return result.rc
694
 
695
    def dir_remove(self, dirname):
696
        """ Removes an (empty) directory """
697
        result = self.lib.monitorcommand(struct.pack("IIII%dsB" % len(dirname), 48, 0, 0, 0, dirname, 0), "III", ("rc", None, None))
698
        if result.rc > 0x80000000:
699
            raise DeviceError("dir_remove(dirname=\"%s\") failed with RC=0x%08X, errno=%d" % (dirname, result.rc, self.errno()))
700
        return result.rc
701
 
702
    def errno(self):
703
        """ Returns the number of the last error that happened """
704
        result = self.lib.monitorcommand(struct.pack("IIII", 49, 0, 0, 0), "III", ("errno", None, None))
705
        return result.errno
706
 
707
    def disk_mount(self, volume):
708
        """ Mounts a volume """
709
        result = self.lib.monitorcommand(struct.pack("IIII", 50, volume, 0, 0), "III", ("rc", None, None))
710
        if result.rc > 0x80000000:
711
            raise DeviceError("disk_mount(volume=%d) failed with RC=0x%08X, errno=%d" % (volume, result.rc, self.errno()))
712
        return result.rc
713
 
714
    def disk_unmount(self, volume):
715
        """ Unmounts a volume """
716
        result = self.lib.monitorcommand(struct.pack("IIII", 51, volume, 0, 0), "III", ("rc", None, None))
717
        if result.rc > 0x80000000:
718
            raise DeviceError("disk_unmount(volume=%d) failed with RC=0x%08X, errno=%d" % (volume, result.rc, self.errno()))
719
        return result.rc
720
 
721
 
171 farthen 722
class Lib(object):
176 farthen 723
    def __init__(self):
171 farthen 724
        self.idVendor = 0xFFFF
725
        self.idProduct = 0xE000
176 farthen 726
 
727
        self.headersize = 0x10
728
 
729
        self.connect()
56 benedikt93 730
 
171 farthen 731
    def connect(self):
732
        self.dev = Dev(self.idVendor, self.idProduct)
733
        self.connected = True
56 benedikt93 734
 
171 farthen 735
    def monitorcommand(self, cmd, rcvdatatypes=None, rcvstruct=None):
269 farthen 736
        writelen = self.dev.cout(cmd)
171 farthen 737
        if rcvdatatypes:
738
            rcvdatatypes = "I" + rcvdatatypes # add the response
739
            data = self.dev.cin(struct.calcsize(rcvdatatypes))
740
            data = struct.unpack(rcvdatatypes, data)
741
            response = data[0]
742
            if libembiosdata.responsecodes[response] == "ok":
743
                if rcvstruct:
744
                    datadict = Bunch()
745
                    counter = 1 # start with 1, 0 is the id
746
                    for item in rcvstruct:
747
                        if item != None: # else the data is undefined
748
                            datadict[item] = data[counter]
749
                        counter += 1
750
                    return datadict
751
                else:
752
                    return data
753
            elif libembiosdata.responsecodes[response] == "unsupported":
754
                raise DeviceError("The device does not support this command.")
755
            elif libembiosdata.responsecodes[response] == "invalid":
756
                raise DeviceError("Invalid command! This should NOT happen!")
757
            elif libembiosdata.responsecodes[response] == "busy":
758
                raise DeviceError("Device busy")
269 farthen 759
        else:
760
            return writelen
56 benedikt93 761
 
762
 
171 farthen 763
class Dev(object):
764
    def __init__(self, idVendor, idProduct):
765
        self.idVendor = idVendor
766
        self.idProduct = idProduct
67 benedikt93 767
 
171 farthen 768
        self.interface = 0
769
        self.timeout = 100
176 farthen 770
 
171 farthen 771
        self.connect()
772
        self.findEndpoints()
773
 
342 farthen 774
 
775
        # Device properties
343 farthen 776
        self.packetsizelimit = Bunch()
777
        self.packetsizelimit.cout = None
778
        self.packetsizelimit.cin = None
779
        self.packetsizelimit.dout = None
780
        self.packetsizelimit.din = None
342 farthen 781
 
343 farthen 782
        self.version = Bunch()
342 farthen 783
        self.version.revision = None
784
        self.version.majorv = None
785
        self.version.minorv = None
786
        self.version.patchv = None
787
        self.swtypeid = None
788
        self.hwtypeid = None
789
 
343 farthen 790
        self.usermem = Bunch()
342 farthen 791
        self.usermem.lower = None
792
        self.usermem.upper = None
56 benedikt93 793
 
171 farthen 794
    def __del__(self):
795
        self.disconnect()
56 benedikt93 796
 
171 farthen 797
    def findEndpoints(self):
798
        epcounter = 0
343 farthen 799
        self.endpoint = Bunch()
171 farthen 800
        for cfg in self.dev:
801
            for intf in cfg:
802
                for ep in intf:
803
                    if epcounter == 0:
343 farthen 804
                        self.endpoint.cout = ep.bEndpointAddress
171 farthen 805
                    elif epcounter == 1:
343 farthen 806
                        self.endpoint.cin = ep.bEndpointAddress
171 farthen 807
                    elif epcounter == 2:
343 farthen 808
                        self.endpoint.dout = ep.bEndpointAddress
171 farthen 809
                    elif epcounter == 3:
343 farthen 810
                        self.endpoint.din = ep.bEndpointAddress
171 farthen 811
                    epcounter += 1
812
        if epcounter <= 3:
813
            raise DeviceError("Not all endpoints found in the descriptor. Only "+str(epcounter)+" found, we need 4")
56 benedikt93 814
 
171 farthen 815
    def connect(self):
816
        self.dev = usb.core.find(idVendor=self.idVendor, idProduct=self.idProduct)
817
        if self.dev is None:
818
            raise DeviceNotFoundError()
819
        self.dev.set_configuration()
56 benedikt93 820
 
171 farthen 821
    def disconnect(self):
822
        pass
102 benedikt93 823
 
171 farthen 824
    def send(self, endpoint, data):
825
        size = self.dev.write(endpoint, data, self.interface, self.timeout)
826
        if size != len(data):
176 farthen 827
            raise SendError("Not all data was written!")
171 farthen 828
        return len
102 benedikt93 829
 
171 farthen 830
    def receive(self, endpoint, size):
831
        read = self.dev.read(endpoint, size, self.interface, self.timeout)
832
        if len(read) != size:
176 farthen 833
            raise ReceiveError("Requested size and read size don't match!")
171 farthen 834
        return read
56 benedikt93 835
 
171 farthen 836
    def cout(self, data):
343 farthen 837
        if self.packetsizelimit.cout and len(data) > self.packetsizelimit.cout:
171 farthen 838
            raise SendError("Packet too big")
343 farthen 839
        return self.send(self.endpoint.cout, data)
94 benedikt93 840
 
171 farthen 841
    def cin(self, size):
343 farthen 842
        if self.packetsizelimit.cin and size > self.packetsizelimit.cin:
171 farthen 843
            raise ReceiveError("Packet too big")
343 farthen 844
        return self.receive(self.endpoint.cin, size)
94 benedikt93 845
 
171 farthen 846
    def dout(self, data):
343 farthen 847
        if self.packetsizelimit.dout and len(data) > self.packetsizelimit.dout:
171 farthen 848
            raise SendError("Packet too big")
343 farthen 849
        return self.send(self.endpoint.dout, data)
94 benedikt93 850
 
171 farthen 851
    def din(self, size):
343 farthen 852
        if self.packetsizelimit.din and size > self.packetsizelimit.din:
171 farthen 853
            raise ReceiveError("Packet too big")
343 farthen 854
        return self.receive(self.endpoint.din, size)
56 benedikt93 855
 
96 benedikt93 856
 
171 farthen 857
if __name__ == "__main__":
858
    # Some tests
859
    import sys
860
    embios = Embios()
861
    resp = embios.getversioninfo()
862
    sys.stdout.write("Embios device version information: " + libembiosdata.swtypes[resp.swtypeid] + " v" + str(resp.majorv) + "." + str(resp.minorv) + 
863
                     "." + str(resp.patchv) + " r" + str(resp.revision) + " running on " + libembiosdata.hwtypes[resp.hwtypeid] + "\n")
864
    resp = embios.getusermemrange()
865
    sys.stdout.write("Usermemrange: "+hex(resp.lower)+" - "+hex(resp.upper)+"\n")
866
    memaddr = resp.lower
867
    maxlen = resp.upper - resp.lower
868
    f = open("./embios.py", "rb")
869
    sys.stdout.write("Loading test file (embios.py) to send over USB...\n")
870
    datastr = f.read()[:maxlen]
871
    sys.stdout.write("Sending data...\n")
872
    embios.write(memaddr, datastr)
873
    sys.stdout.write("Encrypting data with the hardware key...\n")
874
    embios.aesencrypt(memaddr, len(datastr), 0)
875
    sys.stdout.write("Reading data back and saving it to 'libembios-test-encrypted.bin'...\n")
876
    f = open("./libembios-test-encrypted.bin", "wb")
877
    f.write(embios.read(memaddr, len(datastr)))
878
    sys.stdout.write("Decrypting the data again...\n")
879
    embios.aesdecrypt(memaddr, len(datastr), 0)
880
    sys.stdout.write("Reading data back from device...\n")
881
    readdata = embios.read(memaddr, len(datastr))
882
    if readdata == datastr:
883
        sys.stdout.write("Data matches!")
884
    else:
346 theseven 885
        sys.stdout.write("Data does NOT match. Something went wrong")