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