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.
