sdfgen 0.9.0__cp312-cp312-musllinux_1_2_x86_64.whl
Sign up to get free protection for your applications and to get access to all the features.
- csdfgen.cpython-312-x86_64-linux-musl.so +0 -0
- sdfgen/__init__.py +3 -0
- sdfgen/module.py +683 -0
- sdfgen/py.typed +0 -0
- sdfgen-0.9.0.dist-info/METADATA +160 -0
- sdfgen-0.9.0.dist-info/RECORD +8 -0
- sdfgen-0.9.0.dist-info/WHEEL +5 -0
- sdfgen-0.9.0.dist-info/top_level.txt +2 -0
Binary file
|
sdfgen/__init__.py
ADDED
sdfgen/module.py
ADDED
@@ -0,0 +1,683 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
import ctypes
|
3
|
+
import importlib.util
|
4
|
+
from ctypes import (
|
5
|
+
cast, c_void_p, c_char_p, c_uint8, c_uint16, c_uint32, c_uint64, c_bool, POINTER, byref
|
6
|
+
)
|
7
|
+
from typing import Optional, List, Tuple
|
8
|
+
from enum import IntEnum
|
9
|
+
|
10
|
+
# TOOD: double check
|
11
|
+
MapPermsType = c_uint32
|
12
|
+
|
13
|
+
libsdfgen = ctypes.CDLL(importlib.util.find_spec("csdfgen").origin)
|
14
|
+
|
15
|
+
libsdfgen.sdfgen_create.argtypes = [c_uint32, c_uint64]
|
16
|
+
libsdfgen.sdfgen_create.restype = c_void_p
|
17
|
+
|
18
|
+
libsdfgen.sdfgen_destroy.restype = None
|
19
|
+
libsdfgen.sdfgen_destroy.argtypes = [c_void_p]
|
20
|
+
|
21
|
+
libsdfgen.sdfgen_dtb_parse_from_bytes.restype = c_void_p
|
22
|
+
libsdfgen.sdfgen_dtb_parse_from_bytes.argtypes = [c_char_p, c_uint32]
|
23
|
+
|
24
|
+
libsdfgen.sdfgen_dtb_destroy.restype = None
|
25
|
+
libsdfgen.sdfgen_dtb_destroy.argtypes = [c_void_p]
|
26
|
+
|
27
|
+
libsdfgen.sdfgen_dtb_node.restype = c_void_p
|
28
|
+
libsdfgen.sdfgen_dtb_node.argtypes = [c_void_p, c_char_p]
|
29
|
+
|
30
|
+
libsdfgen.sdfgen_add_pd.restype = None
|
31
|
+
libsdfgen.sdfgen_add_pd.argtypes = [c_void_p, c_void_p]
|
32
|
+
libsdfgen.sdfgen_add_mr.restype = None
|
33
|
+
libsdfgen.sdfgen_add_mr.argtypes = [c_void_p, c_void_p]
|
34
|
+
libsdfgen.sdfgen_add_channel.restype = None
|
35
|
+
libsdfgen.sdfgen_add_channel.argtypes = [c_void_p, c_void_p]
|
36
|
+
|
37
|
+
libsdfgen.sdfgen_pd_set_priority.restype = None
|
38
|
+
libsdfgen.sdfgen_pd_set_priority.argtypes = [c_void_p, c_uint8]
|
39
|
+
libsdfgen.sdfgen_pd_set_budget.restype = None
|
40
|
+
libsdfgen.sdfgen_pd_set_budget.argtypes = [c_void_p, c_uint32]
|
41
|
+
libsdfgen.sdfgen_pd_set_period.restype = None
|
42
|
+
libsdfgen.sdfgen_pd_set_period.argtypes = [c_void_p, c_uint32]
|
43
|
+
libsdfgen.sdfgen_pd_set_stack_size.restype = None
|
44
|
+
libsdfgen.sdfgen_pd_set_stack_size.argtypes = [c_void_p, c_uint32]
|
45
|
+
|
46
|
+
libsdfgen.sdfgen_to_xml.restype = c_char_p
|
47
|
+
libsdfgen.sdfgen_to_xml.argtypes = [c_void_p]
|
48
|
+
|
49
|
+
libsdfgen.sdfgen_channel_create.restype = c_void_p
|
50
|
+
libsdfgen.sdfgen_channel_create.argtypes = [c_void_p, c_void_p]
|
51
|
+
libsdfgen.sdfgen_channel_destroy.restype = None
|
52
|
+
libsdfgen.sdfgen_channel_destroy.argtypes = [c_void_p]
|
53
|
+
libsdfgen.sdfgen_channel_get_pd_a_id.restype = c_uint8
|
54
|
+
libsdfgen.sdfgen_channel_get_pd_a_id.argtypes = [c_void_p]
|
55
|
+
libsdfgen.sdfgen_channel_get_pd_b_id.restype = c_uint8
|
56
|
+
libsdfgen.sdfgen_channel_get_pd_b_id.argtypes = [c_void_p]
|
57
|
+
|
58
|
+
libsdfgen.sdfgen_map_create.restype = c_void_p
|
59
|
+
libsdfgen.sdfgen_map_create.argtypes = [c_void_p, c_uint64, MapPermsType, c_bool]
|
60
|
+
libsdfgen.sdfgen_map_destroy.restype = None
|
61
|
+
libsdfgen.sdfgen_map_destroy.argtypes = [c_void_p]
|
62
|
+
|
63
|
+
libsdfgen.sdfgen_mr_create.restype = c_void_p
|
64
|
+
libsdfgen.sdfgen_mr_create.argtypes = [c_char_p, c_uint64]
|
65
|
+
libsdfgen.sdfgen_mr_create_physical.restype = c_void_p
|
66
|
+
libsdfgen.sdfgen_mr_create_physical.argtypes = [c_char_p, c_uint64, c_uint64]
|
67
|
+
libsdfgen.sdfgen_mr_destroy.restype = None
|
68
|
+
libsdfgen.sdfgen_mr_destroy.argtypes = [c_void_p]
|
69
|
+
|
70
|
+
libsdfgen.sdfgen_vm_create.restype = c_void_p
|
71
|
+
libsdfgen.sdfgen_vm_create.argtypes = [c_char_p, POINTER(c_void_p), c_uint32]
|
72
|
+
libsdfgen.sdfgen_vm_destroy.restype = None
|
73
|
+
libsdfgen.sdfgen_vm_destroy.argtypes = [c_void_p]
|
74
|
+
|
75
|
+
libsdfgen.sdfgen_vm_add_map.restype = None
|
76
|
+
libsdfgen.sdfgen_vm_add_map.argtypes = [c_void_p, c_void_p]
|
77
|
+
|
78
|
+
libsdfgen.sdfgen_vm_vcpu_create.restype = c_void_p
|
79
|
+
libsdfgen.sdfgen_vm_vcpu_create.argtypes = [c_uint8, c_uint16]
|
80
|
+
libsdfgen.sdfgen_vm_vcpu_destroy.restype = None
|
81
|
+
libsdfgen.sdfgen_vm_vcpu_destroy.argtypes = [c_void_p]
|
82
|
+
|
83
|
+
libsdfgen.sdfgen_pd_create.restype = c_void_p
|
84
|
+
libsdfgen.sdfgen_pd_create.argtypes = [c_char_p, c_char_p]
|
85
|
+
libsdfgen.sdfgen_pd_destroy.restype = None
|
86
|
+
libsdfgen.sdfgen_pd_destroy.argtypes = [c_void_p]
|
87
|
+
|
88
|
+
libsdfgen.sdfgen_pd_add_child.restype = c_uint8
|
89
|
+
libsdfgen.sdfgen_pd_add_child.argtypes = [c_void_p, c_void_p, POINTER(c_uint8)]
|
90
|
+
libsdfgen.sdfgen_pd_add_map.restype = None
|
91
|
+
libsdfgen.sdfgen_pd_add_map.argtypes = [c_void_p, c_void_p]
|
92
|
+
|
93
|
+
libsdfgen.sdfgen_sddf_timer.restype = c_void_p
|
94
|
+
libsdfgen.sdfgen_sddf_timer.argtypes = [c_void_p, c_void_p, c_void_p]
|
95
|
+
libsdfgen.sdfgen_sddf_timer_destroy.restype = None
|
96
|
+
libsdfgen.sdfgen_sddf_timer_destroy.argtypes = [c_void_p]
|
97
|
+
|
98
|
+
libsdfgen.sdfgen_sddf_timer_add_client.restype = None
|
99
|
+
libsdfgen.sdfgen_sddf_timer_add_client.argtypes = [c_void_p, c_void_p]
|
100
|
+
|
101
|
+
libsdfgen.sdfgen_sddf_timer_connect.restype = c_bool
|
102
|
+
libsdfgen.sdfgen_sddf_timer_connect.argtypes = [c_void_p]
|
103
|
+
libsdfgen.sdfgen_sddf_timer_serialise_config.restype = c_bool
|
104
|
+
libsdfgen.sdfgen_sddf_timer_serialise_config.argtypes = [c_void_p, c_char_p]
|
105
|
+
|
106
|
+
libsdfgen.sdfgen_sddf_i2c.restype = c_void_p
|
107
|
+
libsdfgen.sdfgen_sddf_i2c.argtypes = [c_void_p, c_void_p, c_void_p, c_void_p]
|
108
|
+
libsdfgen.sdfgen_sddf_i2c_destroy.restype = None
|
109
|
+
libsdfgen.sdfgen_sddf_i2c_destroy.argtypes = [c_void_p]
|
110
|
+
|
111
|
+
libsdfgen.sdfgen_sddf_i2c_add_client.restype = None
|
112
|
+
libsdfgen.sdfgen_sddf_i2c_add_client.argtypes = [c_void_p, c_void_p]
|
113
|
+
|
114
|
+
libsdfgen.sdfgen_sddf_i2c_connect.restype = c_bool
|
115
|
+
libsdfgen.sdfgen_sddf_i2c_connect.argtypes = [c_void_p]
|
116
|
+
libsdfgen.sdfgen_sddf_i2c_serialise_config.restype = c_bool
|
117
|
+
libsdfgen.sdfgen_sddf_i2c_serialise_config.argtypes = [c_void_p, c_char_p]
|
118
|
+
|
119
|
+
libsdfgen.sdfgen_sddf_block.restype = c_void_p
|
120
|
+
libsdfgen.sdfgen_sddf_block.argtypes = [c_void_p, c_void_p, c_void_p, c_void_p]
|
121
|
+
libsdfgen.sdfgen_sddf_block_destroy.restype = None
|
122
|
+
libsdfgen.sdfgen_sddf_block_destroy.argtypes = [c_void_p]
|
123
|
+
|
124
|
+
libsdfgen.sdfgen_sddf_block_add_client.restype = None
|
125
|
+
libsdfgen.sdfgen_sddf_block_add_client.argtypes = [c_void_p, c_void_p, c_uint32]
|
126
|
+
|
127
|
+
libsdfgen.sdfgen_sddf_block_connect.restype = c_bool
|
128
|
+
libsdfgen.sdfgen_sddf_block_connect.argtypes = [c_void_p]
|
129
|
+
|
130
|
+
libsdfgen.sdfgen_sddf_block_serialise_config.restype = c_bool
|
131
|
+
libsdfgen.sdfgen_sddf_block_serialise_config.argtypes = [c_void_p, c_char_p]
|
132
|
+
|
133
|
+
libsdfgen.sdfgen_sddf_serial.restype = c_void_p
|
134
|
+
libsdfgen.sdfgen_sddf_serial.argtypes = [c_void_p, c_void_p, c_void_p, c_void_p, c_void_p]
|
135
|
+
libsdfgen.sdfgen_sddf_serial_destroy.restype = None
|
136
|
+
libsdfgen.sdfgen_sddf_serial_destroy.argtypes = [c_void_p]
|
137
|
+
|
138
|
+
libsdfgen.sdfgen_sddf_serial_add_client.restype = None
|
139
|
+
libsdfgen.sdfgen_sddf_serial_add_client.argtypes = [c_void_p, c_void_p]
|
140
|
+
|
141
|
+
libsdfgen.sdfgen_sddf_serial_connect.restype = c_bool
|
142
|
+
libsdfgen.sdfgen_sddf_serial_connect.argtypes = [c_void_p]
|
143
|
+
|
144
|
+
libsdfgen.sdfgen_sddf_serial_serialise_config.restype = c_bool
|
145
|
+
libsdfgen.sdfgen_sddf_serial_serialise_config.argtypes = [c_void_p, c_char_p]
|
146
|
+
|
147
|
+
libsdfgen.sdfgen_sddf_net.restype = c_void_p
|
148
|
+
libsdfgen.sdfgen_sddf_net.argtypes = [c_void_p, c_void_p, c_void_p, c_void_p, c_void_p]
|
149
|
+
libsdfgen.sdfgen_sddf_net_destroy.restype = None
|
150
|
+
libsdfgen.sdfgen_sddf_net_destroy.argtypes = [c_void_p]
|
151
|
+
|
152
|
+
libsdfgen.sdfgen_sddf_net_add_client_with_copier.restype = c_bool
|
153
|
+
libsdfgen.sdfgen_sddf_net_add_client_with_copier.argtypes = [
|
154
|
+
c_void_p,
|
155
|
+
c_void_p,
|
156
|
+
c_void_p,
|
157
|
+
c_char_p
|
158
|
+
]
|
159
|
+
|
160
|
+
libsdfgen.sdfgen_sddf_net_connect.restype = c_bool
|
161
|
+
libsdfgen.sdfgen_sddf_net_connect.argtypes = [c_void_p]
|
162
|
+
|
163
|
+
libsdfgen.sdfgen_sddf_net_serialise_config.restype = c_bool
|
164
|
+
libsdfgen.sdfgen_sddf_net_serialise_config.argtypes = [c_void_p, c_char_p]
|
165
|
+
|
166
|
+
libsdfgen.sdfgen_lionsos_fs_fat.restype = None
|
167
|
+
libsdfgen.sdfgen_lionsos_fs_fat.argtypes = [c_void_p, c_void_p, c_void_p]
|
168
|
+
libsdfgen.sdfgen_lionsos_fs_fat_connect.restype = c_bool
|
169
|
+
libsdfgen.sdfgen_lionsos_fs_fat_connect.argtypes = [c_void_p]
|
170
|
+
libsdfgen.sdfgen_lionsos_fs_nfs.restype = None
|
171
|
+
libsdfgen.sdfgen_lionsos_fs_nfs.argtypes = [c_void_p, c_void_p, c_void_p, c_void_p, c_void_p]
|
172
|
+
libsdfgen.sdfgen_lionsos_fs_nfs_connect.restype = c_bool
|
173
|
+
libsdfgen.sdfgen_lionsos_fs_nfs_connect.argtypes = [c_void_p]
|
174
|
+
|
175
|
+
|
176
|
+
class DeviceTree:
|
177
|
+
"""
|
178
|
+
This class exists to allow other layers to be generic to boards or architectures
|
179
|
+
by letting the user talk about hardware via the Device Tree.
|
180
|
+
"""
|
181
|
+
_obj: c_void_p
|
182
|
+
_bytes: bytes
|
183
|
+
|
184
|
+
def __init__(self, data: bytes):
|
185
|
+
"""
|
186
|
+
Parse a Device Tree Blob (.dtb) and use it to get nodes
|
187
|
+
for generating sDDF device classes or other components.
|
188
|
+
"""
|
189
|
+
# Data is stored explicitly so it is not freed in GC.
|
190
|
+
# The DTB parser assumes the memory does not go away.
|
191
|
+
self._bytes = data
|
192
|
+
self._obj = libsdfgen.sdfgen_dtb_parse_from_bytes(c_char_p(data), len(data))
|
193
|
+
assert self._obj is not None
|
194
|
+
|
195
|
+
def __del__(self):
|
196
|
+
libsdfgen.sdfgen_dtb_destroy(self._obj)
|
197
|
+
|
198
|
+
class Node:
|
199
|
+
# TODO: does having a node increase the ref count for the
|
200
|
+
# device tree
|
201
|
+
def __init__(self, device_tree: DeviceTree, node: str):
|
202
|
+
c_node = c_char_p(node.encode("utf-8"))
|
203
|
+
self._obj = libsdfgen.sdfgen_dtb_node(device_tree._obj, c_node)
|
204
|
+
|
205
|
+
if self._obj is None:
|
206
|
+
raise Exception(f"could not find DTB node '{node}'")
|
207
|
+
|
208
|
+
def node(self, name: str) -> DeviceTree.Node:
|
209
|
+
"""
|
210
|
+
Given a parsed DeviceTree, find the specific node based on the node names.
|
211
|
+
Child nodes can be referenced by separating the parent and child node name
|
212
|
+
by '/'.
|
213
|
+
|
214
|
+
Example:
|
215
|
+
|
216
|
+
.. code-block:: python
|
217
|
+
|
218
|
+
dtb = DeviceTree(dtb_bytes)
|
219
|
+
dtb.node("soc/timer@13050000")
|
220
|
+
|
221
|
+
would be used to access the timer device on a Device Tree that looked like:
|
222
|
+
|
223
|
+
.. code-block::
|
224
|
+
|
225
|
+
soc {
|
226
|
+
timer@13050000 {
|
227
|
+
...
|
228
|
+
};
|
229
|
+
};
|
230
|
+
"""
|
231
|
+
return DeviceTree.Node(self, name)
|
232
|
+
|
233
|
+
|
234
|
+
class SystemDescription:
|
235
|
+
"""
|
236
|
+
Class for describing a Microkit system. Manages all Microkit resources such as
|
237
|
+
Protection Domains, Memory Regions, Channels, etc.
|
238
|
+
"""
|
239
|
+
|
240
|
+
_obj: c_void_p
|
241
|
+
# We need to hold references to the PDs in case they get GC'd.
|
242
|
+
# TODO: is this really necessary?
|
243
|
+
_pds: List[ProtectionDomain]
|
244
|
+
|
245
|
+
class Arch(IntEnum):
|
246
|
+
"""Target architecture. Used to resolve architecture specific features or attributes."""
|
247
|
+
# Important that this aligns with sdfgen_arch_t in the C bindings.
|
248
|
+
AARCH32 = 0,
|
249
|
+
AARCH64 = 1,
|
250
|
+
RISCV32 = 2,
|
251
|
+
RISCV64 = 3,
|
252
|
+
X86 = 4,
|
253
|
+
X86_64 = 5,
|
254
|
+
|
255
|
+
class ProtectionDomain:
|
256
|
+
name: str
|
257
|
+
_obj: c_void_p
|
258
|
+
# We need to hold references to the PDs in case they get GC'd.
|
259
|
+
_child_pds: List[SystemDescription.ProtectionDomain]
|
260
|
+
|
261
|
+
def __init__(
|
262
|
+
self,
|
263
|
+
name: str,
|
264
|
+
program_image: str,
|
265
|
+
priority: Optional[int] = None,
|
266
|
+
budget: Optional[int] = None,
|
267
|
+
period: Optional[int] = None,
|
268
|
+
stack_size: Optional[int] = None
|
269
|
+
) -> None:
|
270
|
+
# TODO: don't do this, users might expect to be able to mutate name which
|
271
|
+
# is not the case
|
272
|
+
self.name = name
|
273
|
+
c_name = c_char_p(name.encode("utf-8"))
|
274
|
+
c_program_image = c_char_p(program_image.encode("utf-8"))
|
275
|
+
self._obj = libsdfgen.sdfgen_pd_create(c_name, c_program_image)
|
276
|
+
self._child_pds = []
|
277
|
+
if priority is not None:
|
278
|
+
libsdfgen.sdfgen_pd_set_priority(self._obj, priority)
|
279
|
+
if budget is not None:
|
280
|
+
libsdfgen.sdfgen_pd_set_budget(self._obj, budget)
|
281
|
+
if period is not None:
|
282
|
+
libsdfgen.sdfgen_pd_set_period(self._obj, period)
|
283
|
+
if stack_size is not None:
|
284
|
+
libsdfgen.sdfgen_pd_set_stack_size(self._obj, stack_size)
|
285
|
+
|
286
|
+
def add_child_pd(self, child_pd: SystemDescription.ProtectionDomain, child_id=None) -> int:
|
287
|
+
"""
|
288
|
+
Returns allocated ID for the child.
|
289
|
+
"""
|
290
|
+
c_child_id = byref(c_uint8(child_id)) if child_id else None
|
291
|
+
|
292
|
+
returned_id = libsdfgen.sdfgen_pd_add_child(self._obj, child_pd._obj, c_child_id)
|
293
|
+
if returned_id is None:
|
294
|
+
raise Exception("Could not allocate child PD ID")
|
295
|
+
|
296
|
+
self._child_pds.append(child_pd)
|
297
|
+
|
298
|
+
return returned_id
|
299
|
+
|
300
|
+
def add_map(self, map: SystemDescription.Map):
|
301
|
+
libsdfgen.sdfgen_pd_add_map(self._obj, map._obj)
|
302
|
+
|
303
|
+
def set_virtual_machine(self, vm: SystemDescription.VirtualMachine):
|
304
|
+
ret = libsdfgen.sdfgen_pd_set_virtual_machine(self._obj, vm._obj)
|
305
|
+
if not ret:
|
306
|
+
# TODO: improve error message
|
307
|
+
raise Exception("ProtectionDomain already has VirtualMachine")
|
308
|
+
|
309
|
+
def __del__(self):
|
310
|
+
libsdfgen.sdfgen_pd_destroy(self._obj)
|
311
|
+
|
312
|
+
class VirtualMachine:
|
313
|
+
_obj: c_void_p
|
314
|
+
|
315
|
+
class VirtualCpu:
|
316
|
+
def __init__(self, *, id: int, cpu: Optional[int] = 0):
|
317
|
+
# TODO: error checking
|
318
|
+
self._obj = libsdfgen.sdfgen_vm_vcpu_create(id, cpu)
|
319
|
+
|
320
|
+
def __init__(self, name: str, vcpus: List[VirtualCpu]):
|
321
|
+
vcpus_tuple: Tuple[c_void_p] = tuple([vcpu._obj for vcpu in vcpus])
|
322
|
+
c_vcpus = (c_void_p * len(vcpus))(vcpus_tuple)
|
323
|
+
self._obj = libsdfgen.sdfgen_vm_create(name, cast(c_vcpus, POINTER(c_void_p)))
|
324
|
+
|
325
|
+
def add_map(self, map: SystemDescription.Map):
|
326
|
+
libsdfgen.sdfgen_vm_add_map(self._obj, map._obj)
|
327
|
+
|
328
|
+
class Map:
|
329
|
+
_obj: c_void_p
|
330
|
+
|
331
|
+
class Perms:
|
332
|
+
def __init__(self, *, r: bool = False, w: bool = False, x: bool = False):
|
333
|
+
self.read = r
|
334
|
+
self.write = w
|
335
|
+
self.execute = x
|
336
|
+
|
337
|
+
def _to_c_bindings(self) -> int:
|
338
|
+
c_perms = 0
|
339
|
+
if self.read:
|
340
|
+
c_perms |= 0b001
|
341
|
+
if self.write:
|
342
|
+
c_perms |= 0b010
|
343
|
+
if self.execute:
|
344
|
+
c_perms |= 0b100
|
345
|
+
|
346
|
+
return c_perms
|
347
|
+
|
348
|
+
def __init__(
|
349
|
+
self,
|
350
|
+
mr: SystemDescription.MemoryRegion,
|
351
|
+
vaddr: int,
|
352
|
+
perms: Perms,
|
353
|
+
*,
|
354
|
+
cached: bool = True,
|
355
|
+
) -> None:
|
356
|
+
self._obj = libsdfgen.sdfgen_map_create(mr._obj, vaddr, perms._to_c_bindings(), cached)
|
357
|
+
|
358
|
+
class MemoryRegion:
|
359
|
+
_obj: c_void_p
|
360
|
+
|
361
|
+
# TODO: handle more options
|
362
|
+
def __init__(
|
363
|
+
self,
|
364
|
+
name: str,
|
365
|
+
size: int,
|
366
|
+
*,
|
367
|
+
paddr: Optional[int] = None
|
368
|
+
) -> None:
|
369
|
+
c_name = c_char_p(name.encode("utf-8"))
|
370
|
+
if paddr:
|
371
|
+
self._obj = libsdfgen.sdfgen_mr_create_physical(c_name, size, paddr)
|
372
|
+
else:
|
373
|
+
self._obj = libsdfgen.sdfgen_mr_create(c_name, size)
|
374
|
+
|
375
|
+
def __del__(self):
|
376
|
+
libsdfgen.sdfgen_mr_destroy(self._obj)
|
377
|
+
|
378
|
+
class Channel:
|
379
|
+
_obj: c_void_p
|
380
|
+
|
381
|
+
# TODO: handle options
|
382
|
+
def __init__(
|
383
|
+
self,
|
384
|
+
a: SystemDescription.ProtectionDomain,
|
385
|
+
b: SystemDescription.ProtectionDomain,
|
386
|
+
*,
|
387
|
+
pp_a=False,
|
388
|
+
pp_b=False,
|
389
|
+
notify_a=True,
|
390
|
+
notify_b=True
|
391
|
+
) -> None:
|
392
|
+
self._obj = libsdfgen.sdfgen_channel_create(a._obj, b._obj)
|
393
|
+
|
394
|
+
@property
|
395
|
+
def pd_a_id(self) -> int:
|
396
|
+
return libsdfgen.sdfgen_channel_get_pd_a_id(self._obj)
|
397
|
+
|
398
|
+
@property
|
399
|
+
def pd_b_id(self) -> int:
|
400
|
+
return libsdfgen.sdfgen_channel_get_pd_b_id(self._obj)
|
401
|
+
|
402
|
+
def __del__(self):
|
403
|
+
libsdfgen.sdfgen_channel_destroy(self._obj)
|
404
|
+
|
405
|
+
def __init__(self, arch: Arch, paddr_top: int) -> None:
|
406
|
+
"""
|
407
|
+
Create a System Description
|
408
|
+
"""
|
409
|
+
self._obj = libsdfgen.sdfgen_create(arch.value, paddr_top)
|
410
|
+
self._pds = []
|
411
|
+
|
412
|
+
def __del__(self):
|
413
|
+
libsdfgen.sdfgen_destroy(self._obj)
|
414
|
+
|
415
|
+
def add_pd(self, pd: ProtectionDomain):
|
416
|
+
self._pds.append(pd)
|
417
|
+
libsdfgen.sdfgen_add_pd(self._obj, pd._obj)
|
418
|
+
|
419
|
+
def add_mr(self, mr: MemoryRegion):
|
420
|
+
libsdfgen.sdfgen_add_mr(self._obj, mr._obj)
|
421
|
+
|
422
|
+
def add_channel(self, ch: Channel):
|
423
|
+
libsdfgen.sdfgen_add_channel(self._obj, ch._obj)
|
424
|
+
|
425
|
+
def xml(self) -> str:
|
426
|
+
"""
|
427
|
+
Generate the XML view of the System Description Format for consumption by the Microkit.
|
428
|
+
"""
|
429
|
+
return libsdfgen.sdfgen_to_xml(self._obj).decode("utf-8")
|
430
|
+
|
431
|
+
|
432
|
+
class Sddf:
|
433
|
+
"""
|
434
|
+
Class for creating I/O systems based on the seL4 Device Driver Framework (sDDF).
|
435
|
+
|
436
|
+
There is a Python class for each device class (e.g Block, Network). They all follow
|
437
|
+
the pattern of being initialised, then having clients added, and then being connected
|
438
|
+
before the final SDF is generated.
|
439
|
+
"""
|
440
|
+
def __init__(self, path: str):
|
441
|
+
"""
|
442
|
+
:param path: str to the root of the sDDF source code.
|
443
|
+
"""
|
444
|
+
ret = libsdfgen.sdfgen_sddf_init(c_char_p(path.encode("utf-8")))
|
445
|
+
if not ret:
|
446
|
+
# TODO: report more information
|
447
|
+
raise Exception("sDDF failed to initialise")
|
448
|
+
|
449
|
+
def __del__(self):
|
450
|
+
# TODO
|
451
|
+
pass
|
452
|
+
|
453
|
+
class Serial:
|
454
|
+
_obj: c_void_p
|
455
|
+
|
456
|
+
def __init__(
|
457
|
+
self,
|
458
|
+
sdf: SystemDescription,
|
459
|
+
device: Optional[DeviceTree.Node],
|
460
|
+
driver: SystemDescription.ProtectionDomain,
|
461
|
+
virt_tx: SystemDescription.ProtectionDomain,
|
462
|
+
*,
|
463
|
+
virt_rx: Optional[SystemDescription.ProtectionDomain] = None
|
464
|
+
) -> None:
|
465
|
+
if device is None:
|
466
|
+
device_obj = None
|
467
|
+
else:
|
468
|
+
device_obj = device._obj
|
469
|
+
|
470
|
+
if virt_rx is None:
|
471
|
+
virt_rx_obj = None
|
472
|
+
else:
|
473
|
+
virt_rx_obj = virt_rx._obj
|
474
|
+
|
475
|
+
self._obj = libsdfgen.sdfgen_sddf_serial(
|
476
|
+
sdf._obj, device_obj, driver._obj, virt_tx._obj, virt_rx_obj
|
477
|
+
)
|
478
|
+
|
479
|
+
def add_client(self, client: SystemDescription.ProtectionDomain):
|
480
|
+
"""Add a new client connection to the serial system."""
|
481
|
+
libsdfgen.sdfgen_sddf_serial_add_client(self._obj, client._obj)
|
482
|
+
|
483
|
+
def connect(self) -> bool:
|
484
|
+
"""
|
485
|
+
Construct and all resources to the associated SystemDescription,
|
486
|
+
returns whether successful.
|
487
|
+
|
488
|
+
Must have all clients and options set before calling.
|
489
|
+
|
490
|
+
Cannot be called more than once.
|
491
|
+
"""
|
492
|
+
return libsdfgen.sdfgen_sddf_serial_connect(self._obj)
|
493
|
+
|
494
|
+
def serialise_config(self, output_dir: str) -> bool:
|
495
|
+
c_output_dir = c_char_p(output_dir.encode("utf-8"))
|
496
|
+
return libsdfgen.sdfgen_sddf_serial_serialise_config(self._obj, c_output_dir)
|
497
|
+
|
498
|
+
def __del__(self):
|
499
|
+
libsdfgen.sdfgen_sddf_serial_destroy(self._obj)
|
500
|
+
|
501
|
+
class I2c:
|
502
|
+
_obj: c_void_p
|
503
|
+
|
504
|
+
def __init__(
|
505
|
+
self,
|
506
|
+
sdf: SystemDescription,
|
507
|
+
device: Optional[DeviceTree.Node],
|
508
|
+
driver: SystemDescription.ProtectionDomain,
|
509
|
+
virt: SystemDescription.ProtectionDomain
|
510
|
+
) -> None:
|
511
|
+
if device is None:
|
512
|
+
device_obj = None
|
513
|
+
else:
|
514
|
+
device_obj = device._obj
|
515
|
+
|
516
|
+
self._obj = libsdfgen.sdfgen_sddf_i2c(sdf._obj, device_obj, driver._obj, virt._obj)
|
517
|
+
|
518
|
+
def add_client(self, client: SystemDescription.ProtectionDomain):
|
519
|
+
libsdfgen.sdfgen_sddf_i2c_add_client(self._obj, client._obj)
|
520
|
+
|
521
|
+
def connect(self) -> bool:
|
522
|
+
return libsdfgen.sdfgen_sddf_i2c_connect(self._obj)
|
523
|
+
|
524
|
+
def serialise_config(self, output_dir: str) -> bool:
|
525
|
+
c_output_dir = c_char_p(output_dir.encode("utf-8"))
|
526
|
+
return libsdfgen.sdfgen_sddf_i2c_serialise_config(self._obj, c_output_dir)
|
527
|
+
|
528
|
+
def __del__(self):
|
529
|
+
libsdfgen.sdfgen_sddf_i2c_destroy(self._obj)
|
530
|
+
|
531
|
+
class Block:
|
532
|
+
_obj: c_void_p
|
533
|
+
|
534
|
+
def __init__(
|
535
|
+
self,
|
536
|
+
sdf: SystemDescription,
|
537
|
+
device: Optional[DeviceTree.Node],
|
538
|
+
driver: SystemDescription.ProtectionDomain,
|
539
|
+
virt: SystemDescription.ProtectionDomain
|
540
|
+
) -> None:
|
541
|
+
if device is None:
|
542
|
+
device_obj = None
|
543
|
+
else:
|
544
|
+
device_obj = device._obj
|
545
|
+
|
546
|
+
self._obj = libsdfgen.sdfgen_sddf_block(sdf._obj, device_obj, driver._obj, virt._obj)
|
547
|
+
|
548
|
+
def add_client(self, client: SystemDescription.ProtectionDomain, *, partition: int):
|
549
|
+
libsdfgen.sdfgen_sddf_block_add_client(self._obj, client._obj, partition)
|
550
|
+
|
551
|
+
def connect(self) -> bool:
|
552
|
+
return libsdfgen.sdfgen_sddf_block_connect(self._obj)
|
553
|
+
|
554
|
+
def serialise_config(self, output_dir: str) -> bool:
|
555
|
+
c_output_dir = c_char_p(output_dir.encode("utf-8"))
|
556
|
+
return libsdfgen.sdfgen_sddf_block_serialise_config(self._obj, c_output_dir)
|
557
|
+
|
558
|
+
def __del__(self):
|
559
|
+
libsdfgen.sdfgen_sddf_block_destroy(self._obj)
|
560
|
+
|
561
|
+
class Network:
|
562
|
+
_obj: c_void_p
|
563
|
+
|
564
|
+
def __init__(
|
565
|
+
self,
|
566
|
+
sdf: SystemDescription,
|
567
|
+
device: Optional[DeviceTree.Node],
|
568
|
+
driver: SystemDescription.ProtectionDomain,
|
569
|
+
virt_tx: SystemDescription.ProtectionDomain,
|
570
|
+
virt_rx: SystemDescription.ProtectionDomain
|
571
|
+
) -> None:
|
572
|
+
if device is None:
|
573
|
+
device_obj = None
|
574
|
+
else:
|
575
|
+
device_obj = device._obj
|
576
|
+
|
577
|
+
self._obj = libsdfgen.sdfgen_sddf_net(
|
578
|
+
sdf._obj, device_obj, driver._obj, virt_tx._obj, virt_rx._obj
|
579
|
+
)
|
580
|
+
|
581
|
+
def add_client_with_copier(
|
582
|
+
self,
|
583
|
+
client: SystemDescription.ProtectionDomain,
|
584
|
+
copier: SystemDescription.ProtectionDomain,
|
585
|
+
*,
|
586
|
+
mac_addr: Optional[str] = None
|
587
|
+
) -> None:
|
588
|
+
"""
|
589
|
+
Add a client connected to a copier component for RX traffic.
|
590
|
+
|
591
|
+
:param copier: must be unique to this client, cannot be used with any other client.
|
592
|
+
:param mac_addr: must be unique to the Network system.
|
593
|
+
"""
|
594
|
+
if mac_addr is not None and len(mac_addr) != 17:
|
595
|
+
raise Exception(f"invalid MAC address length for client '{client.name}', {mac_addr}")
|
596
|
+
|
597
|
+
c_mac_addr = c_char_p(0)
|
598
|
+
if mac_addr is not None:
|
599
|
+
c_mac_addr = c_char_p(mac_addr.encode("utf-8"))
|
600
|
+
ret = libsdfgen.sdfgen_sddf_net_add_client_with_copier(
|
601
|
+
self._obj, client._obj, copier._obj, c_mac_addr
|
602
|
+
)
|
603
|
+
if ret == 0:
|
604
|
+
return
|
605
|
+
elif ret == 1:
|
606
|
+
raise Exception(f"duplicate MAC address given '{mac_addr}'")
|
607
|
+
elif ret == 2:
|
608
|
+
raise Exception(f"duplicate client given '{client}'")
|
609
|
+
elif ret == 3:
|
610
|
+
raise Exception(f"duplicate copier given '{copier}'")
|
611
|
+
else:
|
612
|
+
raise Exception("internal error")
|
613
|
+
|
614
|
+
def connect(self) -> bool:
|
615
|
+
return libsdfgen.sdfgen_sddf_net_connect(self._obj)
|
616
|
+
|
617
|
+
def serialise_config(self, output_dir: str) -> bool:
|
618
|
+
c_output_dir = c_char_p(output_dir.encode("utf-8"))
|
619
|
+
return libsdfgen.sdfgen_sddf_net_serialise_config(self._obj, c_output_dir)
|
620
|
+
|
621
|
+
def __del__(self):
|
622
|
+
libsdfgen.sdfgen_sddf_net_destroy(self._obj)
|
623
|
+
|
624
|
+
class Timer:
|
625
|
+
_obj: c_void_p
|
626
|
+
|
627
|
+
def __init__(
|
628
|
+
self,
|
629
|
+
sdf: SystemDescription,
|
630
|
+
device: Optional[DeviceTree.Node],
|
631
|
+
driver: SystemDescription.ProtectionDomain
|
632
|
+
) -> None:
|
633
|
+
if device is None:
|
634
|
+
device_obj = None
|
635
|
+
else:
|
636
|
+
device_obj = device._obj
|
637
|
+
|
638
|
+
self._obj: c_void_p = libsdfgen.sdfgen_sddf_timer(sdf._obj, device_obj, driver._obj)
|
639
|
+
|
640
|
+
def add_client(self, client: SystemDescription.ProtectionDomain):
|
641
|
+
libsdfgen.sdfgen_sddf_timer_add_client(self._obj, client._obj)
|
642
|
+
|
643
|
+
def connect(self) -> bool:
|
644
|
+
return libsdfgen.sdfgen_sddf_timer_connect(self._obj)
|
645
|
+
|
646
|
+
def serialise_config(self, output_dir: str) -> bool:
|
647
|
+
c_output_dir = c_char_p(output_dir.encode("utf-8"))
|
648
|
+
return libsdfgen.sdfgen_sddf_timer_serialise_config(self._obj, c_output_dir)
|
649
|
+
|
650
|
+
def __del__(self):
|
651
|
+
libsdfgen.sdfgen_sddf_timer_destroy(self._obj)
|
652
|
+
|
653
|
+
class LionsOs:
|
654
|
+
class FileSystem:
|
655
|
+
class Fat:
|
656
|
+
_obj: c_void_p
|
657
|
+
|
658
|
+
def __init__(
|
659
|
+
self,
|
660
|
+
sdf: SystemDescription,
|
661
|
+
fs: SystemDescription.ProtectionDomain,
|
662
|
+
client: SystemDescription.ProtectionDomain
|
663
|
+
):
|
664
|
+
self._obj = libsdfgen.sdfgen_lionsos_fs_fat(sdf._obj, fs._obj, client._obj)
|
665
|
+
|
666
|
+
def connect(self) -> bool:
|
667
|
+
return libsdfgen.sdfgen_lionsos_fs_fat_connect(self._obj)
|
668
|
+
|
669
|
+
class Nfs:
|
670
|
+
_obj: c_void_p
|
671
|
+
|
672
|
+
def __init__(
|
673
|
+
self,
|
674
|
+
sdf: SystemDescription,
|
675
|
+
fs: SystemDescription.ProtectionDomain,
|
676
|
+
client: SystemDescription.ProtectionDomain,
|
677
|
+
net: Sddf.Network,
|
678
|
+
net_copier: SystemDescription.ProtectionDomain
|
679
|
+
):
|
680
|
+
self._obj = libsdfgen.sdfgen_lionsos_fs_nfs(sdf._obj, fs._obj, client._obj, net._obj, net_copier._obj)
|
681
|
+
|
682
|
+
def connect(self) -> bool:
|
683
|
+
return libsdfgen.sdfgen_lionsos_fs_fat_connect(self._obj)
|
sdfgen/py.typed
ADDED
File without changes
|
@@ -0,0 +1,160 @@
|
|
1
|
+
Metadata-Version: 2.1
|
2
|
+
Name: sdfgen
|
3
|
+
Version: 0.9.0
|
4
|
+
Summary: Automating the creation of Microkit System Description Files (SDF)
|
5
|
+
Home-page: https://github.com/au-ts/microkit_sdf_gen
|
6
|
+
Description-Content-Type: text/markdown
|
7
|
+
|
8
|
+
# Higher-level tooling for constructing seL4 Microkit systems
|
9
|
+
|
10
|
+
This repository currently holds various programs to help with automating the
|
11
|
+
process of creating seL4 Microkit systems.
|
12
|
+
|
13
|
+
> [!IMPORTANT]
|
14
|
+
> This project is experimental, we are using it internally to get it into a
|
15
|
+
> usable state for the public. For development this work exists in a separate repository,
|
16
|
+
> but that may change once it has matured (e.g by being apart of the official Microkit
|
17
|
+
> repository).
|
18
|
+
|
19
|
+
## Problem
|
20
|
+
|
21
|
+
In order to remain simple, the seL4 Microkit (intentionally) does not provide one-size-fits-all
|
22
|
+
abstractions for creating systems where the information about the design of the system flows into
|
23
|
+
the actual code of the system.
|
24
|
+
|
25
|
+
A concrete example of this might be say some code that needs to know how many clients it needs to
|
26
|
+
serve. This obviously depends on the system designer, and could easily be something that changes
|
27
|
+
for different configurations of the same system. The Microkit SDF offers no way to pass down this
|
28
|
+
kind of information. For the example described, an easy 'solution' would be to pass some kind of
|
29
|
+
compile-time parameter (e.g a #define in C) for the number of clients. However imagine now you
|
30
|
+
have the same system with two configurations, with two clients and one with three, this requires
|
31
|
+
two separate SDF files even though they are very similar systems and the code remains identical
|
32
|
+
expect for the compile-time parameter. This problem ultimately hampers experimentation.
|
33
|
+
|
34
|
+
Another 'problem' with SDF is that is verbose and descriptive. I say 'problem' as the verbosity of it
|
35
|
+
makes it an ideal source of truth for the design of the system and hides minimal information as to the
|
36
|
+
capability distribution and access policy of a system. But the negative of this is that it does not scale
|
37
|
+
well, even small changes to a large SDF file are difficult to make and ensure are correct.
|
38
|
+
|
39
|
+
## Solution(s)
|
40
|
+
|
41
|
+
* Allow for users to easily auto-generate SDF programmatically using a tool called `sdfgen`.
|
42
|
+
* Create a graphical user-interface to visually display and produce/maintain the design of a Microkit system.
|
43
|
+
This graphical user-interface will sort of act as a 'frontend' for the `sdfgen` tool.
|
44
|
+
|
45
|
+
Both of these solutions are very much in a work-in-progress state.
|
46
|
+
|
47
|
+
## Developing
|
48
|
+
|
49
|
+
All the tooling is currently written in [Zig](https://ziglang.org/download/) with bindings
|
50
|
+
for other languages available.
|
51
|
+
|
52
|
+
### Dependencies
|
53
|
+
|
54
|
+
There are two dependencies:
|
55
|
+
|
56
|
+
* Zig (`0.14.0-dev.2079+ba2d00663` or higher)
|
57
|
+
* See https://ziglang.org/download/, until 0.14.0 is released we rely on a master version of Zig.
|
58
|
+
Once 0.14.0 is released (most likely in a couple of months) we can pin to that release.
|
59
|
+
* Device Tree Compiler (dtc)
|
60
|
+
|
61
|
+
### Tests
|
62
|
+
|
63
|
+
To test the Zig and C bindings, you can run:
|
64
|
+
```sh
|
65
|
+
zig build test
|
66
|
+
```
|
67
|
+
|
68
|
+
### Zig bindings
|
69
|
+
|
70
|
+
The source code for the sdfgen tooling is written in Zig, and so we simply expose a module called
|
71
|
+
`sdf` in `build.zig`.
|
72
|
+
|
73
|
+
To build and run an example of the Zig bindings being used run:
|
74
|
+
```sh
|
75
|
+
zig build zig_example -- --example webserver --board qemu_virt_aarch64
|
76
|
+
```
|
77
|
+
|
78
|
+
The source code is in `examples/examples.zig`.
|
79
|
+
|
80
|
+
To see all the options run:
|
81
|
+
```sh
|
82
|
+
zig build zig_example -- --help
|
83
|
+
```
|
84
|
+
|
85
|
+
### C bindings
|
86
|
+
|
87
|
+
```sh
|
88
|
+
zig build c
|
89
|
+
```
|
90
|
+
|
91
|
+
The library will be at `zig-out/lib/csdfgen`.
|
92
|
+
|
93
|
+
The source code for the bindings is in `src/c/`.
|
94
|
+
|
95
|
+
To run an example C program that uses the bindings, run:
|
96
|
+
```sh
|
97
|
+
zig build c_example
|
98
|
+
```
|
99
|
+
|
100
|
+
The source code for the example is in `examples/examples.c`.
|
101
|
+
|
102
|
+
### Python bindings
|
103
|
+
|
104
|
+
The Python package is supported for versions 3.9 to 3.13.
|
105
|
+
Linux (x86-64) and macOS (Intel/Apple Silicon) are supported. Windows is *not* supported.
|
106
|
+
|
107
|
+
The Python bindings are all in Python itself, and do direct FFI to the C bindings via
|
108
|
+
[ctypes](https://docs.python.org/3/library/ctypes.html).
|
109
|
+
|
110
|
+
#### Building the package
|
111
|
+
|
112
|
+
To build a usable Python package run the following:
|
113
|
+
```sh
|
114
|
+
python3 -m venv venv
|
115
|
+
./venv/bin/python3 -m pip install .
|
116
|
+
```
|
117
|
+
|
118
|
+
Now you should be able to import and use the bindings:
|
119
|
+
```sh
|
120
|
+
./venv/bin/python3
|
121
|
+
>>> import sdfgen
|
122
|
+
>>> help(sdfgen)
|
123
|
+
```
|
124
|
+
|
125
|
+
#### Publishing Python packages
|
126
|
+
|
127
|
+
Binary releases of the Python package (known as 'wheels' in the Python universe) are published to
|
128
|
+
[PyPI](https://pypi.org/project/microkit_sdfgen/).
|
129
|
+
|
130
|
+
Unlike most Python packages, ours is a bit more complicated because:
|
131
|
+
1. We depend on an external C library.
|
132
|
+
2. We are building that external C library via Zig and not a regular C compiler.
|
133
|
+
|
134
|
+
These have some consequences, mainly that the regular `setup.py` has a custom
|
135
|
+
`build_extension` function that calls out to Zig. It calls out to `zig build c`
|
136
|
+
using the correct output library name/path that the Python packaging
|
137
|
+
wants to use.
|
138
|
+
|
139
|
+
This means that you *must* use Zig to build the Python package from source.
|
140
|
+
|
141
|
+
##### Supported versions
|
142
|
+
|
143
|
+
We try to support all versions of Python people would want to use, within reason.
|
144
|
+
|
145
|
+
Right now, that means CPython 3.9 is the lowest version available. If there is a
|
146
|
+
missing Python package target (OS, architecture, or version), please open an issue.
|
147
|
+
|
148
|
+
##### CI
|
149
|
+
|
150
|
+
For the CI, we use [cibuildwheel](https://cibuildwheel.pypa.io/) to automate the process of building
|
151
|
+
for various architectures/operating systems.
|
152
|
+
|
153
|
+
The CI runs on every commit and produces GitHub action artefacts that contain all the wheels (`*.whl`).
|
154
|
+
|
155
|
+
For any new tags to the repository, the CI also uploads a new version of the package to PyPI automatically.
|
156
|
+
Note that each tag should have a new version in the `VERSION` file at the root of the source. See
|
157
|
+
[scripts/README.md](scripts/README.md) for doing this.
|
158
|
+
|
159
|
+
The publishing job works by authenticating the repository's GitHub workflow with the package on PyPI, there
|
160
|
+
are no tokens etc stored on GitHub.
|
@@ -0,0 +1,8 @@
|
|
1
|
+
csdfgen.cpython-312-x86_64-linux-musl.so,sha256=Vva1vY4-RvPsr9wNA9AyzUKZmynnDo-0B4kLJ1yemYQ,3847008
|
2
|
+
sdfgen/module.py,sha256=0DK9UsggaL7dqP-16bh1q-2LJsU-AOzn-bpdVkQg9-I,24807
|
3
|
+
sdfgen/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
4
|
+
sdfgen/__init__.py,sha256=qFoYMCiM89s1BduC2hWsDRa3kGhvmJcxJsaHMWLhf1g,131
|
5
|
+
sdfgen-0.9.0.dist-info/METADATA,sha256=TvnwfHvf1WYJ0yjYMrhdJc0LXEOAOTz7aJQxSpK-ajM,5913
|
6
|
+
sdfgen-0.9.0.dist-info/RECORD,,
|
7
|
+
sdfgen-0.9.0.dist-info/top_level.txt,sha256=M3gUW9vTMij10peQKgv1Qs0jZkdsk_PG0REFxuv6jNY,15
|
8
|
+
sdfgen-0.9.0.dist-info/WHEEL,sha256=BwYrisTu1yp8WloXcEi-3Rmdx-uar3nqcuXFSFGpP_Q,112
|