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()
75
        self.getpacketsizeinfo()
56 benedikt93 76
 
171 farthen 77
    @staticmethod
78
    def _alignsplit(addr, size, blksize, align):
177 farthen 79
        if size <= blksize: return (size, 0, 0)
171 farthen 80
        end = addr + size
81
        if addr & (align - 1):
82
            bodyaddr = (addr + min(size, blksize)) & ~(align - 1)
83
        else: bodyaddr = addr
84
        headsize = bodyaddr - addr
85
        if (size - headsize) & (align - 1):
86
            tailaddr = (end - min(end - bodyaddr, blksize) + align - 1) & ~(align - 1)
87
        else: tailaddr = end
88
        tailsize = end - tailaddr
89
        return (headsize, tailaddr - bodyaddr, tailsize)
56 benedikt93 90
 
178 farthen 91
    def _readmem(self, addr, size):
92
        """ Reads the memory from location 'addr' with size 'size'
93
            from the device.
94
        """
95
        resp = self.lib.monitorcommand(struct.pack("IIII", 4, addr, size, 0), "III%ds" % size, (None, None, None, "data"))
96
        return resp.data
97
 
98
    def _writemem(self, addr, data):
99
        """ Writes the data in 'data' to the location 'addr'
100
            in the memory of the device.
101
        """
102
        return self.lib.monitorcommand(struct.pack("IIII%ds" % len(data), 5, addr, len(data), 0, data), "III", (None, None, None))
103
 
104
    def _readdma(self, addr, size):
105
        """ Reads the memory from location 'addr' with size 'size'
106
            from the device. This uses DMA and the data in endpoint.
107
        """
108
        self.lib.monitorcommand(struct.pack("IIII", 6, addr, size, 0), "III", (None, None, None))
109
        return struct.unpack("%ds" % size, self.lib.dev.din(size))[0]
110
 
111
    def _writedma(self, addr, data):
112
        """ Writes the data in 'data' to the location 'addr'
113
            in the memory of the device. This uses DMA and the data out endpoint.
114
        """
115
        self.lib.monitorcommand(struct.pack("IIII", 7, addr, len(data), 0), "III", (None, None, None))
116
        return self.lib.dev.dout(data)
117
 
171 farthen 118
    def getversioninfo(self):
119
        """ This returns the emBIOS version and device information. """
342 farthen 120
        resp = self.lib.monitorcommand(struct.pack("IIII", 1, 0, 0, 0), "IBBBBI", ("revision", "majorv", "minorv", "patchv", "swtypeid", "hwtypeid"))
121
        self.lib.dev.version.revision = resp.revision
122
        self.lib.dev.version.majorv = resp.majorv
123
        self.lib.dev.version.minorv = resp.minorv
124
        self.lib.dev.version.patchv = resp.patchv
125
        self.lib.dev.swtypeid = resp.swtypeid
126
        self.lib.dev.hwtypeid = resp.hwtypeid
127
        return resp
56 benedikt93 128
 
171 farthen 129
    def getpacketsizeinfo(self):
130
        """ This returns the emBIOS max packet size information.
131
            It also sets the properties of the device object accordingly.
132
        """
133
        resp = self.lib.monitorcommand(struct.pack("IIII", 1, 1, 0, 0), "HHII", ("coutmax", "cinmax", "doutmax", "dinmax"))
134
        self.lib.dev.packetsizelimit['cout'] = resp.coutmax
135
        self.lib.dev.packetsizelimit['cin'] = resp.cinmax
136
        self.lib.dev.packetsizelimit['din'] = resp.dinmax
137
        self.lib.dev.packetsizelimit['dout'] = resp.doutmax
138
        return resp
56 benedikt93 139
 
171 farthen 140
    def getusermemrange(self):
141
        """ This returns the memory range the user has access to. """
342 farthen 142
        resp = self.lib.monitorcommand(struct.pack("IIII", 1, 2, 0, 0), "III", ("lower", "upper", None))
143
        self.lib.dev.usermem.lower = resp.lower
144
        self.lib.dev.usermem.upper = resp.upper
145
        return resp
56 benedikt93 146
 
171 farthen 147
    def reset(self, force=False):
148
        """ Reboot the device """
149
        if force:
150
            return self.lib.monitorcommand(struct.pack("IIII", 2, 0, 0, 0))
151
        else:
152
            return self.lib.monitorcommand(struct.pack("IIII", 2, 1, 0, 0), "III", (None, None, None))
56 benedikt93 153
 
171 farthen 154
    def poweroff(self, force=False):
155
        """ Powers the device off. """
156
        if force:
157
            return self.lib.monitorcommand(struct.pack("IIII", 3, 0, 0, 0))
158
        else:
159
            return self.lib.monitorcommand(struct.pack("IIII", 3, 1, 0, 0), "III", (None, None, None))
56 benedikt93 160
 
171 farthen 161
    def read(self, addr, size):
162
        """ Reads the memory from location 'addr' with size 'size'
163
            from the device. This cares about too long packages
164
            and decides whether to use DMA or not.
165
        """
176 farthen 166
        cin_maxsize = self.lib.dev.packetsizelimit["cin"] - self.lib.headersize
171 farthen 167
        din_maxsize = self.lib.dev.packetsizelimit["din"]
168
        data = ""
169
        (headsize, bodysize, tailsize) = self._alignsplit(addr, size, cin_maxsize, 16)
170
        if headsize != 0:
178 farthen 171
            data += self._readmem(addr, headsize)
171 farthen 172
            addr += headsize
173
        while bodysize > 0:
174
            if bodysize >= 2 * cin_maxsize:
175
                readsize = min(bodysize, din_maxsize)
178 farthen 176
                data += self._readdma(addr, readsize)
171 farthen 177
            else:
178
                readsize = min(bodysize, cin_maxsize)
178 farthen 179
                data += self._readmem(addr, readsize)
171 farthen 180
            addr += readsize
181
            bodysize -= readsize
182
        if tailsize != 0:
178 farthen 183
            data += self._readmem(addr, tailsize)
171 farthen 184
        return data
56 benedikt93 185
 
171 farthen 186
    def write(self, addr, data):
187
        """ Writes the data in 'data' to the location 'addr'
188
            in the memory of the device. This cares about too long packages
189
            and decides whether to use DMA or not.
190
        """
176 farthen 191
        cout_maxsize = self.lib.dev.packetsizelimit["cout"] - self.lib.headersize
171 farthen 192
        dout_maxsize = self.lib.dev.packetsizelimit["dout"]
193
        (headsize, bodysize, tailsize) = self._alignsplit(addr, len(data), cout_maxsize, 16)
194
        offset = 0
195
        if headsize != 0:
178 farthen 196
            self._writemem(addr, data[offset:offset+headsize])
171 farthen 197
            offset += headsize
198
            addr += headsize
199
        while bodysize > 0:
200
            if bodysize >= 2 * cout_maxsize:
201
                writesize = min(bodysize, dout_maxsize)
178 farthen 202
                self._writedma(addr, data[offset:offset+writesize])
171 farthen 203
            else:
204
                writesize = min(bodysize, cout_maxsize)
178 farthen 205
                self._writemem(addr, data[offset:offset+writesize])
171 farthen 206
            offset += writesize
207
            addr += writesize
208
            bodysize -= writesize
209
        if tailsize != 0:
178 farthen 210
            self._writemem(addr, data[offset:offset+tailsize])
171 farthen 211
        return data
56 benedikt93 212
 
173 farthen 213
    def readstring(self, addr, maxlength = 256):
214
        """ Reads a zero terminated string from memory 
215
            Reads only a maximum of 'maxlength' chars.
216
        """
176 farthen 217
        cin_maxsize = self.lib.dev.packetsizelimit["cin"] - self.lib.headersize
173 farthen 218
        string = ""
219
        while (len(string) < maxlength or maxlength < 0):
178 farthen 220
            data = self._readmem(addr, min(maxlength - len(string), cin_maxsize))
173 farthen 221
            length = data.find("\0")
222
            if length >= 0:
223
                string += data[:length]
224
                break
225
            else:
226
                string += data
227
            addr += cin_maxsize
228
        return string
229
 
171 farthen 230
    def i2cread(self, index, slaveaddr, startaddr, size):
231
        """ Reads data from an i2c slave """
236 farthen 232
        data = ""
233
        for i in range(size):
234
            resp = self.lib.monitorcommand(struct.pack("IBBBBII", 8, index, slaveaddr, startaddr + i, 1, 0, 0), "III1s", (None, None, None, "data"))
235
            data += resp.data
236
        return data
56 benedikt93 237
 
171 farthen 238
    def i2cwrite(self, index, slaveaddr, startaddr, data):
239
        """ Writes data to an i2c slave """
176 farthen 240
        size = len(data)
241
        if size > 256 or size < 1:
341 farthen 242
            raise ArgumentError("Size must be a number between 1 and 256")
176 farthen 243
        if size == 256:
244
            size = 0
215 theseven 245
        return self.lib.monitorcommand(struct.pack("IBBBBII%ds" % size, 9, index, slaveaddr, startaddr, size, 0, 0, data), "III", (None, None, None))
56 benedikt93 246
 
176 farthen 247
    def usbcread(self):
248
        """ Reads one packet with the maximal cin size """
249
        cin_maxsize = self.lib.dev.packetsizelimit["cin"] - self.lib.headersize
250
        resp = self.lib.monitorcommand(struct.pack("IIII", 10, cin_maxsize, 0, 0), "III%ds" % cin_maxsize, ("validsize", "buffersize", "queuesize", "data"))
251
        resp.data = resp.data[:resp.validsize]
252
        resp.maxsize = cin_maxsize
253
        return resp
56 benedikt93 254
 
171 farthen 255
    def usbcwrite(self, data):
256
        """ Writes data to the USB console """
176 farthen 257
        cin_maxsize = self.lib.dev.packetsizelimit["cin"] - self.lib.headersize
258
        size = len(data)
259
        while len(data) > 0:
260
            writesize = min(cin_maxsize, len(data))
261
            resp = self.lib.monitorcommand(struct.pack("IIII%ds" % writesize, 11, writesize, 0, 0, data[:writesize]), "III", ("validsize", "buffersize", "freesize"))
262
            data = data[resp.validsize:]
263
        return size
56 benedikt93 264
 
176 farthen 265
    def cread(self, bitmask=0x1):
266
        """ Reads one packet with the maximal cin size from the device consoles
171 farthen 267
            identified with the specified bitmask
268
        """
176 farthen 269
        cin_maxsize = self.lib.dev.packetsizelimit["cin"] - self.lib.headersize
217 theseven 270
        resp = self.lib.monitorcommand(struct.pack("IIII", 13, bitmask, cin_maxsize, 0), "III%ds" % cin_maxsize, ("size", None, None))
176 farthen 271
        resp.data = resp.data[size:]
272
        resp.maxsize = cin_maxsize
273
        return resp
56 benedikt93 274
 
176 farthen 275
    def cwrite(self, data, bitmask=0x1):
171 farthen 276
        """ Writes data to the device consoles 
277
            identified with the specified bitmask.
278
        """
176 farthen 279
        cin_maxsize = self.lib.dev.packetsizelimit["cin"] - self.lib.headersize
280
        size = len(data)
281
        while len(data) > 0:
282
            writesize = min(cin_maxsize, len(data))
217 theseven 283
            resp = self.lib.monitorcommand(struct.pack("IIII%ds" % writesize, 12, bitmask, writesize, 0, data[:writesize]), "III", (None, None, None))
176 farthen 284
            data = data[writesize:]
285
        return size
56 benedikt93 286
 
171 farthen 287
    def cflush(self, bitmask):
288
        """ Flushes the consoles specified with 'bitmask' """
289
        return self.lib.monitorcommand(struct.pack("IIII", 14, bitmask, 0, 0), "III", (None, None, None))
56 benedikt93 290
 
173 farthen 291
    def getprocinfo(self):
171 farthen 292
        """ Gets current state of the scheduler """
176 farthen 293
        cin_maxsize = self.lib.dev.packetsizelimit["cin"] - self.lib.headersize
173 farthen 294
        # Get the size
295
        schedulerstate = self.lockscheduler()
296
        resp = self.lib.monitorcommand(struct.pack("IIII", 15, 0, 0, 0), "III", ("structver", "tablesize", None))
297
        tablesize = resp.tablesize
298
        size = tablesize
299
        structver = resp.structver
300
        offset = 0
301
        data = ""
302
        while size > 0:
303
            if size > cin_maxsize:
304
                readsize = cin_maxsize
305
            else:
306
                readsize = size
307
            resp = self.lib.monitorcommand(struct.pack("IIII", 15, offset, readsize, 0), "III%ds" % readsize, ("structver", "tablesize", None, "data"))
308
            data += resp.data
309
            offset += readsize
310
            size -= readsize
311
        self.lockscheduler(schedulerstate)
312
        threadstructsize = 120
313
        registersize = 32
314
        if len(data) % threadstructsize != 0:
315
            raise DeviceError("The thread struct is not a multiple of "+str(threadsturcsize)+"!")
316
        threadcount = len(data) / threadstructsize
317
        threads = []
318
        id = 0
319
        for thread in range(threadcount):
320
            offset = threadstructsize * thread
321
            threaddata = struct.unpack("<16IIIIIQIIIIIIIBBBB", data[offset:offset+threadstructsize])
322
            info = Bunch()
323
            info.id = id
324
            state = threaddata[17]
325
            info.state = libembiosdata.thread_state[state]
326
            if info.state == "THREAD_FREE":
327
                id += 1
328
                continue
329
            info.regs = Bunch()
330
            for register in range(16):
331
                info.regs["r"+str(register)] = threaddata[register]
332
            info.regs.cpsr = threaddata[16]
333
            info.nameptr = threaddata[18]
334
            if info.nameptr == 0:
335
                info.name = "Thread %d" % info.id
336
            else:
337
                info.name = self.readstring(info.nameptr)
338
            info.cputime_current = threaddata[19]
339
            info.cputime_total = threaddata[20]
340
            info.startusec = threaddata[21]
341
            info.queue_next_ptr = threaddata[22]
342
            info.timeout = threaddata[23]
343
            info.blocked_since = threaddata[24]
344
            info.blocked_by_ptr = threaddata[25]
345
            info.stackaddr = threaddata[26]
346
            info.err_no = threaddata[27]
347
            info.block_type = libembiosdata.thread_block[threaddata[28]]
348
            info.type = libembiosdata.thread_type[threaddata[29]]
349
            info.priority = threaddata[30]
350
            info.cpuload = threaddata[31]
351
            threads.append(info)
352
            id += 1
353
        return threads
56 benedikt93 354
 
173 farthen 355
    def lockscheduler(self, freeze=True):
171 farthen 356
        """ Freezes/Unfreezes the scheduler """
173 farthen 357
        resp = self.lib.monitorcommand(struct.pack("IIII", 16, 1 if freeze else 0, 0, 0), "III", ("before", None, None))
358
        return True if resp.before == 1 else False
67 benedikt93 359
 
173 farthen 360
    def unlockscheduler(self):
171 farthen 361
        """ Unfreezes the scheduler """
362
        return self.lib.monitorcommand(struct.pack("IIII", 16, 0, 0, 0), "III", ("before", None, None))
56 benedikt93 363
 
171 farthen 364
    def suspendthread(self, id, suspend=True):
365
        """ Suspends the thread with the specified id """
173 farthen 366
        resp = self.lib.monitorcommand(struct.pack("IIII", 17, 1 if suspend else 0, id, 0), "III", ("before", None, None))
367
        return True if resp.before == 1 else False
56 benedikt93 368
 
173 farthen 369
    def resumethread(self, id):
370
        """ Resumes the thread with the specified id """
171 farthen 371
        return self.lib.monitorcommand(struct.pack("IIII", 17, 0, id, 0), "III", ("before", None, None))
56 benedikt93 372
 
171 farthen 373
    def killthread(self, id):
374
        """ Kills the thread with the specified id """
375
        return self.lib.monitorcommand(struct.pack("IIII", 18, id, 0, 0), "III", ("before", None, None))
56 benedikt93 376
 
171 farthen 377
    def createthread(self, nameptr, entrypoint, stackptr, stacksize, threadtype, priority, state):
378
        """ Creates a thread with the specified attributes """
379
        if threadtype == "user":
380
            threadtype = 0
381
        elif threadtype == "system":
382
            threadtype = 1
383
        else:
341 farthen 384
            raise ArgumentError("Threadtype must be either 'system' or 'user'")
171 farthen 385
        if priority > 256 or priority < 0:
341 farthen 386
            raise ArgumentError("Priority must be a number between 0 and 256")
171 farthen 387
        if state == "ready":
388
            state = 0
389
        elif state == "suspended":
390
            state = 1
391
        else:
341 farthen 392
            raise ArgumentError("State must be either 'ready' or 'suspended'")
171 farthen 393
        resp = self.lib.monitorcommand(struct.pack("IIIIIIII", 19, nameptr, entrypoint, stackptr, stacksize, threadtype, priority, state), "III", (id, None, None))
394
        if resp.id < 0:
395
            raise DeviceError("The device returned the error code "+str(resp.id))
396
        return resp
56 benedikt93 397
 
172 farthen 398
    def flushcaches(self):
171 farthen 399
        """ Flushes the CPU instruction and data cache """
400
        return self.lib.monitorcommand(struct.pack("IIII", 20, 0, 0, 0), "III", (None, None, None))
56 benedikt93 401
 
172 farthen 402
    def execimage(self, addr):
171 farthen 403
        """ Runs the emBIOS app at 'addr' """
404
        return self.lib.monitorcommand(struct.pack("IIII", 21, addr, 0, 0), "III", ("excecimage", None, None))
56 benedikt93 405
 
238 farthen 406
    def run(self, app):
407
        """ Uploads and runs the emBIOS app in the string 'app' """
408
        try:
409
            appheader = struct.unpack("<8sIIIIIIIIII", app[:48])
410
        except struct.error:
341 farthen 411
            raise ArgumentError("The specified app is not an emBIOS application")
238 farthen 412
        header = appheader[0]
413
        if header != "emBIexec":
341 farthen 414
            raise ArgumentError("The specified app is not an emBIOS application")
238 farthen 415
        baseaddr = appheader[2]
416
        threadnameptr = appheader[8]
417
        nameptr = threadnameptr - baseaddr
418
        name = ""
419
        while True:
420
            char = app[nameptr:nameptr+1]
421
            try:
422
                if ord(char) == 0:
423
                    break
424
            except TypeError:
341 farthen 425
                raise ArgumentError("The specified app is not an emBIOS application")
238 farthen 426
            name += char
427
            nameptr += 1
428
        usermem = self.getusermemrange()
429
        if usermem.lower > baseaddr or usermem.upper < baseaddr + len(app):
430
            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?")
431
        self.write(baseaddr, app)
432
        self.execimage(baseaddr)
433
        return Bunch(baseaddr=baseaddr, name=name)
434
 
171 farthen 435
    def bootflashread(self, memaddr, flashaddr, size):
436
        """ Copies the data in the bootflash at 'flashaddr' of the specified size
437
            to the memory at addr 'memaddr'
438
        """
174 farthen 439
        return self.lib.monitorcommand(struct.pack("IIII", 22, memaddr, flashaddr, size), "III", (None, None, None))
82 benedikt93 440
 
171 farthen 441
    def bootflashwrite(self, memaddr, flashaddr, size):
442
        """ Copies the data in the memory at 'memaddr' of the specified size
443
            to the boot flash at addr 'flashaddr'
444
        """
174 farthen 445
        return self.lib.monitorcommand(struct.pack("IIII", 23, memaddr, flashaddr, size), "III", (None, None, None))
56 benedikt93 446
 
171 farthen 447
    def execfirmware(self, addr):
448
        """ Executes the firmware at 'addr' and passes all control to it. """
269 farthen 449
        return self.lib.monitorcommand(struct.pack("IIII", 24, addr, 0, 0))
56 benedikt93 450
 
171 farthen 451
    def aesencrypt(self, addr, size, keyindex):
452
        """ Encrypts the buffer at 'addr' with the specified size
453
            with the hardware AES key index 'keyindex'
454
        """
455
        return self.lib.monitorcommand(struct.pack("IBBHII", 25, 1, 0, keyindex, addr, size), "III", (None, None, None))
82 benedikt93 456
 
171 farthen 457
    def aesdecrypt(self, addr, size, keyindex):
458
        """ Decrypts the buffer at 'addr' with the specified size
459
            with the hardware AES key index 'keyindex'
460
        """
461
        return self.lib.monitorcommand(struct.pack("IBBHII", 25, 0, 0, keyindex, addr, size), "III", (None, None, None))
82 benedikt93 462
 
171 farthen 463
    def hmac_sha1(self, addr, size, destination):
464
        """ Generates a HMAC-SHA1 hash of the buffer and saves it to 'destination' """
465
        return self.lib.monitorcommand(struct.pack("IIII", 26, addr, size, destination), "III", (None, None, None))
56 benedikt93 466
 
227 theseven 467
    def ipodnano2g_getnandinfo(self):
468
        """ Target-specific function: ipodnano2g
469
            Gathers some information about the NAND chip used
470
        """
471
        return self.lib.monitorcommand(struct.pack("IIII", 0xffff0001, 0, 0, 0), "IHHHH", ("type", "pagesperblock", "banks", "userblocks", "blocks"))
472
 
473
    def ipodnano2g_nandread(self, addr, start, count, doecc, checkempty):
474
        """ Target-specific function: ipodnano2g
475
            Reads data from the NAND chip into memory
476
        """
477
        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))
478
 
479
    def ipodnano2g_nandwrite(self, addr, start, count, doecc):
480
        """ Target-specific function: ipodnano2g
481
            Writes data to the NAND chip
482
        """
483
        return self.lib.monitorcommand(struct.pack("IIII", 0xffff0003, addr | (0x80000000 if doecc != 0 else 0), start, count), "III", (None, None, None))
484
 
485
    def ipodnano2g_nanderase(self, addr, start, count):
486
        """ Target-specific function: ipodnano2g
487
            Erases blocks on the NAND chip and stores the results to memory
488
        """
489
        return self.lib.monitorcommand(struct.pack("IIII", 0xffff0004, addr, start, count), "III", (None, None, None))
490
 
56 benedikt93 491
 
171 farthen 492
class Lib(object):
176 farthen 493
    def __init__(self):
171 farthen 494
        self.idVendor = 0xFFFF
495
        self.idProduct = 0xE000
176 farthen 496
 
497
        self.headersize = 0x10
498
 
499
        self.connect()
56 benedikt93 500
 
171 farthen 501
    def connect(self):
502
        self.dev = Dev(self.idVendor, self.idProduct)
503
        self.connected = True
56 benedikt93 504
 
171 farthen 505
    def monitorcommand(self, cmd, rcvdatatypes=None, rcvstruct=None):
269 farthen 506
        writelen = self.dev.cout(cmd)
171 farthen 507
        if rcvdatatypes:
508
            rcvdatatypes = "I" + rcvdatatypes # add the response
509
            data = self.dev.cin(struct.calcsize(rcvdatatypes))
510
            data = struct.unpack(rcvdatatypes, data)
511
            response = data[0]
512
            if libembiosdata.responsecodes[response] == "ok":
513
                if rcvstruct:
514
                    datadict = Bunch()
515
                    counter = 1 # start with 1, 0 is the id
516
                    for item in rcvstruct:
517
                        if item != None: # else the data is undefined
518
                            datadict[item] = data[counter]
519
                        counter += 1
520
                    return datadict
521
                else:
522
                    return data
523
            elif libembiosdata.responsecodes[response] == "unsupported":
524
                raise DeviceError("The device does not support this command.")
525
            elif libembiosdata.responsecodes[response] == "invalid":
526
                raise DeviceError("Invalid command! This should NOT happen!")
527
            elif libembiosdata.responsecodes[response] == "busy":
528
                raise DeviceError("Device busy")
269 farthen 529
        else:
530
            return writelen
56 benedikt93 531
 
532
 
171 farthen 533
class Dev(object):
534
    def __init__(self, idVendor, idProduct):
535
        self.idVendor = idVendor
536
        self.idProduct = idProduct
67 benedikt93 537
 
171 farthen 538
        self.interface = 0
539
        self.timeout = 100
176 farthen 540
 
171 farthen 541
        self.connect()
542
        self.findEndpoints()
543
 
342 farthen 544
 
545
        # Device properties
171 farthen 546
        self.packetsizelimit = {}
547
        self.packetsizelimit['cout'] = None
548
        self.packetsizelimit['cin'] = None
549
        self.packetsizelimit['dout'] = None
550
        self.packetsizelimit['din'] = None
342 farthen 551
 
552
        self.version.revision = None
553
        self.version.majorv = None
554
        self.version.minorv = None
555
        self.version.patchv = None
556
        self.swtypeid = None
557
        self.hwtypeid = None
558
 
559
        self.usermem.lower = None
560
        self.usermem.upper = None
56 benedikt93 561
 
171 farthen 562
    def __del__(self):
563
        self.disconnect()
56 benedikt93 564
 
171 farthen 565
    def findEndpoints(self):
566
        epcounter = 0
567
        self.endpoint = {}
568
        for cfg in self.dev:
569
            for intf in cfg:
570
                for ep in intf:
571
                    if epcounter == 0:
572
                        self.endpoint['cout'] = ep.bEndpointAddress
573
                    elif epcounter == 1:
574
                        self.endpoint['cin'] = ep.bEndpointAddress
575
                    elif epcounter == 2:
576
                        self.endpoint['dout'] = ep.bEndpointAddress
577
                    elif epcounter == 3:
578
                        self.endpoint['din'] = ep.bEndpointAddress
579
                    epcounter += 1
580
        if epcounter <= 3:
581
            raise DeviceError("Not all endpoints found in the descriptor. Only "+str(epcounter)+" found, we need 4")
56 benedikt93 582
 
171 farthen 583
    def connect(self):
584
        self.dev = usb.core.find(idVendor=self.idVendor, idProduct=self.idProduct)
585
        if self.dev is None:
586
            raise DeviceNotFoundError()
587
        self.dev.set_configuration()
56 benedikt93 588
 
171 farthen 589
    def disconnect(self):
590
        pass
102 benedikt93 591
 
171 farthen 592
    def send(self, endpoint, data):
593
        size = self.dev.write(endpoint, data, self.interface, self.timeout)
594
        if size != len(data):
176 farthen 595
            raise SendError("Not all data was written!")
171 farthen 596
        return len
102 benedikt93 597
 
171 farthen 598
    def receive(self, endpoint, size):
599
        read = self.dev.read(endpoint, size, self.interface, self.timeout)
600
        if len(read) != size:
176 farthen 601
            raise ReceiveError("Requested size and read size don't match!")
171 farthen 602
        return read
56 benedikt93 603
 
171 farthen 604
    def cout(self, data):
605
        if self.packetsizelimit['cout'] and len(data) > self.packetsizelimit['cout']:
606
            raise SendError("Packet too big")
607
        return self.send(self.endpoint['cout'], data)
94 benedikt93 608
 
171 farthen 609
    def cin(self, size):
610
        if self.packetsizelimit['cin'] and size > self.packetsizelimit['cin']:
611
            raise ReceiveError("Packet too big")
612
        return self.receive(self.endpoint['cin'], size)
94 benedikt93 613
 
171 farthen 614
    def dout(self, data):
615
        if self.packetsizelimit['dout'] and len(data) > self.packetsizelimit['dout']:
616
            raise SendError("Packet too big")
617
        return self.send(self.endpoint['dout'], data)
94 benedikt93 618
 
171 farthen 619
    def din(self, size):
620
        if self.packetsizelimit['din'] and size > self.packetsizelimit['din']:
621
            raise ReceiveError("Packet too big")
622
        return self.receive(self.endpoint['din'], size)
56 benedikt93 623
 
96 benedikt93 624
 
171 farthen 625
if __name__ == "__main__":
626
    # Some tests
627
    import sys
628
    embios = Embios()
629
    resp = embios.getversioninfo()
630
    sys.stdout.write("Embios device version information: " + libembiosdata.swtypes[resp.swtypeid] + " v" + str(resp.majorv) + "." + str(resp.minorv) + 
631
                     "." + str(resp.patchv) + " r" + str(resp.revision) + " running on " + libembiosdata.hwtypes[resp.hwtypeid] + "\n")
632
    resp = embios.getusermemrange()
633
    sys.stdout.write("Usermemrange: "+hex(resp.lower)+" - "+hex(resp.upper)+"\n")
634
    memaddr = resp.lower
635
    maxlen = resp.upper - resp.lower
636
    f = open("./embios.py", "rb")
637
    sys.stdout.write("Loading test file (embios.py) to send over USB...\n")
638
    datastr = f.read()[:maxlen]
639
    sys.stdout.write("Sending data...\n")
640
    embios.write(memaddr, datastr)
641
    sys.stdout.write("Encrypting data with the hardware key...\n")
642
    embios.aesencrypt(memaddr, len(datastr), 0)
643
    sys.stdout.write("Reading data back and saving it to 'libembios-test-encrypted.bin'...\n")
644
    f = open("./libembios-test-encrypted.bin", "wb")
645
    f.write(embios.read(memaddr, len(datastr)))
646
    sys.stdout.write("Decrypting the data again...\n")
647
    embios.aesdecrypt(memaddr, len(datastr), 0)
648
    sys.stdout.write("Reading data back from device...\n")
649
    readdata = embios.read(memaddr, len(datastr))
650
    if readdata == datastr:
651
        sys.stdout.write("Data matches!")
652
    else:
653
        sys.stdout.write("Data does NOT match. Something got wrong")