sdfgen 0.9.0__cp39-cp39-macosx_13_0_x86_64.whl

Sign up to get free protection for your applications and to get access to all the features.
Binary file
sdfgen/__init__.py ADDED
@@ -0,0 +1,3 @@
1
+ from .module import SystemDescription, Sddf, DeviceTree, LionsOs
2
+
3
+ __all__ = ['SystemDescription', 'Sddf', 'LionsOs', 'DeviceTree']
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,164 @@
1
+ Metadata-Version: 2.2
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
+ Dynamic: description
8
+ Dynamic: description-content-type
9
+ Dynamic: home-page
10
+ Dynamic: summary
11
+
12
+ # Higher-level tooling for constructing seL4 Microkit systems
13
+
14
+ This repository currently holds various programs to help with automating the
15
+ process of creating seL4 Microkit systems.
16
+
17
+ > [!IMPORTANT]
18
+ > This project is experimental, we are using it internally to get it into a
19
+ > usable state for the public. For development this work exists in a separate repository,
20
+ > but that may change once it has matured (e.g by being apart of the official Microkit
21
+ > repository).
22
+
23
+ ## Problem
24
+
25
+ In order to remain simple, the seL4 Microkit (intentionally) does not provide one-size-fits-all
26
+ abstractions for creating systems where the information about the design of the system flows into
27
+ the actual code of the system.
28
+
29
+ A concrete example of this might be say some code that needs to know how many clients it needs to
30
+ serve. This obviously depends on the system designer, and could easily be something that changes
31
+ for different configurations of the same system. The Microkit SDF offers no way to pass down this
32
+ kind of information. For the example described, an easy 'solution' would be to pass some kind of
33
+ compile-time parameter (e.g a #define in C) for the number of clients. However imagine now you
34
+ have the same system with two configurations, with two clients and one with three, this requires
35
+ two separate SDF files even though they are very similar systems and the code remains identical
36
+ expect for the compile-time parameter. This problem ultimately hampers experimentation.
37
+
38
+ Another 'problem' with SDF is that is verbose and descriptive. I say 'problem' as the verbosity of it
39
+ makes it an ideal source of truth for the design of the system and hides minimal information as to the
40
+ capability distribution and access policy of a system. But the negative of this is that it does not scale
41
+ well, even small changes to a large SDF file are difficult to make and ensure are correct.
42
+
43
+ ## Solution(s)
44
+
45
+ * Allow for users to easily auto-generate SDF programmatically using a tool called `sdfgen`.
46
+ * Create a graphical user-interface to visually display and produce/maintain the design of a Microkit system.
47
+ This graphical user-interface will sort of act as a 'frontend' for the `sdfgen` tool.
48
+
49
+ Both of these solutions are very much in a work-in-progress state.
50
+
51
+ ## Developing
52
+
53
+ All the tooling is currently written in [Zig](https://ziglang.org/download/) with bindings
54
+ for other languages available.
55
+
56
+ ### Dependencies
57
+
58
+ There are two dependencies:
59
+
60
+ * Zig (`0.14.0-dev.2079+ba2d00663` or higher)
61
+ * See https://ziglang.org/download/, until 0.14.0 is released we rely on a master version of Zig.
62
+ Once 0.14.0 is released (most likely in a couple of months) we can pin to that release.
63
+ * Device Tree Compiler (dtc)
64
+
65
+ ### Tests
66
+
67
+ To test the Zig and C bindings, you can run:
68
+ ```sh
69
+ zig build test
70
+ ```
71
+
72
+ ### Zig bindings
73
+
74
+ The source code for the sdfgen tooling is written in Zig, and so we simply expose a module called
75
+ `sdf` in `build.zig`.
76
+
77
+ To build and run an example of the Zig bindings being used run:
78
+ ```sh
79
+ zig build zig_example -- --example webserver --board qemu_virt_aarch64
80
+ ```
81
+
82
+ The source code is in `examples/examples.zig`.
83
+
84
+ To see all the options run:
85
+ ```sh
86
+ zig build zig_example -- --help
87
+ ```
88
+
89
+ ### C bindings
90
+
91
+ ```sh
92
+ zig build c
93
+ ```
94
+
95
+ The library will be at `zig-out/lib/csdfgen`.
96
+
97
+ The source code for the bindings is in `src/c/`.
98
+
99
+ To run an example C program that uses the bindings, run:
100
+ ```sh
101
+ zig build c_example
102
+ ```
103
+
104
+ The source code for the example is in `examples/examples.c`.
105
+
106
+ ### Python bindings
107
+
108
+ The Python package is supported for versions 3.9 to 3.13.
109
+ Linux (x86-64) and macOS (Intel/Apple Silicon) are supported. Windows is *not* supported.
110
+
111
+ The Python bindings are all in Python itself, and do direct FFI to the C bindings via
112
+ [ctypes](https://docs.python.org/3/library/ctypes.html).
113
+
114
+ #### Building the package
115
+
116
+ To build a usable Python package run the following:
117
+ ```sh
118
+ python3 -m venv venv
119
+ ./venv/bin/python3 -m pip install .
120
+ ```
121
+
122
+ Now you should be able to import and use the bindings:
123
+ ```sh
124
+ ./venv/bin/python3
125
+ >>> import sdfgen
126
+ >>> help(sdfgen)
127
+ ```
128
+
129
+ #### Publishing Python packages
130
+
131
+ Binary releases of the Python package (known as 'wheels' in the Python universe) are published to
132
+ [PyPI](https://pypi.org/project/microkit_sdfgen/).
133
+
134
+ Unlike most Python packages, ours is a bit more complicated because:
135
+ 1. We depend on an external C library.
136
+ 2. We are building that external C library via Zig and not a regular C compiler.
137
+
138
+ These have some consequences, mainly that the regular `setup.py` has a custom
139
+ `build_extension` function that calls out to Zig. It calls out to `zig build c`
140
+ using the correct output library name/path that the Python packaging
141
+ wants to use.
142
+
143
+ This means that you *must* use Zig to build the Python package from source.
144
+
145
+ ##### Supported versions
146
+
147
+ We try to support all versions of Python people would want to use, within reason.
148
+
149
+ Right now, that means CPython 3.9 is the lowest version available. If there is a
150
+ missing Python package target (OS, architecture, or version), please open an issue.
151
+
152
+ ##### CI
153
+
154
+ For the CI, we use [cibuildwheel](https://cibuildwheel.pypa.io/) to automate the process of building
155
+ for various architectures/operating systems.
156
+
157
+ The CI runs on every commit and produces GitHub action artefacts that contain all the wheels (`*.whl`).
158
+
159
+ For any new tags to the repository, the CI also uploads a new version of the package to PyPI automatically.
160
+ Note that each tag should have a new version in the `VERSION` file at the root of the source. See
161
+ [scripts/README.md](scripts/README.md) for doing this.
162
+
163
+ The publishing job works by authenticating the repository's GitHub workflow with the package on PyPI, there
164
+ are no tokens etc stored on GitHub.
@@ -0,0 +1,8 @@
1
+ csdfgen.cpython-39-darwin.so,sha256=RGPpGJXpMq1f9W__Gm6TQlEA9tibXRovQ5UJI3QMDuk,764311
2
+ sdfgen/__init__.py,sha256=qFoYMCiM89s1BduC2hWsDRa3kGhvmJcxJsaHMWLhf1g,131
3
+ sdfgen/module.py,sha256=0DK9UsggaL7dqP-16bh1q-2LJsU-AOzn-bpdVkQg9-I,24807
4
+ sdfgen/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
+ sdfgen-0.9.0.dist-info/METADATA,sha256=MXxKvhmvKBvvrsgBxyNTSvjdAZubk2fUbNZIMJYWzIY,6004
6
+ sdfgen-0.9.0.dist-info/WHEEL,sha256=wjwK1yLd0er3cZ5dA3bBdCN3rjDJSMBsC9PR3uXt8Cg,108
7
+ sdfgen-0.9.0.dist-info/top_level.txt,sha256=M3gUW9vTMij10peQKgv1Qs0jZkdsk_PG0REFxuv6jNY,15
8
+ sdfgen-0.9.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (75.8.0)
3
+ Root-Is-Purelib: false
4
+ Tag: cp39-cp39-macosx_13_0_x86_64
5
+
@@ -0,0 +1,2 @@
1
+ csdfgen
2
+ sdfgen