hv: vacpi: add fadt table support

Add FADT table support to support guest S5 setting.

According to ACPI 6.3 Spec, OSPM must ignored the DSDT and FACS fields if them're zero.
However, Linux kernel seems not to abide by the protocol, it will check DSDT still.
So add an empty DSDT to meet it.

Tracked-On: #4623
Signed-off-by: Li Fei1 <fei1.li@intel.com>
This commit is contained in:
Li Fei1 2020-04-21 11:52:41 +08:00 committed by wenlingz
parent 9f036cff6a
commit 4eb3f5a0c7
3 changed files with 79 additions and 7 deletions

View File

@ -8,6 +8,7 @@
#include <per_cpu.h> #include <per_cpu.h>
#include <vacpi.h> #include <vacpi.h>
#include <pgtable.h> #include <pgtable.h>
#include <platform_acpi_info.h>
/* ACPI tables for pre-launched VM and SOS */ /* ACPI tables for pre-launched VM and SOS */
static struct acpi_table_info acpi_table_template[CONFIG_MAX_VM_NUM] = { static struct acpi_table_info acpi_table_template[CONFIG_MAX_VM_NUM] = {
@ -20,9 +21,6 @@ static struct acpi_table_info acpi_table_template[CONFIG_MAX_VM_NUM] = {
.xsdt_physical_address = ACPI_XSDT_ADDR, .xsdt_physical_address = ACPI_XSDT_ADDR,
}, },
.xsdt = { .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.revision = 0x1U,
.header.oem_revision = 0x1U, .header.oem_revision = 0x1U,
.header.asl_compiler_revision = ACPI_ASL_COMPILER_VERSION, .header.asl_compiler_revision = ACPI_ASL_COMPILER_VERSION,
@ -33,6 +31,35 @@ static struct acpi_table_info acpi_table_template[CONFIG_MAX_VM_NUM] = {
.table_offset_entry[0] = ACPI_MADT_ADDR, .table_offset_entry[0] = ACPI_MADT_ADDR,
}, },
.fadt = {
.header.revision = 0x3U,
.header.length = 0xF4U,
.header.oem_revision = 0x1U,
.header.asl_compiler_revision = ACPI_ASL_COMPILER_VERSION,
.header.signature = ACPI_SIG_FADT,
.header.oem_id = ACPI_OEM_ID,
.header.oem_table_id = "ACRNMADT",
.header.asl_compiler_id = ACPI_ASL_COMPILER_ID,
.dsdt = ACPI_DSDT_ADDR,
.pm1a_event_block = PM1A_EVT_ADDRESS,
.pm1a_control_block = PM1A_CNT_ADDRESS,
.pm1_event_length = 0x4U,
.pm1_control_length = 0x02U,
.flags = 0x00001125U, /* HEADLESS | TMR_VAL_EXT | SLP_BUTTON | PROC_C1 | WBINVD */
},
.dsdt = {
.revision = 0x3U,
.length = sizeof(struct acpi_table_header),
.oem_revision = 0x1U,
.asl_compiler_revision = ACPI_ASL_COMPILER_VERSION,
.signature = ACPI_SIG_DSDT,
.oem_id = ACPI_OEM_ID,
.oem_table_id = "ACRNMADT",
.asl_compiler_id = ACPI_ASL_COMPILER_ID,
},
.madt = { .madt = {
.header.revision = 0x3U, .header.revision = 0x3U,
.header.oem_revision = 0x1U, .header.oem_revision = 0x1U,
@ -70,6 +97,8 @@ void build_vacpi(struct acrn_vm *vm)
{ {
struct acpi_table_rsdp *rsdp; struct acpi_table_rsdp *rsdp;
struct acpi_table_xsdt *xsdt; struct acpi_table_xsdt *xsdt;
struct acpi_table_fadt *fadp;
struct acpi_table_header *dsdt;
struct acpi_table_madt *madt; struct acpi_table_madt *madt;
struct acpi_madt_local_apic *lapic; struct acpi_madt_local_apic *lapic;
uint16_t i; uint16_t i;
@ -81,9 +110,28 @@ void build_vacpi(struct acrn_vm *vm)
(void)copy_to_gpa(vm, rsdp, ACPI_RSDP_ADDR, ACPI_RSDP_XCHECKSUM_LENGTH); (void)copy_to_gpa(vm, rsdp, ACPI_RSDP_ADDR, ACPI_RSDP_XCHECKSUM_LENGTH);
xsdt = &acpi_table_template[vm->vm_id].xsdt; xsdt = &acpi_table_template[vm->vm_id].xsdt;
xsdt->header.checksum = calculate_checksum8(xsdt, xsdt->header.length);
/* Copy XSDT table to guest physical memory */ /* Copy XSDT table to guest physical memory */
(void)copy_to_gpa(vm, xsdt, ACPI_XSDT_ADDR, xsdt->header.length); (void)copy_to_gpa(vm, xsdt, ACPI_XSDT_ADDR, sizeof(struct acpi_table_header));
xsdt = (struct acpi_table_xsdt *)gpa2hva(vm, ACPI_XSDT_ADDR);
stac();
xsdt->table_offset_entry[0] = ACPI_FADT_ADDR;
xsdt->table_offset_entry[1] = ACPI_MADT_ADDR;
/* Currently XSDT table only pointers to 2 ACPI table entry (FADT/MADT) */
xsdt->header.length = sizeof(struct acpi_table_header) + (2U * sizeof(uint64_t));
xsdt->header.checksum = calculate_checksum8(xsdt, xsdt->header.length);
clac();
fadp = &acpi_table_template[vm->vm_id].fadt;
fadp->header.checksum = calculate_checksum8(fadp, fadp->header.length);
/* Copy FADT table to guest physical memory */
(void)copy_to_gpa(vm, fadp, ACPI_FADT_ADDR, fadp->header.length);
dsdt = &acpi_table_template[vm->vm_id].dsdt;
dsdt->checksum = calculate_checksum8(dsdt, dsdt->length);
/* Copy DSDT table and its subtables to guest physical memory */
(void)copy_to_gpa(vm, dsdt, ACPI_DSDT_ADDR, dsdt->length);
/* Fix up MADT LAPIC subtables */ /* Fix up MADT LAPIC subtables */
for (i = 0U; i < vm->hw.created_vcpus; i++) { for (i = 0U; i < vm->hw.created_vcpus; i++) {

View File

@ -56,6 +56,7 @@
#define ACPI_SIG_MADT "APIC" /* Multiple APIC Description Table */ #define ACPI_SIG_MADT "APIC" /* Multiple APIC Description Table */
#define ACPI_SIG_DMAR "DMAR" #define ACPI_SIG_DMAR "DMAR"
#define ACPI_SIG_MCFG "MCFG" /* Memory Mapped Configuration table */ #define ACPI_SIG_MCFG "MCFG" /* Memory Mapped Configuration table */
#define ACPI_SIG_DSDT "DSDT" /* Differentiated System Description Table */
struct packed_gas { struct packed_gas {
uint8_t space_id; uint8_t space_id;
@ -121,6 +122,23 @@ struct acpi_table_xsdt {
uint64_t table_offset_entry[1]; uint64_t table_offset_entry[1];
} __packed; } __packed;
struct acpi_table_fadt {
struct acpi_table_header header;/* Common ACPI table header */
uint32_t facs; /* 32-bit physical address of FACS */
uint32_t dsdt; /* 32-bit physical address of DSDT */
uint8_t unused0[12]; /* ACRN doesn't use these fields */
uint32_t pm1a_event_block; /* 32-bit port address of Power Mgt 1a Event Reg Blk */
uint32_t pm1b_event_block; /* 32-bit port address of Power Mgt 1b Event Reg Blk */
uint32_t pm1a_control_block; /* 32-bit port address of Power Mgt 1a Control Reg Blk */
uint32_t pm1b_control_block; /* 32-bit port address of Power Mgt 1b Control Reg Blk */
uint8_t unused1[16]; /* ACRN doesn't use these fields */
uint8_t pm1_event_length; /* Byte Length of ports at pm1x_event_block */
uint8_t pm1_control_length; /* Byte Length of ports at pm1x_control_block */
uint8_t unused2[22]; /* ACRN doesn't use these fields */
uint32_t flags; /* Miscellaneous flag bits (see below for individual flags) */
uint8_t unused3[128]; /* ACRN doesn't use these fields */
} __packed;
struct acpi_table_madt { struct acpi_table_madt {
/* Common ACPI table header */ /* Common ACPI table header */
struct acpi_table_header header; struct acpi_table_header header;

View File

@ -34,13 +34,17 @@
* ------ * ------
* RSDP -> 0xf2400 (36 bytes fixed) * RSDP -> 0xf2400 (36 bytes fixed)
* XSDT -> 0xf2480 (36 bytes + 8*7 table addrs, 4 used) * XSDT -> 0xf2480 (36 bytes + 8*7 table addrs, 4 used)
* MADT -> 0xf2500 (depends on #CPUs) * FADT -> 0xf2500 (244 bytes fixed for ACPI 2.0)
* DSDT -> 0xf2600 (36 bytes fixed for an empty DSDT)
* MADT -> 0xf2740 (depends on #CPUs)
*/ */
#define ACPI_BASE 0xf2400U #define ACPI_BASE 0xf2400U
#define ACPI_RSDP_ADDR (ACPI_BASE + 0x0U) #define ACPI_RSDP_ADDR (ACPI_BASE + 0x0U)
#define ACPI_XSDT_ADDR (ACPI_BASE + 0x080U) #define ACPI_XSDT_ADDR (ACPI_BASE + 0x080U)
#define ACPI_MADT_ADDR (ACPI_BASE + 0x100U) #define ACPI_FADT_ADDR (ACPI_BASE + 0x100U)
#define ACPI_DSDT_ADDR (ACPI_BASE + 0x200U)
#define ACPI_MADT_ADDR (ACPI_BASE + 0x340U)
#define ACPI_OEM_ID "ACRN " #define ACPI_OEM_ID "ACRN "
#define ACPI_ASL_COMPILER_ID "INTL" #define ACPI_ASL_COMPILER_ID "INTL"
@ -52,6 +56,8 @@ struct acpi_table_info {
struct acpi_table_xsdt xsdt; struct acpi_table_xsdt xsdt;
struct { struct {
struct acpi_table_fadt fadt;
struct acpi_table_header dsdt; /* an empty DSDT */
struct acpi_table_madt madt; struct acpi_table_madt madt;
struct acpi_madt_local_apic_nmi lapic_nmi; struct acpi_madt_local_apic_nmi lapic_nmi;
struct acpi_madt_local_apic lapic_array[MAX_PCPU_NUM]; struct acpi_madt_local_apic lapic_array[MAX_PCPU_NUM];