mirror of
https://github.com/projectacrn/acrn-hypervisor.git
synced 2025-06-24 14:33:38 +00:00
doc: update software design guidelines
This patch adds the guidelines for 'Module Level Configuration Design'. Signed-off-by: Shiqing Gao <shiqing.gao@intel.com>
This commit is contained in:
parent
efad496352
commit
79582b996f
BIN
doc/developer-guides/images/boot_information_parsing_module.png
Normal file
BIN
doc/developer-guides/images/boot_information_parsing_module.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 28 KiB |
@ -450,6 +450,236 @@ boot information.
|
|||||||
Yes. Because 'vdev->ops' and 'vdev->ops->init' can not be guaranteed to be
|
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.
|
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
|
References
|
||||||
**********
|
**********
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user