From 15d3686501b7e0a1b0021e1e1c88281bde997097 Mon Sep 17 00:00:00 2001 From: Joerg Vehlow Date: Wed, 12 Feb 2025 13:22:52 +0000 Subject: [PATCH 01/17] doc: fix edit url --- book.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/book.toml b/book.toml index dc4b025..8838996 100644 --- a/book.toml +++ b/book.toml @@ -17,9 +17,9 @@ additional-css = ["docs/custom.css"] curly-quotes = true mathjax-support = false copy-fonts = true -git-repository-url = "https://github.com/Elektrobit/ebcl_dev_container/" +git-repository-url = "https://github.com/Elektrobit/ebcl_build_tools/" git-repository-icon = "fa-github" -edit-url-template = "https://github.com/Elektrobit/ebcl_dev_container/edit/main/{path}" +edit-url-template = "https://github.com/Elektrobit/ebcl_build_tools/edit/main/{path}" input-404 = "not-found.md" [output.html.print] From afb5bde0564fa1429e6677448e35401bab4f6919 Mon Sep 17 00:00:00 2001 From: Joerg Vehlow Date: Thu, 13 Feb 2025 08:50:02 +0000 Subject: [PATCH 02/17] hypervisor: initial documentation --- docs/SUMMARY.md | 1 + docs/assets/hv_overview.drawio | 97 +++++++ docs/assets/hv_overview.png | Bin 0 -> 70360 bytes docs/hypervisor_config.md | 481 ++++++++++++++++++++++++++++++++ ebcl_build_tools.code-workspace | 3 +- 5 files changed, 581 insertions(+), 1 deletion(-) create mode 100644 docs/assets/hv_overview.drawio create mode 100644 docs/assets/hv_overview.png create mode 100644 docs/hypervisor_config.md diff --git a/docs/SUMMARY.md b/docs/SUMMARY.md index 1bdb902..10eaaa4 100644 --- a/docs/SUMMARY.md +++ b/docs/SUMMARY.md @@ -7,5 +7,6 @@ - [Initrd Generator](initrd_generator.md) - [Boot Generator](boot_generator.md) - [Downloader](downloader.md) +- [Hypervisor Config Generator](hypervisor_config.md) - [Proxy](proxy.md) - [Common](common.md) diff --git a/docs/assets/hv_overview.drawio b/docs/assets/hv_overview.drawio new file mode 100644 index 0000000..e7ad37a --- /dev/null +++ b/docs/assets/hv_overview.drawio @@ -0,0 +1,97 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/assets/hv_overview.png b/docs/assets/hv_overview.png new file mode 100644 index 0000000000000000000000000000000000000000..7ed24d0944975f78adc6b244392047f3ee622a35 GIT binary patch literal 70360 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®OMkrj>aQas>kCt{!rNgSnL)r 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 literal 0 HcmV?d00001 diff --git a/docs/hypervisor_config.md b/docs/hypervisor_config.md new file mode 100644 index 0000000..be58a72 --- /dev/null +++ b/docs/hypervisor_config.md @@ -0,0 +1,481 @@ +# Hypervisor Config Generator +The hypervisor config generator can create configuration files for the Elektrobit Hypervisor from a declarative configuration in yaml configuration files. + +## Background +Thy Elektrobit hypervisor traditionally is configured using the lua interface. +Configuration of the hypervisor usually consists of: + + * Virtual Machines (e.g. linux) to be started with assigned resources like + * CPUs + * RAM + * Passthrough hardware devices + * ... + * Applications running directly on the hypervisor + * Available physical hardware + * Virtual hardware like network interface pairs + +The configuration using lua is very flexible, but being a full-fledged imperative programming language it is not as straight forward as it could be. + +For that reason this tool was created that can turn a declarative definition of the system configuration into the required lua code. + + +Note: In the future the safety relevant applications of the hypervisor will require configuration in a format different from lua (e.g. compiled binary or binary configuration files). These files have to be created/generated as well which will likely be a part of this tool in the future. + +## Overview +![Elektrobit](assets/hv_overview.png) + +The image above shows the main components of the hypervisor config generator and the surrounding elements. +It shows the tooling itself (*hypervisor config tool*), which is the python code and some data (*builtin model*, *schema* and *template*) that is described later. +There is also the *declarative configuration* that is supplied by the user (i.e. it is part of the image description) and the resulting *lua configuration* that is generated by the tool and should be built into the hypervisor image by the surrounding toolchain. +The last part shown here is the optional *hypervisor specialization*. It can be used to extend or change the model used for the configuration and also replace or extend the configuration files generated. + +### Model and Schema +As described in the overview chapter the tool comes with a model and schema definition, that can be extended using a hypervisor specialization. The main reason for that mechanism is that the hypervisor can provide different features depending on the build (i.e. a hypervisor with and without safety extensions). +These features must be configurable and at the time of writing this tool and documentation it does not seem to be viable to integrate all possible features into the tool itself, so it is "outsourced" to a package created together with the hypervisor binaries. + +In this context the *schema* is a yaml file that describes all possible properties in the configuration file with their datatypes. It can be compared to [JSON Schema](https://json-schema.org/) but is very specific to the hypervisor and limited to +required features. Everything in the configuration file is either a simple datatype (like string, integer or boolean) an object of a specific type (i.e. a named collection of specified properties) or a list of these. +This schema is then used to parse the configuration file into a python object *model*. The model can also be extended/overwritten by the hypervisor specialization. For every named object type defined in the schema a python class exists or is dynamically created. This allows to add some functionality to transform the configuration or derive information using python code. + +The schema also defines the templates that are rendered into the final lua configuration using the python model in the last step of the tool. The templates can either be jinja2 templates (ending in .j2) then they are processed or they are just copied (e.g. for lua library code). + + +## Usage +The tool always requires the configuration yaml file and the output directory: +```bash +hypervisor_config config.yaml output_dir +``` + +When a hypervisor specialization is to be used there are two variants: + +1. Pass a directory containing the specialization (schema.yaml and/or model.py and templates) + `hypervisor_config --specialization specialization_dir config.yaml output_dir` +2. Pass a debian package name and a config file that contains repository definitions in the format of the other build tools: + `hypervisor_config --specialization-package package_name --repo-config repo_config.yaml config.yaml output_dir`. + This will automatically download the package and use the contained specialization (by searching for a directory with schema.yaml). + +The generated config files can then be used to rebuild the hypervisor binary using the l4image tool. + +## Reference +### Builtin configuration +This chapter describes the builtin configuration model. +It can be changed or extended by specializations but usually most of the information here should be correct for all hypervisor configurations. + +The root of the configuration is the `HVConfig` class. +It has four properties: + + * *cons*: Configuration for the the console multiplexer + * *vms*: A list of virtual machines to start + * *shms*: A list of shared memory segments that can be assigned to virtual machines + * *vbus*: A list of virtual hardware busses that can be used to pass real hardware to the virtual machines + +#### *cons* - Configuration of the console multiplexer +The console multiplexer is used to share a single serial console with multiple users (e.g. VMs). + +Currently there is only one configurable option for cons implemented: + + * *default_vm*: This is an optional string and connects the serial terminal to the virtual machine specified here. + If it is not specified cons is connected to the console multiplexer's command line interface. + Output is always visible for all clients of the console multiplexer even if the console is connected to one specific VM. + +The serial console can be used in a virtual machine by adding a node like this to the device tree: +```c +virtio_uart@20000 { + compatible = "virtio,mmio"; + reg = <0x20000 0x100>; /* The address can be moved around but should be page aligned (0x1000) */ + interrupt-parent = <&gic>; + interrupts = <0x0 0x7a 0x4>; /* irq can be set arbitrarily as long as it does not collide */ + l4vmm,vdev = "console"; /* This name is used for matching */ + status = "okay"; +}; +``` +The device will be visible in linux as `/dev/hvcX` with `X` being a number dependent on the order of nodes in the device tree. +I.e. if this is the first `virtio,mmio` node where the device backend defines a serial interface, it will be `hvc0`. + +#### *vms* - List of virtual machines +The element is a list of virtual machine descriptions. +All virtual machines defined here are started in the order they are defined. + +The following properties are defined for every virtual machine: + + * *name*: A string specifying the name of the virtual machine (used e.g. in console output). + * *kernel*: A string specifying the name of the kernel binary. (Automatically added to modules.list) + * *ram*: An integer defining the amount of RAM assigned to the machine in megabyte. + * *cpus*: An integer specifying the CPU mask for the machine (e.g. 0x13 means CPUS \[0,1,4\] are assigned to the VM). + * *cmdline*: A string defining the kernel commandline for the linux kernel. + * *initrd*: An optional string defining the name of the initial ramdisk. (Automatically added to modules.list) + * *dtb*: A string specifying the name of the binary device tree. (Automatically added to modules.list) + * *vbus*: An optional string specifying a virtual bus. (See [vbus](#vbus---list-of-virtual-busses)) + * *shms*: A list of strings of names of shared memory segments that are available to the VM. (See [shms](#shms---list-of-shared-memory-segments)) + * *virtio_block*: A list of virtio block devices used to serve a block device from one VM as as virtio block device in another VM. (see [Virtio Block Devices](#virtio-block-devices)) + * *vnets*: A list of strings that create virtual network pair devices. The same name must be used in exactly two virtual machines to create a pair of connected virtio net interfaces in the two VMs. + + +#### *shms* - List of shared memory segments +Shared memory segments can be used to assign the same physical RAM to more than one virtual machine (or even L4RE applications). +The *shms* property defines a list of shared memory segments with the following properties for each shm segment: + + * *name*: The name of the segment used to reference it in a virtual machine configuration and its device tree. + * *size*: The size of the segment in bytes. + * *address*: The optional physical address of the shared memory. If this is not set a valid address is automatically determined. If set it will trigger an error if the address is already used or outside of the RAM. Use with caution! + +A device tree entry for a shared memory segment `my_shm` looks like this: +```c +my_shm@0 { + device_type = "memory"; + l4vmm,dscap = "my_shm"; /* reference to the name of the shm */ + reg = <0x0 0 0x0 0x0>; /* size and address is set automatically */ + status = "okay"; +}; +``` + +#### Virtio Block Devices +Virtio block devices allow sharing of a block device from one virtual machine to another. +This allows for example executing the driver for an mmc interface in one linux VM and sharing one partition of that storage device to a different VM. + +A virtio serial device (on linux this will be `/dev/hvcX` with `X` being dependent on the device tree) is assigned to the server side and the `vio_filed` application should be used to serve a block device. +On the client side a virtio block device is created. Note: The client VM will not be started until all related servers are served by `vio_filed` daemons. + +Definition of virtio block devices is done using the *virtio_block* property in two VMs. +This property is a mapping of a list strings of *servers* and *clients*. +A name for a virtio block device should appear exactly once in the server list of a VM and once in the client list of another VM. + +##### Example +```yaml +vms: + - name: vm1 + virtio_block: + servers: + - root + - data + - name: vm2 + virtio_block: + clients: + - root + - data +``` +This creates two VMs where the first one (`vm1`) serves two virtio block devices that are used in the second vm. +So in `vm1` two instances of `vio_filed` have to be started. + +The device tree for `vm1` should specify two serial virtio devices: +```c + virtio_ser@0 { + compatible = "virtio,mmio"; + reg = <0x0 0x200>; /* The address can be set arbitrarily, but should not collide and be page aligned */ + interrupt-parent = <&gic>; + interrupts = <0 0x7c 4>; /* irq numbers can be selected freely as long as they don't collide */ + l4vmm,vdev = "proxy"; + l4vmm,virtiocap = "root_server"; /* name with _server appended */ + status = "okay"; + }; + + virtio_ser@1000 { + compatible = "virtio,mmio"; + reg = <0x1000 0x200>; + interrupt-parent = <&gic>; + interrupts = <0 0x7d 4>; + l4vmm,vdev = "proxy"; + l4vmm,virtiocap = "data_server"; /* name with _server appended */ + status = "okay"; + }; +``` +The devices will be visible as `/dev/hvcX`. (See [cons](#cons---configuration-of-the-console-multiplexer) for some information on the ordering). + +In `vm2`- on the client side - the device tree needs nodes like this: +```c +virtio_block@0 { + compatible = "virtio,mmio"; + reg = <0x0 0x1000>; /* The address can be set arbitrarily, but should not collide and be page aligned */ + interrupt-parent = <&gic>; + interrupts = <0 0x60 4>; /* irq numbers can be selected freely as long as they don't collide */ + l4vmm,vdev = "proxy"; + l4vmm,virtiocap = "root_client"; /* name with _client appended */ + status = "okay"; +}; + +virtio_block@1000 { + compatible = "virtio,mmio"; + reg = <0x1000 0x1000>; + interrupt-parent = <&gic>; + interrupts = <0 0x61 4>; + l4vmm,vdev = "proxy"; + l4vmm,virtiocap = "data_client"; /* name with _client appended */ + status = "okay"; +}; +``` +This will create two `/dev/vdY`devices with `Y` being a letter starting at 'a'. +If these are the only two `virtio,mmio` devices in the device tree that are backed by a block device, the names will be `vda` for `root` and `vdb` for `data`. + + +#### *vbus* - List of virtual busses +A *vbus* is a virtual bus that can have an arbitrary amount of devices assigned to it. +Devices are physical devices defined by register addresses and/or interrupts. +The *vbus* can be used to pass the devices to a virtual machine so the virtual machine can access the hardware directly. +Virtual busses are used to aggregate multiple devices together so they can be passed to one virtual machine. + +Every vbus has a *name* and an optional list of *devices* assigned to that bus. + +A device has the following properties: + + * *name*: Name of the device used to identify it. + * *compatible*: Optional compatible string used to match a device tree node to the device defined. + * *mmios*: An optional list of memory mapped IO addresses. Each entry in the list has the following properties: + * *address*: An integer describing the mmio address. + * *size*: An integer describing the size of the mmio region in bytes. + * *cached*: Optional boolean. If set to true, the memory is mapped as cached normal memory instead of device memory. For real devices this usually should not be set. + * *irqs*: An optional list of interrupts generated by the device. Each entry in the list has the following properties: + * *irq*: An integer describing the interrupt number. Note: This defines the interrupt using the same numbering schema as the linux device tree uses (i.e. do not add 32 for SPIs). + * *type*: An enum describing the type of the interrupt (`SGI`, `PPI`, `SPI`). The default is `SPI` which is used for almost all peripherals on arm. + * *trigger*: An enum describing the trigger mode of the interrupt, either `level_high` or `rising_edge`. + +##### Example +This example shows how to pass the gmac interface on an S32G to a virtual machine. +```yaml +... +vbus: + - name: s32_gmac + devices: + - name: ethernet_gmac + compatible: nxp,s32cc-dwmac + mmios: + - address: 0x4033c000 + size: 0x2000 + - address: 0x4007c004 + size: 4 + irqs: + - irq: 57 + trigger: level_high +vms: + - name: vma + vbus: s32_gmac +... +``` +The configuration defines a vbus `s32_gmac` with one device `ethernet_gmac` with two mmio regions (`0x2000` bytes at `0x4033c000` and `4` bytes at `0x4007c004`) and one SPI interrupt (`57`) with high level trigger behavior. +It is passed to virtual machine `vma`. + +A device tree that could be used for that can look like this: +```c +gmac0: ethernet@4033c000 { + compatible = "nxp,s32cc-dwmac"; /* must be the same as compatible string in device definition */ + reg = <0x0 0x4033c000 0x0 0x2000>, /* first mmio segment */ + <0x0 0x4007c004 0x0 0x4>; /* second defined mmio segment */ + interrupt-parent = <&gic>; + interrupts = ; /* Same interrupt number as in the device definition */ + /* reduced for brevity in this example */ + status = "okay"; +} +``` + + +### Schema +This chapter describes the format of the schema.yaml file. +As written above the schema file describes the hypervisor configuration file. + +There are four top level elements in the schema: + + * *version*: At the moment this is always `1`. It will be used when breaking changes are required. + * *classes*: This describes the available object types of the model. + * *root*: The type of the root node of the model. + * *templates*: A list of relative paths to templates that are rendered (`.j2`) or copied to the final configuration folder. + +#### Available datatypes +All configuration elements are typed. +There are some datatypes for basic types built into the parser. +These are: + + * *string*: A simple string + * *integer*: A natural positive or negative number + * *boolean*: A `True` or `False` value (in yaml format `true` or `false`) + +Additional datatypes can be defined using the classes collection in the schema. + +#### The *classes* element +The classes element describes a collection of classes used to parse the configuration into. +The collection is a yaml mapping where the key is the name of the class and the value is a mapping of properties to their type. + +```yaml +classes: + VM: + name: + type: string + kernel: + type: string + ram: + type: integer +``` +In this example a class `VM` is defined with three properties (`name`, `kernel` and `ram`). +When this type is used and loaded all three values MUST be specified. + +##### Properties of classes +In the previous chapter a class is described as a mapping of properties to their type. +A type is also a mapping to allow for more complex type definitions than just scalars. +The following properties are valid in a type definition: + + * *type*: The scalar datatype, a name of a class in the classes collection or `enum`. + * *optional*: Defaults to `false`. If set to `true` the value may be omitted in the configuration and will be set to the default value. + * *default*: Defaults to `None`. Can be set to a default value when optional is `true`. + * *enum_values*: If *type* is set to `enum` a sequence of strings of valid values for the enum. An enum is represented as a string in the python model. + * *aggregate*: Currently this supports only `list`. If set the parser expects a sequence of objects of the type defined in `type`. This allows for example to define a list of virtual machines.\ + Even for list aggregates a default value can be used. For example for an empty list `[]` can be used. It would also be possible to define one or more objects in the default. + +#### The *root* element +The *root* element describes the type expected for the whole configuration file. +This type should be a container for all elements required to configure the hypervisor. +In the builtin schema it is `HVConfig` which is a container that holds virtual machine, device configuration and others. + +#### Example + +```yaml +version: 1 + +classes: + # Define a class called Root + Root: + # A simple integer + simple_int: + type: integer + # An optional string that will have the value "default_value" when not specified + optional_str: + type: string + optional: true + default: default_value + # A list of boolean that will have the default value [true, false, false] when not specified + list_of_bool: + type: boolean + aggregate: list + optional: true + default: + - true + - false + - false + # An enum with valid values: value_a or value_b + an_enum: + type: enum + enum_values: + - value_a + - value_b + # An optional list of objects from type AnotherObject. Will be None if not specified + list_of_objects: + type: AnotherObject + aggregate: list + optional: true + + # Define a class called AnotherObject ... + AnotherObject: + # ... with just one property name as string + name: + type: string + +# The root class is the root node +root: Root + +# Define templates to be rendered +template: + - jinja_template.cfg.j2 + - copy_me.lua +``` + +The schema above can parse this configuration file: +```yaml +simple_int: 42 +optional_str: some string +list_of_bool: + - false + - false + - true +an_enum: value_b +list_of_objects: + - name: object 1 + - name: object 2 +``` + +Parsing this will return an instance of a `Root`-object with the five properties set and the `list_of_objects` property will contain a list of two `AnotherObject` instances. +This root object is passed to the jinja templates using the variable name `config` and can then be used to render the templates. + +Two templates are rendered in this example: *jinja_template.cfg.j2* is rendered using jinja2 and will be stored in the output folder as *jinja_template.cfg*. While *copy_me.lua* is just copied to the output folder. + + +### Model +In this context model means the python object model representing the configuration. +It is used to further process and validate the configuration to simplify the process of writing configuration templates in jinja. +One example for processing done in the model is collecting all kernel and device trees into a single list for inclusion into the modules.list that is then used to created the hypervisor binary. + +All classes defined in the schema may have a defined python class with the same name. +This is not necessary though, if a class does not exist it is dynamically created. +All model classes must be derived from `BaseModel` which is used for parsing the configuration. + + +### Hypervisor Specialization +The hypervisor specialization is used to enhance the schema, model and templates used to generate the configuration. +It allows customization depending on the supported features available in the hypervisor binary. +A specialization is a directory containing one or all of `schema.yaml`, `model.py` and templates. + + +#### Schema specialization +The specialization schema is loaded after the builtin schema and can extend it. +It can add new properties to existing classes, add new classes, change the root class and add/overwrite templates. + + +##### Example +The example below shows a snipped from the builtin schema and the specialization schema that adds a new property `hi` to the `VM` class and a new template. +This new property can then be used in the template to generate code that is only required if the virtual machine is a high integrity VM. + +Builtin schema: +```yaml +... +classes: + VM: + name: + type: string +... +``` + +Specialization schema: +```yaml +version: 1 + +classes: + VM: + hi: + type: boolean + default: false + optional: true + +templates: + - init.ned.j2 +``` + +#### Model specialization +When a specialization contains a `model.py` it is loaded after the builtin module and can overwrite existing classes or add new classes. +This can be used to add properties to the python classes or even add new processing of the configuration. +It is also possible to extend the existing classes by inheritance. + +##### Example +This example shows how a validation step can be integrated for the schema extension defined below. +In this hypothetical example a high integrity VM always requires the shared memory segments named `fbshm`, `proxycomshm`, `hicomshm`, `tmshm` and `wdgshm`. + + +```py +from ebcl.tools.hypervisor.model_gen import ConfigError +from ebcl.tools.hypervisor.model import VM as VMBase + +class VM(VMBase): + HI_EXPECTED_SHMS = set(( + "fbshm", + "proxycomshm", + "hicomshm", + "tmshm", + "wdgshm" + )) + hi: bool + """True if this is a high integrity VM""" + + def finalize(self, registry: HVConfig) -> None: + super().finalize(registry) + shm_names = [shm.name for shm in self.shms] + missing = self.HI_EXPECTED_SHMS.difference(shm_names) + if missing: + raise ConfigError(f"For a hi VM the following shms are missing: {', '.join(missing)}") +``` +The specialization model derives the class `VM` from the builtin `VM` class and adds a validation step to the `finalize` method. +Note that the `finalize` method is not (yet) called for all classes defined in the model. diff --git a/ebcl_build_tools.code-workspace b/ebcl_build_tools.code-workspace index 0018498..347b907 100644 --- a/ebcl_build_tools.code-workspace +++ b/ebcl_build_tools.code-workspace @@ -8,7 +8,8 @@ "cSpell.words": [ "debootstrap", "ebcl", - "minbase" + "minbase", + "Elektrobit" ] } } From c692b4b68902e35c8400f09b65a93f9b5081f4ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Vehlow?= Date: Wed, 19 Feb 2025 12:59:27 +0100 Subject: [PATCH 03/17] Update docs/hypervisor_config.md Co-authored-by: Matthias Beckert --- docs/hypervisor_config.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/hypervisor_config.md b/docs/hypervisor_config.md index be58a72..eab7d33 100644 --- a/docs/hypervisor_config.md +++ b/docs/hypervisor_config.md @@ -2,7 +2,7 @@ The hypervisor config generator can create configuration files for the Elektrobit Hypervisor from a declarative configuration in yaml configuration files. ## Background -Thy Elektrobit hypervisor traditionally is configured using the lua interface. +The Elektrobit hypervisor traditionally is configured using a lua interface. Configuration of the hypervisor usually consists of: * Virtual Machines (e.g. linux) to be started with assigned resources like From bac762b3f40831da8d2c9d373ddaec6987ece659 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Vehlow?= Date: Wed, 19 Feb 2025 12:59:33 +0100 Subject: [PATCH 04/17] Update docs/hypervisor_config.md Co-authored-by: Matthias Beckert --- docs/hypervisor_config.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/hypervisor_config.md b/docs/hypervisor_config.md index eab7d33..95b02b1 100644 --- a/docs/hypervisor_config.md +++ b/docs/hypervisor_config.md @@ -19,7 +19,8 @@ The configuration using lua is very flexible, but being a full-fledged imperativ For that reason this tool was created that can turn a declarative definition of the system configuration into the required lua code. -Note: In the future the safety relevant applications of the hypervisor will require configuration in a format different from lua (e.g. compiled binary or binary configuration files). These files have to be created/generated as well which will likely be a part of this tool in the future. +Note: In the future the safety relevant applications of the hypervisor will require configuration in a format different from lua (e.g. compiled binary or binary configuration files). +These files have to be created/generated as well which will likely be a part of this tool in the future. ## Overview ![Elektrobit](assets/hv_overview.png) From d6c6f23dc9de40fa04545c06af77a803cd772324 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Vehlow?= Date: Wed, 19 Feb 2025 13:00:52 +0100 Subject: [PATCH 05/17] Update docs/hypervisor_config.md Co-authored-by: Matthias Beckert --- docs/hypervisor_config.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/hypervisor_config.md b/docs/hypervisor_config.md index 95b02b1..5b026c0 100644 --- a/docs/hypervisor_config.md +++ b/docs/hypervisor_config.md @@ -28,7 +28,8 @@ These files have to be created/generated as well which will likely be a part of The image above shows the main components of the hypervisor config generator and the surrounding elements. It shows the tooling itself (*hypervisor config tool*), which is the python code and some data (*builtin model*, *schema* and *template*) that is described later. There is also the *declarative configuration* that is supplied by the user (i.e. it is part of the image description) and the resulting *lua configuration* that is generated by the tool and should be built into the hypervisor image by the surrounding toolchain. -The last part shown here is the optional *hypervisor specialization*. It can be used to extend or change the model used for the configuration and also replace or extend the configuration files generated. +The last part shown here is the optional *hypervisor specialization*. +It can be used to extend or change the model used for the configuration and also replace or extend the configuration files generated. ### Model and Schema As described in the overview chapter the tool comes with a model and schema definition, that can be extended using a hypervisor specialization. The main reason for that mechanism is that the hypervisor can provide different features depending on the build (i.e. a hypervisor with and without safety extensions). From 171b0e8b691a4568b8c0f71978e4e1173d92ff3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Vehlow?= Date: Wed, 19 Feb 2025 13:03:12 +0100 Subject: [PATCH 06/17] Update docs/hypervisor_config.md Co-authored-by: Matthias Beckert --- docs/hypervisor_config.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/hypervisor_config.md b/docs/hypervisor_config.md index 5b026c0..f2bafe9 100644 --- a/docs/hypervisor_config.md +++ b/docs/hypervisor_config.md @@ -391,7 +391,8 @@ list_of_objects: - name: object 2 ``` -Parsing this will return an instance of a `Root`-object with the five properties set and the `list_of_objects` property will contain a list of two `AnotherObject` instances. +Parsing this will return an instance of a `Root`-object with the five properties set. +The `list_of_objects` property will contain a list of two `AnotherObject` instances. This root object is passed to the jinja templates using the variable name `config` and can then be used to render the templates. Two templates are rendered in this example: *jinja_template.cfg.j2* is rendered using jinja2 and will be stored in the output folder as *jinja_template.cfg*. While *copy_me.lua* is just copied to the output folder. From 9da20cc847853c60844baf373d32e87c5f8ed3bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Vehlow?= Date: Wed, 19 Feb 2025 13:03:44 +0100 Subject: [PATCH 07/17] Update docs/hypervisor_config.md Co-authored-by: Matthias Beckert --- docs/hypervisor_config.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/hypervisor_config.md b/docs/hypervisor_config.md index f2bafe9..2251417 100644 --- a/docs/hypervisor_config.md +++ b/docs/hypervisor_config.md @@ -395,7 +395,9 @@ Parsing this will return an instance of a `Root`-object with the five properties The `list_of_objects` property will contain a list of two `AnotherObject` instances. This root object is passed to the jinja templates using the variable name `config` and can then be used to render the templates. -Two templates are rendered in this example: *jinja_template.cfg.j2* is rendered using jinja2 and will be stored in the output folder as *jinja_template.cfg*. While *copy_me.lua* is just copied to the output folder. +Two templates are rendered in this example: +*jinja_template.cfg.j2* is rendered using jinja2 and will be stored in the output folder as *jinja_template.cfg*. +*copy_me.lua* is just copied to the output folder. ### Model From 7af1f587235a4c86546eca76c44947b9bcfcdbd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Vehlow?= Date: Wed, 19 Feb 2025 13:04:07 +0100 Subject: [PATCH 08/17] Update docs/hypervisor_config.md Co-authored-by: Matthias Beckert --- docs/hypervisor_config.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/hypervisor_config.md b/docs/hypervisor_config.md index 2251417..a9c1b0a 100644 --- a/docs/hypervisor_config.md +++ b/docs/hypervisor_config.md @@ -32,7 +32,8 @@ The last part shown here is the optional *hypervisor specialization*. It can be used to extend or change the model used for the configuration and also replace or extend the configuration files generated. ### Model and Schema -As described in the overview chapter the tool comes with a model and schema definition, that can be extended using a hypervisor specialization. The main reason for that mechanism is that the hypervisor can provide different features depending on the build (i.e. a hypervisor with and without safety extensions). +As described in the overview chapter the tool comes with a model and schema definition, that can be extended using a hypervisor specialization. +The main reason for that mechanism is that the hypervisor can provide different features depending on the build (i.e. a hypervisor with and without safety extensions). These features must be configurable and at the time of writing this tool and documentation it does not seem to be viable to integrate all possible features into the tool itself, so it is "outsourced" to a package created together with the hypervisor binaries. In this context the *schema* is a yaml file that describes all possible properties in the configuration file with their datatypes. It can be compared to [JSON Schema](https://json-schema.org/) but is very specific to the hypervisor and limited to From 3dccd74445000c53b67f0c7de69fec0ec955fe3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Vehlow?= Date: Wed, 19 Feb 2025 13:05:06 +0100 Subject: [PATCH 09/17] Update docs/hypervisor_config.md Co-authored-by: Matthias Beckert --- docs/hypervisor_config.md | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/docs/hypervisor_config.md b/docs/hypervisor_config.md index a9c1b0a..37c4cd0 100644 --- a/docs/hypervisor_config.md +++ b/docs/hypervisor_config.md @@ -36,9 +36,14 @@ As described in the overview chapter the tool comes with a model and schema defi The main reason for that mechanism is that the hypervisor can provide different features depending on the build (i.e. a hypervisor with and without safety extensions). These features must be configurable and at the time of writing this tool and documentation it does not seem to be viable to integrate all possible features into the tool itself, so it is "outsourced" to a package created together with the hypervisor binaries. -In this context the *schema* is a yaml file that describes all possible properties in the configuration file with their datatypes. It can be compared to [JSON Schema](https://json-schema.org/) but is very specific to the hypervisor and limited to -required features. Everything in the configuration file is either a simple datatype (like string, integer or boolean) an object of a specific type (i.e. a named collection of specified properties) or a list of these. -This schema is then used to parse the configuration file into a python object *model*. The model can also be extended/overwritten by the hypervisor specialization. For every named object type defined in the schema a python class exists or is dynamically created. This allows to add some functionality to transform the configuration or derive information using python code. +In this context the *schema* is a yaml file that describes all possible properties in the configuration file with their datatypes. +It can be compared to [JSON Schema](https://json-schema.org/). +Nevertheless, it is very specific to the hypervisor and limited to required features only. +Everything in the configuration file is either a simple datatype (like string, integer or boolean) an object of a specific type (i.e. a named collection of specified properties) or a list of these. +This schema is then used to parse the configuration file into a python object *model*. +The model can also be extended/overwritten by the hypervisor specialization. +For every named object type defined in the schema a python class exists or is dynamically created. +This allows to add functionality to transform the configuration or derive information using python code. The schema also defines the templates that are rendered into the final lua configuration using the python model in the last step of the tool. The templates can either be jinja2 templates (ending in .j2) then they are processed or they are just copied (e.g. for lua library code). From 84d47038740204032ee10e010188f625f62fe832 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Vehlow?= Date: Wed, 19 Feb 2025 13:05:36 +0100 Subject: [PATCH 10/17] Update docs/hypervisor_config.md Co-authored-by: Matthias Beckert --- docs/hypervisor_config.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/hypervisor_config.md b/docs/hypervisor_config.md index 37c4cd0..8805089 100644 --- a/docs/hypervisor_config.md +++ b/docs/hypervisor_config.md @@ -45,7 +45,8 @@ The model can also be extended/overwritten by the hypervisor specialization. For every named object type defined in the schema a python class exists or is dynamically created. This allows to add functionality to transform the configuration or derive information using python code. -The schema also defines the templates that are rendered into the final lua configuration using the python model in the last step of the tool. The templates can either be jinja2 templates (ending in .j2) then they are processed or they are just copied (e.g. for lua library code). +The schema also defines templates that are rendered into the final lua configuration using the python model in the last step of the tool. +The templates can either be jinja2 templates (ending in .j2), being processed by the tool, or lua code that can be copied directly. ## Usage From acaaef4c57b0b491e88e136b8a2e1394a31958fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Vehlow?= Date: Wed, 19 Feb 2025 13:05:54 +0100 Subject: [PATCH 11/17] Update docs/hypervisor_config.md Co-authored-by: Matthias Beckert --- docs/hypervisor_config.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/hypervisor_config.md b/docs/hypervisor_config.md index 8805089..efed001 100644 --- a/docs/hypervisor_config.md +++ b/docs/hypervisor_config.md @@ -55,7 +55,7 @@ The tool always requires the configuration yaml file and the output directory: hypervisor_config config.yaml output_dir ``` -When a hypervisor specialization is to be used there are two variants: +There are two variants available to hand over a hypervisor specialization: 1. Pass a directory containing the specialization (schema.yaml and/or model.py and templates) `hypervisor_config --specialization specialization_dir config.yaml output_dir` From a91035e12e35e9fc41ec889e77a985bfb9469526 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Vehlow?= Date: Wed, 19 Feb 2025 13:06:38 +0100 Subject: [PATCH 12/17] Update docs/hypervisor_config.md Co-authored-by: Matthias Beckert --- docs/hypervisor_config.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/hypervisor_config.md b/docs/hypervisor_config.md index efed001..22d61ae 100644 --- a/docs/hypervisor_config.md +++ b/docs/hypervisor_config.md @@ -34,7 +34,9 @@ It can be used to extend or change the model used for the configuration and also ### Model and Schema As described in the overview chapter the tool comes with a model and schema definition, that can be extended using a hypervisor specialization. The main reason for that mechanism is that the hypervisor can provide different features depending on the build (i.e. a hypervisor with and without safety extensions). -These features must be configurable and at the time of writing this tool and documentation it does not seem to be viable to integrate all possible features into the tool itself, so it is "outsourced" to a package created together with the hypervisor binaries. +These features must be configurable for each supported platform. +At the time of writing this tool and documentation it does not seem to be viable to integrate all possible features into the tool itself. +As a result, the required features are "outsourced" to an additional package, created together with the hypervisor binaries for the corresponding platform. In this context the *schema* is a yaml file that describes all possible properties in the configuration file with their datatypes. It can be compared to [JSON Schema](https://json-schema.org/). From fad33efd671e115ac333ea1d4428c60bed5573c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Vehlow?= Date: Wed, 19 Feb 2025 13:11:26 +0100 Subject: [PATCH 13/17] Update docs/hypervisor_config.md Co-authored-by: Matthias Beckert --- docs/hypervisor_config.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/hypervisor_config.md b/docs/hypervisor_config.md index 22d61ae..43477ff 100644 --- a/docs/hypervisor_config.md +++ b/docs/hypervisor_config.md @@ -16,7 +16,8 @@ Configuration of the hypervisor usually consists of: The configuration using lua is very flexible, but being a full-fledged imperative programming language it is not as straight forward as it could be. -For that reason this tool was created that can turn a declarative definition of the system configuration into the required lua code. +For that reason, the *hypervisor config tool* was created. +It allows generation of the required lua code from a declarative system definition. Note: In the future the safety relevant applications of the hypervisor will require configuration in a format different from lua (e.g. compiled binary or binary configuration files). From cee9c4e84437e4170a2a166fd00020e77cb71016 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Vehlow?= Date: Wed, 19 Feb 2025 13:16:20 +0100 Subject: [PATCH 14/17] Update docs/hypervisor_config.md Co-authored-by: Matthias Beckert --- docs/hypervisor_config.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/hypervisor_config.md b/docs/hypervisor_config.md index 43477ff..b6c2014 100644 --- a/docs/hypervisor_config.md +++ b/docs/hypervisor_config.md @@ -129,7 +129,7 @@ The *shms* property defines a list of shared memory segments with the following * *name*: The name of the segment used to reference it in a virtual machine configuration and its device tree. * *size*: The size of the segment in bytes. - * *address*: The optional physical address of the shared memory. If this is not set a valid address is automatically determined. If set it will trigger an error if the address is already used or outside of the RAM. Use with caution! + * *address*: The optional physical address of the shared memory. If this is not set, a valid address is determined automatically. If the set address is already in use or outside of the RAM, it will trigger an error. Use with caution! A device tree entry for a shared memory segment `my_shm` looks like this: ```c From 2ee0adc3a1b40795068e7f1d4c3a96bebb982e49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Vehlow?= Date: Wed, 19 Feb 2025 13:16:45 +0100 Subject: [PATCH 15/17] Update docs/hypervisor_config.md Co-authored-by: Matthias Beckert --- docs/hypervisor_config.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/hypervisor_config.md b/docs/hypervisor_config.md index b6c2014..0bca375 100644 --- a/docs/hypervisor_config.md +++ b/docs/hypervisor_config.md @@ -216,7 +216,7 @@ virtio_block@1000 { }; ``` This will create two `/dev/vdY`devices with `Y` being a letter starting at 'a'. -If these are the only two `virtio,mmio` devices in the device tree that are backed by a block device, the names will be `vda` for `root` and `vdb` for `data`. +If these are the only two `virtio,mmio` devices in the device tree backed by a block device, the names will be `vda` for `root` and `vdb` for `data`. #### *vbus* - List of virtual busses From a2f19b17c7ba7a964f7f956b0ff7e9f140e21a53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Vehlow?= Date: Wed, 19 Feb 2025 13:19:48 +0100 Subject: [PATCH 16/17] Update docs/hypervisor_config.md Co-authored-by: Matthias Beckert --- docs/hypervisor_config.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/hypervisor_config.md b/docs/hypervisor_config.md index 0bca375..2368491 100644 --- a/docs/hypervisor_config.md +++ b/docs/hypervisor_config.md @@ -411,7 +411,7 @@ Two templates are rendered in this example: ### Model -In this context model means the python object model representing the configuration. +In this context, model means the python object model representing the configuration. It is used to further process and validate the configuration to simplify the process of writing configuration templates in jinja. One example for processing done in the model is collecting all kernel and device trees into a single list for inclusion into the modules.list that is then used to created the hypervisor binary. From 751223bba57084c915576dc76ded8c4da50c2d0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Vehlow?= Date: Wed, 19 Feb 2025 13:25:52 +0100 Subject: [PATCH 17/17] Update docs/hypervisor_config.md Co-authored-by: Matthias Beckert --- docs/hypervisor_config.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/hypervisor_config.md b/docs/hypervisor_config.md index 2368491..876aaae 100644 --- a/docs/hypervisor_config.md +++ b/docs/hypervisor_config.md @@ -28,7 +28,7 @@ These files have to be created/generated as well which will likely be a part of The image above shows the main components of the hypervisor config generator and the surrounding elements. It shows the tooling itself (*hypervisor config tool*), which is the python code and some data (*builtin model*, *schema* and *template*) that is described later. -There is also the *declarative configuration* that is supplied by the user (i.e. it is part of the image description) and the resulting *lua configuration* that is generated by the tool and should be built into the hypervisor image by the surrounding toolchain. +There is also the user-supplied *declarative configuration* (i.e. it is part of the image description) and the resulting generated *lua configuration*, which is intended to be integrated into the hypervisor image by the surrounding toolchain. The last part shown here is the optional *hypervisor specialization*. It can be used to extend or change the model used for the configuration and also replace or extend the configuration files generated.