From 34547e1e196fad86e7177aa65a1e3e9718a0b0c6 Mon Sep 17 00:00:00 2001 From: Victor Sun Date: Wed, 2 Sep 2020 15:42:20 +0800 Subject: [PATCH] HV: add acpi module support for pre-launched VM Previously we use a pre-defined structure as vACPI table for pre-launched VM, the structure is initialized by HV code. Now change the method to use a pre-loaded multiboot module instead. The module file will be generated by acrn-config tool and loaded to GPA 0x7ff00000, a hardcoded RSDP table at GPA 0x000f2400 will point to the XSDT table which at GPA 0x7ff00080; Tracked-On: #5266 Signed-off-by: Victor Sun Signed-off-by: Shuang Zheng Acked-by: Eddie Dong --- hypervisor/arch/x86/configs/vacpi.c | 20 ++++++++++++++++++++ hypervisor/arch/x86/guest/vm.c | 2 +- hypervisor/boot/guest/vboot_info.c | 21 +++++++++++++++++++++ hypervisor/boot/include/boot.h | 7 +++++-- hypervisor/common/vm_load.c | 5 +++++ hypervisor/include/arch/x86/guest/vm.h | 1 + hypervisor/include/arch/x86/vm_config.h | 5 +++++ hypervisor/include/dm/vacpi.h | 9 +++++++++ 8 files changed, 67 insertions(+), 3 deletions(-) diff --git a/hypervisor/arch/x86/configs/vacpi.c b/hypervisor/arch/x86/configs/vacpi.c index 08216acbb..66a101483 100644 --- a/hypervisor/arch/x86/configs/vacpi.c +++ b/hypervisor/arch/x86/configs/vacpi.c @@ -205,3 +205,23 @@ void build_vacpi(struct acrn_vm *vm) (void)copy_to_gpa(vm, &tpm2, ACPI_TPM2_ADDR, tpm2.header.length); } } + +/** + * @pre vm != NULL + * @pre vm->vm_id < CONFIG_MAX_VM_NUM + */ +void build_vrsdp(struct acrn_vm *vm) +{ + struct acpi_table_rsdp rsdp = { + .signature = ACPI_SIG_RSDP, + .oem_id = ACPI_OEM_ID, + .revision = 0x2U, + .length = ACPI_RSDP_XCHECKSUM_LENGTH, + .xsdt_physical_address = VIRT_XSDT_ADDR, + }; + + rsdp.checksum = calculate_checksum8(&rsdp, ACPI_RSDP_CHECKSUM_LENGTH); + rsdp.extended_checksum = calculate_checksum8(&rsdp, ACPI_RSDP_XCHECKSUM_LENGTH); + /* Copy RSDP table to guest physical memory F segment */ + (void)copy_to_gpa(vm, &rsdp, VIRT_RSDP_ADDR, ACPI_RSDP_XCHECKSUM_LENGTH); +} diff --git a/hypervisor/arch/x86/guest/vm.c b/hypervisor/arch/x86/guest/vm.c index 7bba37b20..78511a9ab 100644 --- a/hypervisor/arch/x86/guest/vm.c +++ b/hypervisor/arch/x86/guest/vm.c @@ -774,7 +774,7 @@ void prepare_vm(uint16_t vm_id, struct acrn_vm_config *vm_config) if (err == 0) { if (is_prelaunched_vm(vm)) { - build_vacpi(vm); + build_vrsdp(vm); } (void)vm_sw_loader(vm); diff --git a/hypervisor/boot/guest/vboot_info.c b/hypervisor/boot/guest/vboot_info.c index bf2df60cb..7e7568ba0 100644 --- a/hypervisor/boot/guest/vboot_info.c +++ b/hypervisor/boot/guest/vboot_info.c @@ -19,6 +19,7 @@ #include #include #include +#include #define DBG_LEVEL_BOOT 6U @@ -37,6 +38,16 @@ static void init_vm_ramdisk_info(struct acrn_vm *vm, const struct multiboot_modu } } +/** + * @pre vm != NULL && mod != NULL + */ +static void init_vm_acpi_info(struct acrn_vm *vm, const struct multiboot_module *mod) +{ + vm->sw.acpi_info.src_addr = hpa2hva((uint64_t)mod->mm_mod_start); + vm->sw.acpi_info.load_addr = (void *)VIRT_ACPI_DATA_ADDR; + vm->sw.acpi_info.size = ACPI_MODULE_SIZE; +} + /** * @pre vm != NULL */ @@ -222,6 +233,16 @@ static int32_t init_vm_sw_load(struct acrn_vm *vm, const struct acrn_multiboot_i if (mod != NULL) { init_vm_ramdisk_info(vm, mod); } + + if (is_prelaunched_vm(vm)) { + mod = get_mod_by_tag(mbi, vm_config->acpi_config.acpi_mod_tag); + if ((mod != NULL) && ((mod->mm_mod_end - mod->mm_mod_start) == ACPI_MODULE_SIZE)) { + init_vm_acpi_info(vm, mod); + } else { + pr_err("failed to load VM %d acpi module", vm->vm_id); + } + } + } else { pr_err("failed to load VM %d kernel module", vm->vm_id); } diff --git a/hypervisor/boot/include/boot.h b/hypervisor/boot/include/boot.h index 0f3e2d04b..8eab388cc 100644 --- a/hypervisor/boot/include/boot.h +++ b/hypervisor/boot/include/boot.h @@ -16,8 +16,11 @@ #include #define MAX_BOOTARGS_SIZE 2048U -/* The modules in multiboot are for kernel and ramdisk of pre-launched VMs and SOS VM */ -#define MAX_MODULE_NUM (2U * PRE_VM_NUM + 2U * SOS_VM_NUM) +/* The modules in multiboot are: Pre-launched VM: kernel/ramdisk/acpi; SOS VM: kernel/ramdisk */ +#define MAX_MODULE_NUM (3U * PRE_VM_NUM + 2U * SOS_VM_NUM) + +/* The vACPI module size is fixed to 1MB */ +#define ACPI_MODULE_SIZE MEM_1M /* extended flags for acrn multiboot info from multiboot2 */ #define MULTIBOOT_INFO_HAS_EFI_MMAP 0x00010000U diff --git a/hypervisor/common/vm_load.c b/hypervisor/common/vm_load.c index de9b580d7..73d596f3e 100644 --- a/hypervisor/common/vm_load.c +++ b/hypervisor/common/vm_load.c @@ -187,6 +187,7 @@ int32_t direct_boot_sw_loader(struct acrn_vm *vm) struct sw_kernel_info *sw_kernel = &(vm->sw.kernel_info); struct sw_module_info *bootargs_info = &(vm->sw.bootargs_info); struct sw_module_info *ramdisk_info = &(vm->sw.ramdisk_info); + struct sw_module_info *acpi_info = &(vm->sw.acpi_info); /* get primary vcpu */ struct acrn_vcpu *vcpu = vcpu_from_vid(vm, BSP_CPU_ID); @@ -216,6 +217,10 @@ int32_t direct_boot_sw_loader(struct acrn_vm *vm) (uint64_t)bootargs_info->load_addr, (strnlen_s((char *)bootargs_info->src_addr, MAX_BOOTARGS_SIZE) + 1U)); } + /* Copy Guest OS ACPI to its load location */ + if (acpi_info->size == ACPI_MODULE_SIZE) { + (void)copy_to_gpa(vm, acpi_info->src_addr, (uint64_t)acpi_info->load_addr, ACPI_MODULE_SIZE); + } switch (vm->sw.kernel_type) { case KERNEL_BZIMAGE: prepare_loading_bzimage(vm, vcpu); diff --git a/hypervisor/include/arch/x86/guest/vm.h b/hypervisor/include/arch/x86/guest/vm.h index 2c6662fc5..48f4ac898 100644 --- a/hypervisor/include/arch/x86/guest/vm.h +++ b/hypervisor/include/arch/x86/guest/vm.h @@ -65,6 +65,7 @@ struct vm_sw_info { struct sw_kernel_info kernel_info; struct sw_module_info bootargs_info; struct sw_module_info ramdisk_info; + struct sw_module_info acpi_info; /* HVA to IO shared page */ void *io_shared_page; /* If enable IO completion polling mode */ diff --git a/hypervisor/include/arch/x86/vm_config.h b/hypervisor/include/arch/x86/vm_config.h index 237ebbb68..912f51bb3 100644 --- a/hypervisor/include/arch/x86/vm_config.h +++ b/hypervisor/include/arch/x86/vm_config.h @@ -140,6 +140,10 @@ struct acrn_vm_os_config { uint64_t kernel_ramdisk_addr; } __aligned(8); +struct acrn_vm_acpi_config { + char acpi_mod_tag[MAX_MOD_TAG_LEN]; /* multiboot module tag for ACPI */ +} __aligned(8); + /* the vbdf is assgined by device model */ #define UNASSIGNED_VBDF 0xFFFFU @@ -180,6 +184,7 @@ struct acrn_vm_config { uint16_t pci_dev_num; /* indicate how many PCI devices in VM */ struct acrn_vm_pci_dev_config *pci_devs; /* point to PCI devices BDF list */ struct acrn_vm_os_config os_config; /* OS information the VM */ + struct acrn_vm_acpi_config acpi_config; /* ACPI config for the VM */ /* * below are variable length members (per build). diff --git a/hypervisor/include/dm/vacpi.h b/hypervisor/include/dm/vacpi.h index 46e99bff5..220c462c9 100644 --- a/hypervisor/include/dm/vacpi.h +++ b/hypervisor/include/dm/vacpi.h @@ -53,8 +53,16 @@ #define ACPI_ASL_COMPILER_ID "INTL" #define ACPI_ASL_COMPILER_VERSION 0x20190802U +/* Use a pre-loaded multiboot module as pre-launched VM ACPI table. + * The module file size is fixed to 1MB and loaded to GPA 0x7ff00000. + * A hardcoded RSDP table at GPA 0x000f2400 will point to the XSDT + * table which at GPA 0x7ff00080; + * The module file should be generated by acrn-config tool; + */ #define VIRT_ACPI_DATA_ADDR 0x7ff00000UL #define VIRT_ACPI_NVS_ADDR 0x7fff0000UL +#define VIRT_RSDP_ADDR 0x000f2400UL +#define VIRT_XSDT_ADDR 0x7ff00080UL /* virtual PCI MMCFG address base for pre/post-launched VM. */ #define VIRT_PCI_MMCFG_BASE 0xE0000000UL @@ -77,5 +85,6 @@ struct acpi_table_info { }; void build_vacpi(struct acrn_vm *vm); +void build_vrsdp(struct acrn_vm *vm); #endif /* VACPI_H */