diff --git a/doc/developer-guides/images/boot_information_parsing_module.png b/doc/developer-guides/images/boot_information_parsing_module.png new file mode 100644 index 000000000..91588ce76 Binary files /dev/null and b/doc/developer-guides/images/boot_information_parsing_module.png differ diff --git a/doc/developer-guides/sw_design_guidelines.rst b/doc/developer-guides/sw_design_guidelines.rst index d3cf35cd8..a15867634 100644 --- a/doc/developer-guides/sw_design_guidelines.rst +++ b/doc/developer-guides/sw_design_guidelines.rst @@ -450,6 +450,236 @@ boot information. Yes. Because 'vdev->ops' and 'vdev->ops->init' can not be guaranteed to be not NULL. If the VM called ``partition_mode_vpci_deinit`` twice, it may be NULL. + +Module Level Configuration Design Guidelines +******************************************** + +Design Goals +============ + +There are two goals for module level configuration design, as shown below: + +a) In order to make the hypervisor more flexible, one source code and binary + is preferred for different platforms with different configurations; + +b) If one module is not used by a specific project, the module source code is + treated as dead code. The effort to configure it in/out shall be minimized. + + +Hypervisor Operation Modes +========================== + +The hypervisor operation modes are shown in +:numref:`hypervisor_operation_modes` below. + +.. table:: Hypervisor Operation Modes + :align: center + :widths: 10 10 50 + :name: hypervisor_operation_modes + + +-------------+-----------+------------------------------------------------------------------------------+ + | Operation | Sub-modes | Description | + | Modes | | | + +=============+===========+==============================================================================+ + | INIT mode | DETECT | The hypervisor detects firmware, detects hardware resource, and reads | + | | mode | configuration data. | + | +-----------+------------------------------------------------------------------------------+ + | | STARTUP | The hypervisor initializes hardware resources, creates virtual resources like| + | | mode | VCPU and VM, and executes VMLAUNCH instruction(the very first VM entry). | + +-------------+-----------+------------------------------------------------------------------------------+ + | OPERATIONAL | N/A | After the first VM entry, the hypervisor runs in VMX root mode and guest OS | + | mode | | runs in VMX non-root mode. | + +-------------+-----------+------------------------------------------------------------------------------+ + | TERMINATION | N/A | If any fatal error is detected, the hypervisor will enter TERMINATION mode. | + | mode | | In this mode, a default fatal error handler will be invoked to handle the | + | | | fatal error. | + +-------------+-----------+------------------------------------------------------------------------------+ + + +Configurable Module Properties +============================== + +The properties of configurable modules are shown below: + +- The functionality of the module depends on platform configurations; +- Corresponding platform configurations can be detected in DETECT mode; +- The module APIs shall be configured in DETECT mode; +- The module APIs shall be used in modes other than DETECT mode. + +Platform configurations include: + +- Features depending on hardware or firmware +- Configuration data provided by firmware +- Configuration data provided by BSP + + +Design Rules +============ + +The module level configuration design rules are shown below: + +1. The platform configurations shall be detectable by hypervisor in DETECT mode; + +2. Configurable module APIs shall be abstracted as operations which are + implemented through a set of function pointers in the operations data + structure; + +3. Every function pointer in the operations data structure shall be instantiated + as one module API in DETECT mode and the API is allowed to be implemented as + empty function for some specific configurations; + +4. The operations data structure shall be read-only in STARTUP mode, OPERATIONAL + mode, and TERMINATION mode; + +5. The configurable module shall only be accessed via APIs in the operations + data structure in STARTUP mode or OPERATIONAL mode; + +6. In order to guarantee that the function pointer in the operations data + structure is dereferenced after it has been instantiated, the pre-condition + shall be added for the function which deferences the function pointer, + instead of checking the pointer for NULL. + +.. note:: The third rule shall be double checked during code review. + +Use Cases +========= + +The following table shows some use cases of module level configuration design: + +.. list-table:: Module Level Configuration Design Use Cases + :widths: 10 25 20 + :header-rows: 1 + + * - **Platform Configuration** + - **Configurable Module** + - **Prerequisite** + + * - Features depending on hardware or firmware + - This module is used to virtualize part of LAPIC functionalities. + It can be done via APICv or software emulation depending on CPU + capabilities. + For example, KBL NUC doesn't support virtual-interrupt delivery, while + other platforms support it. + - If a function pointer is used, the prerequisite is + "hv_operation_mode == OPERATIONAL". + + * - Configuration data provided by firmware + - This module is used to interact with firmware (UEFI or SBL), and the + configuration data is provided by firmware. + For example, UP2 uses SBL and KBL NUC uses UEFI. + - If a function pointer is used, the prerequisite is + "hv_operation_mode != DETECT". + + * - Configuration data provided by BSP + - This module is used to virtualize LAPIC, and the configuration data is + provided by BSP. + For example, some VMs use LAPIC pass-through and the other VMs use + vLAPIC. + - If a function pointer is used, the prerequisite is + "hv_operation_mode == OPERATIONAL". + +.. note:: Prerequisite is used to guarantee that the function pointer used for + configuration is dereferenced after it has been instantiated. + + +Examples +======== + +Take the module for parsing boot information as an example to illustrate the +idea of module level configuration design. + +.. figure:: images/boot_information_parsing_module.png + :align: center + :scale: 70 % + :name: boot_information_parsing_module + + Boot Information Parsing Module + + +As shown in the source code below, 'struct firmware_operations' is an operations +data structure that contains a set of function pointers. +Different firmware may have different implementations: + +- 'firmware_uefi_ops' is for UEFI platform; +- 'firmware_sbl_ops' is for SBL platform. + + +.. code-block:: c + + struct firmware_operations { + void (*init)(void); + uint64_t (*get_ap_trampoline)(void); + void *(*get_rsdp)(void); + void (*init_irq)(void); + int32_t (*init_vm_boot_info)(struct acrn_vm *vm); + }; + + static struct firmware_operations firmware_uefi_ops = { + .init = uefi_init, + .get_ap_trampoline = uefi_get_ap_trampoline, + .get_rsdp = uefi_get_rsdp, + .init_irq = uefi_init_irq, + .init_vm_boot_info = uefi_init_vm_boot_info, + }; + + static struct firmware_operations firmware_sbl_ops = { + .init = sbl_init, + .get_ap_trampoline = sbl_get_ap_trampoline, + .get_rsdp = sbl_get_rsdp, + .init_irq = sbl_init_irq, + .init_vm_boot_info = sbl_init_vm_boot_info, + }; + + +'firmware_ops' is the operations set that is dereferenced and takes effect. + +'init_firmware_operations' is called when the hypervisor is in DETECT mode and +'firmware_ops' is instantiated here to either 'firmware_uefi_ops' or +'firmware_sbl_ops' depending on the platform. + +.. note:: All the other exported interfaces using 'firmware_ops' shall be called + after the instantiation. + + +.. code-block:: c + + static struct firmware_operations *firmware_ops; + + struct firmware_operations* uefi_get_firmware_operations(void) + { + return &firmware_uefi_ops; + } + + struct firmware_operations* sbl_get_firmware_operations(void) + { + return &firmware_sbl_ops; + } + + void init_firmware_operations(void) + { + if (is_firmware_sbl()) { + firmware_ops = sbl_get_firmware_operations(); + } else { + firmware_ops = uefi_get_firmware_operations(); + } + } + + +For example, when the hypervisor needs to initialize the VM boot information, +it calls 'firmware_init_vm_boot_info' and 'firmware_ops->init_vm_boot_info' is +dereferenced here with correct API being called. + +.. code-block:: c + + /** + * @pre firmware_ops->init_vm_boot_info != NULL + */ + int32_t firmware_init_vm_boot_info(struct acrn_vm *vm) + { + return firmware_ops->init_vm_boot_info(vm); + } + + References **********