Skip to content

Commit 79582b9

Browse files
shiqinggdbkinder
authored andcommitted
doc: update software design guidelines
This patch adds the guidelines for 'Module Level Configuration Design'. Signed-off-by: Shiqing Gao <shiqing.gao@intel.com>
1 parent efad496 commit 79582b9

File tree

2 files changed

+230
-0
lines changed

2 files changed

+230
-0
lines changed
27.5 KB
Loading

doc/developer-guides/sw_design_guidelines.rst

Lines changed: 230 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -450,6 +450,236 @@ boot information.
450450
Yes. Because 'vdev->ops' and 'vdev->ops->init' can not be guaranteed to be
451451
not NULL. If the VM called ``partition_mode_vpci_deinit`` twice, it may be NULL.
452452

453+
454+
Module Level Configuration Design Guidelines
455+
********************************************
456+
457+
Design Goals
458+
============
459+
460+
There are two goals for module level configuration design, as shown below:
461+
462+
a) In order to make the hypervisor more flexible, one source code and binary
463+
is preferred for different platforms with different configurations;
464+
465+
b) If one module is not used by a specific project, the module source code is
466+
treated as dead code. The effort to configure it in/out shall be minimized.
467+
468+
469+
Hypervisor Operation Modes
470+
==========================
471+
472+
The hypervisor operation modes are shown in
473+
:numref:`hypervisor_operation_modes` below.
474+
475+
.. table:: Hypervisor Operation Modes
476+
:align: center
477+
:widths: 10 10 50
478+
:name: hypervisor_operation_modes
479+
480+
+-------------+-----------+------------------------------------------------------------------------------+
481+
| Operation | Sub-modes | Description |
482+
| Modes | | |
483+
+=============+===========+==============================================================================+
484+
| INIT mode | DETECT | The hypervisor detects firmware, detects hardware resource, and reads |
485+
| | mode | configuration data. |
486+
| +-----------+------------------------------------------------------------------------------+
487+
| | STARTUP | The hypervisor initializes hardware resources, creates virtual resources like|
488+
| | mode | VCPU and VM, and executes VMLAUNCH instruction(the very first VM entry). |
489+
+-------------+-----------+------------------------------------------------------------------------------+
490+
| OPERATIONAL | N/A | After the first VM entry, the hypervisor runs in VMX root mode and guest OS |
491+
| mode | | runs in VMX non-root mode. |
492+
+-------------+-----------+------------------------------------------------------------------------------+
493+
| TERMINATION | N/A | If any fatal error is detected, the hypervisor will enter TERMINATION mode. |
494+
| mode | | In this mode, a default fatal error handler will be invoked to handle the |
495+
| | | fatal error. |
496+
+-------------+-----------+------------------------------------------------------------------------------+
497+
498+
499+
Configurable Module Properties
500+
==============================
501+
502+
The properties of configurable modules are shown below:
503+
504+
- The functionality of the module depends on platform configurations;
505+
- Corresponding platform configurations can be detected in DETECT mode;
506+
- The module APIs shall be configured in DETECT mode;
507+
- The module APIs shall be used in modes other than DETECT mode.
508+
509+
Platform configurations include:
510+
511+
- Features depending on hardware or firmware
512+
- Configuration data provided by firmware
513+
- Configuration data provided by BSP
514+
515+
516+
Design Rules
517+
============
518+
519+
The module level configuration design rules are shown below:
520+
521+
1. The platform configurations shall be detectable by hypervisor in DETECT mode;
522+
523+
2. Configurable module APIs shall be abstracted as operations which are
524+
implemented through a set of function pointers in the operations data
525+
structure;
526+
527+
3. Every function pointer in the operations data structure shall be instantiated
528+
as one module API in DETECT mode and the API is allowed to be implemented as
529+
empty function for some specific configurations;
530+
531+
4. The operations data structure shall be read-only in STARTUP mode, OPERATIONAL
532+
mode, and TERMINATION mode;
533+
534+
5. The configurable module shall only be accessed via APIs in the operations
535+
data structure in STARTUP mode or OPERATIONAL mode;
536+
537+
6. In order to guarantee that the function pointer in the operations data
538+
structure is dereferenced after it has been instantiated, the pre-condition
539+
shall be added for the function which deferences the function pointer,
540+
instead of checking the pointer for NULL.
541+
542+
.. note:: The third rule shall be double checked during code review.
543+
544+
Use Cases
545+
=========
546+
547+
The following table shows some use cases of module level configuration design:
548+
549+
.. list-table:: Module Level Configuration Design Use Cases
550+
:widths: 10 25 20
551+
:header-rows: 1
552+
553+
* - **Platform Configuration**
554+
- **Configurable Module**
555+
- **Prerequisite**
556+
557+
* - Features depending on hardware or firmware
558+
- This module is used to virtualize part of LAPIC functionalities.
559+
It can be done via APICv or software emulation depending on CPU
560+
capabilities.
561+
For example, KBL NUC doesn't support virtual-interrupt delivery, while
562+
other platforms support it.
563+
- If a function pointer is used, the prerequisite is
564+
"hv_operation_mode == OPERATIONAL".
565+
566+
* - Configuration data provided by firmware
567+
- This module is used to interact with firmware (UEFI or SBL), and the
568+
configuration data is provided by firmware.
569+
For example, UP2 uses SBL and KBL NUC uses UEFI.
570+
- If a function pointer is used, the prerequisite is
571+
"hv_operation_mode != DETECT".
572+
573+
* - Configuration data provided by BSP
574+
- This module is used to virtualize LAPIC, and the configuration data is
575+
provided by BSP.
576+
For example, some VMs use LAPIC pass-through and the other VMs use
577+
vLAPIC.
578+
- If a function pointer is used, the prerequisite is
579+
"hv_operation_mode == OPERATIONAL".
580+
581+
.. note:: Prerequisite is used to guarantee that the function pointer used for
582+
configuration is dereferenced after it has been instantiated.
583+
584+
585+
Examples
586+
========
587+
588+
Take the module for parsing boot information as an example to illustrate the
589+
idea of module level configuration design.
590+
591+
.. figure:: images/boot_information_parsing_module.png
592+
:align: center
593+
:scale: 70 %
594+
:name: boot_information_parsing_module
595+
596+
Boot Information Parsing Module
597+
598+
599+
As shown in the source code below, 'struct firmware_operations' is an operations
600+
data structure that contains a set of function pointers.
601+
Different firmware may have different implementations:
602+
603+
- 'firmware_uefi_ops' is for UEFI platform;
604+
- 'firmware_sbl_ops' is for SBL platform.
605+
606+
607+
.. code-block:: c
608+
609+
struct firmware_operations {
610+
void (*init)(void);
611+
uint64_t (*get_ap_trampoline)(void);
612+
void *(*get_rsdp)(void);
613+
void (*init_irq)(void);
614+
int32_t (*init_vm_boot_info)(struct acrn_vm *vm);
615+
};
616+
617+
static struct firmware_operations firmware_uefi_ops = {
618+
.init = uefi_init,
619+
.get_ap_trampoline = uefi_get_ap_trampoline,
620+
.get_rsdp = uefi_get_rsdp,
621+
.init_irq = uefi_init_irq,
622+
.init_vm_boot_info = uefi_init_vm_boot_info,
623+
};
624+
625+
static struct firmware_operations firmware_sbl_ops = {
626+
.init = sbl_init,
627+
.get_ap_trampoline = sbl_get_ap_trampoline,
628+
.get_rsdp = sbl_get_rsdp,
629+
.init_irq = sbl_init_irq,
630+
.init_vm_boot_info = sbl_init_vm_boot_info,
631+
};
632+
633+
634+
'firmware_ops' is the operations set that is dereferenced and takes effect.
635+
636+
'init_firmware_operations' is called when the hypervisor is in DETECT mode and
637+
'firmware_ops' is instantiated here to either 'firmware_uefi_ops' or
638+
'firmware_sbl_ops' depending on the platform.
639+
640+
.. note:: All the other exported interfaces using 'firmware_ops' shall be called
641+
after the instantiation.
642+
643+
644+
.. code-block:: c
645+
646+
static struct firmware_operations *firmware_ops;
647+
648+
struct firmware_operations* uefi_get_firmware_operations(void)
649+
{
650+
return &firmware_uefi_ops;
651+
}
652+
653+
struct firmware_operations* sbl_get_firmware_operations(void)
654+
{
655+
return &firmware_sbl_ops;
656+
}
657+
658+
void init_firmware_operations(void)
659+
{
660+
if (is_firmware_sbl()) {
661+
firmware_ops = sbl_get_firmware_operations();
662+
} else {
663+
firmware_ops = uefi_get_firmware_operations();
664+
}
665+
}
666+
667+
668+
For example, when the hypervisor needs to initialize the VM boot information,
669+
it calls 'firmware_init_vm_boot_info' and 'firmware_ops->init_vm_boot_info' is
670+
dereferenced here with correct API being called.
671+
672+
.. code-block:: c
673+
674+
/**
675+
* @pre firmware_ops->init_vm_boot_info != NULL
676+
*/
677+
int32_t firmware_init_vm_boot_info(struct acrn_vm *vm)
678+
{
679+
return firmware_ops->init_vm_boot_info(vm);
680+
}
681+
682+
453683
References
454684
**********
455685

0 commit comments

Comments
 (0)