This enables to create Jailhouse configurations without relying on a C
compiler.

Signed-off-by: Andrej Utz <[email protected]>
---
 pyjailhouse/config_parser.py | 124 +++++++++++++++++++++++++++++++++--
 1 file changed, 118 insertions(+), 6 deletions(-)

diff --git a/pyjailhouse/config_parser.py b/pyjailhouse/config_parser.py
index 75e22fad..eaec4fa2 100644
--- a/pyjailhouse/config_parser.py
+++ b/pyjailhouse/config_parser.py
@@ -15,8 +15,9 @@
 # to change the generated C-code.
 
 from __future__ import print_function
-import struct
+import copy
 import io
+import struct
 
 from .extendedenum import ExtendedEnum
 
@@ -39,6 +40,19 @@ class CStruct:
 
         return attrs
 
+    def save(self, stream):
+        values = tuple()
+        for field in self._slots():
+            value = getattr(self, field, 0)
+            values = values + (value,)
+
+        stream.write(self._BIN_FMT.pack(*values))
+
+    @staticmethod
+    def save_array(itr, stream):
+        for obj in itr:
+            obj.save(stream)
+
     @classmethod
     def parse(cls, stream):
         obj = cls.parse_class(cls, stream)
@@ -172,6 +186,10 @@ class Irqchip(CStruct):
     def is_standard(self):
         return self.address == 0xfec00000
 
+    def save(self, stream):
+        super(self.__class__, self).save(stream)
+        stream.write(self._BIN_FMT_PIN_MAP.pack(*self.pin_bitmap))
+
     @classmethod
     def parse(cls, stream):
         self = cls.parse_class(cls, stream)
@@ -207,6 +225,12 @@ class PciDevice(CStruct):
     TYPE_BRIDGE = 2
     TYPE_IVSHMEM = 3
 
+    def save(self, stream):
+        temp = copy.copy(self)
+        temp.bar_mask = self._BIN_FMT_BAR_MASK.pack(*self.bar_mask)
+        temp._caps_num = len(self.caps)
+        return super(self.__class__, temp).save(stream)
+
     @classmethod
     def parse(cls, stream):
         self = cls.parse_class(cls, stream)
@@ -256,6 +280,62 @@ class CellConfig(CStruct):
         self.cpu_reset_address = 0
         self.console = Console()
 
+    def save(self, stream, is_rootcell=False):
+        # Flatten and deduplicate PCI capabilities
+        pci_caps = []
+        for idx,dev in enumerate(self.pci_devices):
+            if not dev.caps:
+                continue
+
+            duplicate = False
+            # look for duplicate capability patterns
+            for dev_prev in self.pci_devices[:idx]:
+                if dev_prev.caps == dev.caps:
+                    dev._caps_start = dev_prev._caps_start
+                    duplicate = True
+                    break
+
+            if not duplicate:
+                dev._caps_start = len(pci_caps)
+                pci_caps += dev.caps
+
+        # Convert CPU set to bit array
+        cpu_bits_cap = self._BIN_FMT_CPU.size * 8
+        cpu_sets = [0]
+        for cpu in self.cpu_set:
+            if cpu >= cpu_bits_cap:
+                cpu_sets += [0]
+            cpu_sets[-1] |= 1 << (cpu % cpu_bits_cap)
+        cpu_sets.reverse() #
+
+        temp = copy.copy(self)
+        temp.name = self.name.encode()
+        temp.cpu_set = int(len(cpu_sets) * self._BIN_FMT_CPU.size)
+        temp.memory_regions = len(self.memory_regions)
+        temp.cache_regions = len(self.cache_regions)
+        temp.irqchips = len(self.irqchips)
+        temp.pio_regions = len(self.pio_regions)
+        temp.pci_devices = len(self.pci_devices)
+        temp.pci_caps = len(pci_caps)
+        temp.stream_ids = len(self.stream_ids)
+
+        if not is_rootcell:
+            stream.write(self._BIN_FMT_HDR.pack(self._BIN_SIGNATURE, \
+                                                _CONFIG_REVISION))
+
+        super(self.__class__, temp).save(stream)
+        self.console.save(stream)
+        for cpu_set in cpu_sets:
+            stream.write(self._BIN_FMT_CPU.pack(cpu_set))
+        self.save_array(self.memory_regions, stream)
+        self.save_array(self.cache_regions, stream)
+        self.save_array(self.irqchips, stream)
+        self.save_array(self.pio_regions, stream)
+        self.save_array(self.pci_devices, stream)
+        self.save_array(pci_caps, stream)
+        for sid in self.stream_ids:
+            stream.write(self._BIN_FMT_STREAM_ID.pack(sid))
+
     @classmethod
     def parse(cls, stream):
         self = cls.parse_class(cls, stream)
@@ -311,6 +391,7 @@ class Iommu(CStruct):
     __slots__ = 'type', 'base', 'size',
     _BIN_FIELD_NUM = len(__slots__)
     _BIN_FMT = struct.Struct('=IQI')
+    _BIN_PAD_SIZE = max(IommuAmd._BIN_FMT.size, IommuPvu._BIN_FMT.size)
 
     # constructed fields
     __slots__ += 'subtype',
@@ -322,6 +403,21 @@ class Iommu(CStruct):
     TYPE_SMMUV3 = 3
     TYPE_PVU = 4
 
+    def __init__(self, subtype = None):
+        self.type = 0
+        self.base = 0
+        self.size = 0
+        self.subtype = subtype
+
+    def save(self, stream):
+        super(self.__class__, self).save(stream)
+        padding = self._BIN_PAD_SIZE
+        if self.subtype:
+            self.subtype.save(stream)
+            padding -= self.subtype._BIN_FMT.size
+
+        stream.write(bytes(padding))
+
     @classmethod
     def parse(cls, stream):
         self = cls.parse_class(cls, stream)
@@ -335,8 +431,7 @@ class Iommu(CStruct):
             self.subtype = sub_cls.parse(stream)
 
         # skip rest of the C union, if needed
-        skip = max(IommuAmd._BIN_FMT.size, IommuPvu._BIN_FMT.size) \
-            - (sub_cls._BIN_FMT.size if sub_cls else 0)
+        skip = cls._BIN_PAD_SIZE - (sub_cls._BIN_FMT.size if sub_cls else 0)
         stream.seek(skip, io.SEEK_CUR)
         return self
 
@@ -360,6 +455,8 @@ class PlattformInfo(CStruct):
                 'pci_is_virtual', 'pci_domain',
     _BIN_FIELD_NUM = len(__slots__)
     _BIN_FMT = struct.Struct('=QBBH')
+    _BIN_PAD_SIZE = max(PlattformInfoArm._BIN_FMT.size, \
+                        PlattformInfoX86._BIN_FMT.size)
 
     # constructed fields
     __slots__ += 'iommus', 'arch_info',
@@ -372,6 +469,13 @@ class PlattformInfo(CStruct):
         self.iommus = []
         self.arch_info = arch_info_cls()
 
+    def save(self, stream):
+        super(self.__class__, self).save(stream)
+        self.save_array(self.iommus, stream)
+        self.arch_info.save(stream)
+        padding = self._BIN_PAD_SIZE - self.arch_info._BIN_FMT.size
+        stream.write(bytes(padding))
+
     @classmethod
     def parse(cls, stream, arch_info_cls=PlattformInfoX86):
         self = cls.parse_class(cls, stream)
@@ -379,9 +483,7 @@ class PlattformInfo(CStruct):
         self.arch_info = arch_info_cls.parse(stream)
 
         # skip rest of the C union, if needed
-        skip = \
-            max(PlattformInfoArm._BIN_FMT.size, 
PlattformInfoX86._BIN_FMT.size)\
-            - arch_info_cls._BIN_FMT.size
+        skip = cls._BIN_PAD_SIZE - arch_info_cls._BIN_FMT.size
         stream.seek(skip, io.SEEK_CUR)
         return self
 
@@ -403,6 +505,16 @@ class SystemConfig(CStruct):
         self.platform_info = PlattformInfo()
         self.root_cell = CellConfig()
 
+    def save(self, stream):
+        hdr_fmt = CellConfig._BIN_FMT_HDR
+        stream.write(hdr_fmt.pack(self._BIN_SIGNATURE, _CONFIG_REVISION))
+        super(self.__class__, self).save(stream)
+        self.hypervisor_memory.save(stream)
+        self.debug_console.save(stream)
+        self.platform_info.save(stream)
+        stream.write(bytes(hdr_fmt.size)) # place dummy cell header
+        self.root_cell.save(stream, is_rootcell=True)
+
     @classmethod
     def parse(cls, stream):
         self = cls.parse_class(cls, stream)
-- 
2.27.0

-- 
You received this message because you are subscribed to the Google Groups 
"Jailhouse" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/jailhouse-dev/20200630064730.7210-2-andrej.utz%40st.oth-regensburg.de.

Reply via email to