hv: add ACPI support for pre-launched VMs

Statically define the per vm RSDP/XSDT/MADT ACPI template tables in vacpi.c,
RSDP/XSDT tables are copied to guest physical memory after checksum is
calculated. For MADT table, first fix up process id/lapic id in its lapic
subtable, then the MADT table's checksum is calculated before it is copies to
guest physical memory.

Add 8-bit checksum function in util.h

Tracked-On: #3601
Signed-off-by: dongshen <dongsheng.x.zhang@intel.com>
Reviewed-by: Eddie Dong <eddie.dong@intel.com>
This commit is contained in:
dongshen 2019-08-21 19:37:33 -07:00 committed by wenlingz
parent 96b422ce9d
commit b447ce3d86
7 changed files with 191 additions and 4 deletions

View File

@ -247,6 +247,7 @@ VP_BASE_C_SRCS += common/hv_main.c
VP_BASE_C_SRCS += common/vm_load.c
VP_BASE_C_SRCS += arch/x86/configs/vmptable.c
VP_BASE_C_SRCS += arch/x86/configs/pci_dev.c
VP_BASE_C_SRCS += arch/x86/configs/vacpi.c
VP_BASE_C_SRCS += arch/x86/configs/$(CONFIG_BOARD)/ve820.c
# virtual platform device model

View File

@ -0,0 +1,103 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <vm.h>
#include <per_cpu.h>
#include <vacpi.h>
#include <pgtable.h>
/* ACPI tables for pre-launched VM and SOS */
static struct acpi_table_info acpi_table_template[CONFIG_MAX_VM_NUM] = {
[0U ... (CONFIG_MAX_VM_NUM - 1U)] = {
.rsdp = {
.signature = ACPI_SIG_RSDP,
.oem_id = ACPI_OEM_ID,
.revision = 0x2U,
.length = ACPI_RSDP_XCHECKSUM_LENGTH,
.xsdt_physical_address = ACPI_XSDT_ADDR,
},
.xsdt = {
/* Currently XSDT table only pointers to 1 ACPI table entry (MADT) */
.header.length = sizeof(struct acpi_table_header) + sizeof(uint64_t),
.header.revision = 0x1U,
.header.oem_revision = 0x1U,
.header.asl_compiler_revision = ACPI_ASL_COMPILER_VERSION,
.header.signature = ACPI_SIG_XSDT,
.header.oem_id = ACPI_OEM_ID,
.header.oem_table_id = "ACRNXSDT",
.header.asl_compiler_id = ACPI_ASL_COMPILER_ID,
.table_offset_entry[0] = ACPI_MADT_ADDR,
},
.madt = {
.header.revision = 0x3U,
.header.oem_revision = 0x1U,
.header.asl_compiler_revision = ACPI_ASL_COMPILER_VERSION,
.header.signature = ACPI_SIG_MADT,
.header.oem_id = ACPI_OEM_ID,
.header.oem_table_id = "ACRNMADT",
.header.asl_compiler_id = ACPI_ASL_COMPILER_ID,
.address = 0xFEE00000U, /* Local APIC Address */
.flags = 0x1U, /* PC-AT Compatibility=1 */
},
.lapic_nmi = {
.header.type = ACPI_MADT_TYPE_LOCAL_APIC_NMI,
.header.length = sizeof(struct acpi_madt_local_apic_nmi),
.processor_id = 0xFFU,
.flags = 0x5U,
.lint = 0x1U,
},
.lapic_array = {
[0U ... (CONFIG_MAX_PCPU_NUM - 1U)] = {
.header.type = ACPI_MADT_TYPE_LOCAL_APIC,
.header.length = sizeof(struct acpi_madt_local_apic),
.lapic_flags = 0x1U, /* Processor Enabled=1, Runtime Online Capable=0 */
}
},
}
};
/**
* @pre vm != NULL
* @pre vm->vm_id < CONFIG_MAX_VM_NUM
*/
void build_vacpi(struct acrn_vm *vm)
{
struct acpi_table_rsdp *rsdp;
struct acpi_table_xsdt *xsdt;
struct acpi_table_madt *madt;
struct acpi_madt_local_apic *lapic;
uint16_t i;
rsdp = &acpi_table_template[vm->vm_id].rsdp;
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 */
(void)copy_to_gpa(vm, rsdp, ACPI_RSDP_ADDR, ACPI_RSDP_XCHECKSUM_LENGTH);
xsdt = &acpi_table_template[vm->vm_id].xsdt;
xsdt->header.checksum = calculate_checksum8(xsdt, xsdt->header.length);
/* Copy XSDT table to guest physical memory */
(void)copy_to_gpa(vm, xsdt, ACPI_XSDT_ADDR, xsdt->header.length);
/* Fix up MADT LAPIC subtables */
for (i = 0U; i < vm->hw.created_vcpus; i++) {
lapic = &acpi_table_template[vm->vm_id].lapic_array[i];
lapic->processor_id = (uint8_t)i;
lapic->id = (uint8_t)i;
}
madt = &acpi_table_template[vm->vm_id].madt;
madt->header.length = sizeof(struct acpi_table_madt)
+ sizeof(struct acpi_madt_local_apic_nmi)
+ (sizeof(struct acpi_madt_local_apic) * (size_t)vm->hw.created_vcpus);
madt->header.checksum = calculate_checksum8(madt, madt->header.length);
/* Copy MADT table and its subtables to guest physical memory */
(void)copy_to_gpa(vm, madt, ACPI_MADT_ADDR, madt->header.length);
}

View File

@ -743,6 +743,7 @@ void prepare_vm(uint16_t vm_id, struct acrn_vm_config *vm_config)
if (err == 0) {
if (is_prelaunched_vm(vm)) {
(void)mptable_build(vm);
build_vacpi(vm);
}
(void )vm_sw_loader(vm);

View File

@ -11,6 +11,7 @@
#define ACPI_RSDP_CHECKSUM_LENGTH 20U
#define ACPI_RSDP_XCHECKSUM_LENGTH 36U
#define ACPI_NAME_SIZE 4U
#define ACPI_OEM_ID_SIZE 6U
@ -19,6 +20,7 @@
#define ACPI_MADT_TYPE_LOCAL_APIC 0U
#define ACPI_MADT_TYPE_IOAPIC 1U
#define ACPI_MADT_ENABLED 1U
#define ACPI_MADT_TYPE_LOCAL_APIC_NMI 4U
/* FACP field offsets */
#define OFFSET_FACS_ADDR 36U
@ -37,6 +39,7 @@
#define ACPI_SIG_FADT "FACP" /* Fixed ACPI Description Table */
#define ACPI_SIG_FACS 0x53434146U /* "FACS" */
#define ACPI_SIG_RSDP "RSD PTR " /* Root System Description Ptr */
#define ACPI_SIG_XSDT "XSDT" /* Extended System Description Table */
#define ACPI_SIG_MADT "APIC" /* Multiple APIC Description Table */
#define ACPI_SIG_DMAR "DMAR"
@ -127,13 +130,20 @@ struct acpi_madt_local_apic {
uint32_t lapic_flags;
} __packed;
struct acpi_madt_local_apic_nmi {
struct acpi_subtable_header header;
uint8_t processor_id;
uint16_t flags;
uint8_t lint;
} __packed;
struct acpi_madt_ioapic {
struct acpi_subtable_header header;
/* IOAPIC id */
uint8_t id;
uint8_t rsvd;
uint32_t addr;
uint32_t gsi_base;
uint8_t id;
uint8_t rsvd;
uint32_t addr;
uint32_t gsi_base;
} __packed;
enum acpi_dmar_type {

View File

@ -12,6 +12,7 @@
#include <multiboot.h>
#include <acrn_common.h>
#include <mptable.h>
#include <vacpi.h>
#include <vm_configurations.h>
#include <sgx.h>

View File

@ -0,0 +1,63 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/************************************************************************
*
* FILE NAME
*
* vacpi.h
*
* DESCRIPTION
*
* This file defines API and extern variable for virtual ACPI
*
************************************************************************/
/**********************************/
/* EXTERNAL VARIABLES */
/**********************************/
#ifndef VACPI_H
#define VACPI_H
#include <acpi.h>
/*
*
* Create the minimal set of ACPI tables required to boot pre-launched VM
*
* The tables are placed in the guest's ROM area just below 1MB physical,
* above the MPTable.
*
* Layout
* ------
* RSDP -> 0xf2400 (36 bytes fixed)
* XSDT -> 0xf2480 (36 bytes + 8*7 table addrs, 4 used)
* MADT -> 0xf2500 (depends on #CPUs)
*/
#define ACPI_BASE 0xf2400U
#define ACPI_RSDP_ADDR (ACPI_BASE + 0x0U)
#define ACPI_XSDT_ADDR (ACPI_BASE + 0x080U)
#define ACPI_MADT_ADDR (ACPI_BASE + 0x100U)
#define ACPI_OEM_ID "ACRN "
#define ACPI_ASL_COMPILER_ID "INTL"
#define ACPI_ASL_COMPILER_VERSION 0x20190802U
struct acpi_table_info {
struct acpi_table_rsdp rsdp;
struct acpi_table_xsdt xsdt;
struct {
struct acpi_table_madt madt;
struct acpi_madt_local_apic_nmi lapic_nmi;
struct acpi_madt_local_apic lapic_array[CONFIG_MAX_PCPU_NUM];
} __packed;
};
void build_vacpi(struct acrn_vm *vm);
#endif /* VACPI_H */

View File

@ -46,4 +46,12 @@ static inline uint8_t calculate_sum8(const void *buf, uint32_t length)
return sum;
}
/**
* @pre buf != NULL
*/
static inline uint8_t calculate_checksum8(const void *buf, uint32_t len)
{
return (uint8_t)(0x100U - calculate_sum8(buf, len));
}
#endif /* UTIL_H */