From e2d723d4fa914071fa99c801c7e3ef93ab7ec269 Mon Sep 17 00:00:00 2001 From: Victor Sun Date: Mon, 29 Apr 2019 13:52:37 +0800 Subject: [PATCH] HV: enable acpi pm1a register info fixup Previously ACPI PM1A register info was hardcoded to 0 in HV for generic boards, but SOS still can know the real PM1A info so the system would hang if user trigger S3 in SOS. Enabling PM1A register info fixup will let HV be able to intercept the operation on PM1A and then make basic function of S3 work for all boards; Tracked-On: #2291 Signed-off-by: Victor Sun Acked-by: Eddie Dong --- .../x86/configs/apl-mrb/platform_acpi_info.h | 2 - hypervisor/arch/x86/guest/pm.c | 22 +++-- hypervisor/arch/x86/pm.c | 6 -- hypervisor/boot/acpi.c | 82 +++++++++++++------ hypervisor/boot/include/acpi.h | 4 + hypervisor/bsp/firmware_wrapper.c | 1 + hypervisor/bsp/include/firmware.h | 4 - hypervisor/include/arch/x86/host_pm.h | 2 - 8 files changed, 77 insertions(+), 46 deletions(-) diff --git a/hypervisor/arch/x86/configs/apl-mrb/platform_acpi_info.h b/hypervisor/arch/x86/configs/apl-mrb/platform_acpi_info.h index 0e5c09f7b..4c99286b9 100644 --- a/hypervisor/arch/x86/configs/apl-mrb/platform_acpi_info.h +++ b/hypervisor/arch/x86/configs/apl-mrb/platform_acpi_info.h @@ -12,8 +12,6 @@ #ifndef PLATFORM_ACPI_INFO_H #define PLATFORM_ACPI_INFO_H -#define ACPI_INFO_VALIDATED - /* pm sstate data */ #define PM1A_EVT_ACCESS_SIZE 3U #define PM1A_EVT_ADDRESS 0x400UL diff --git a/hypervisor/arch/x86/guest/pm.c b/hypervisor/arch/x86/guest/pm.c index c7830cf68..e3fc9368c 100644 --- a/hypervisor/arch/x86/guest/pm.c +++ b/hypervisor/arch/x86/guest/pm.c @@ -100,15 +100,19 @@ void vm_setup_cpu_state(struct acrn_vm *vm) */ int32_t vm_load_pm_s_state(struct acrn_vm *vm) { -#ifdef ACPI_INFO_VALIDATED - vm->pm.sx_state_data = get_host_sstate_data(); - pr_info("System S3/S5 is supported."); - return 0; -#else - vm->pm.sx_state_data = NULL; - pr_err("System S3/S5 is NOT supported."); - return -1; -#endif + int32_t ret; + struct pm_s_state_data *sx_data = get_host_sstate_data(); + + if ((sx_data->pm1a_evt.address == 0UL) || (sx_data->pm1a_cnt.address == 0UL) + || (sx_data->wake_vector_32 == NULL)) { + pr_err("System S3/S5 is NOT supported."); + ret = -1; + } else { + pr_info("System S3/S5 is supported."); + vm->pm.sx_state_data = sx_data; + ret = 0; + } + return ret; } static inline uint32_t s3_enabled(uint32_t pm1_cnt) diff --git a/hypervisor/arch/x86/pm.c b/hypervisor/arch/x86/pm.c index 657c9f92e..9e0abfc33 100644 --- a/hypervisor/arch/x86/pm.c +++ b/hypervisor/arch/x86/pm.c @@ -65,12 +65,6 @@ static struct pm_s_state_data host_pm_s_state = { .wake_vector_64 = (uint64_t *)WAKE_VECTOR_64 }; -void set_host_wake_vectors(void *vector_32, void *vector_64) -{ - host_pm_s_state.wake_vector_32 = (uint32_t *)vector_32; - host_pm_s_state.wake_vector_64 = (uint64_t *)vector_64; -} - struct pm_s_state_data *get_host_sstate_data(void) { return &host_pm_s_state; diff --git a/hypervisor/boot/acpi.c b/hypervisor/boot/acpi.c index e486737f9..d5c54e0fb 100644 --- a/hypervisor/boot/acpi.c +++ b/hypervisor/boot/acpi.c @@ -349,6 +349,8 @@ void *get_dmar_table(void) /* FACP field offsets */ #define OFFSET_FACS_ADDR 36U #define OFFSET_FACS_X_ADDR 132U +#define OFFSET_PM1A_EVT 148U +#define OFFSET_PM1A_CNT 172U /* FACS field offsets */ #define OFFSET_FACS_SIGNATURE 0U @@ -368,35 +370,54 @@ static inline uint64_t get_acpi_dt_qword(const uint8_t *dt_addr, uint32_t dt_off return *(uint64_t *)(dt_addr + dt_offset); } -static void *get_facs_table(void) +struct packed_gas { + uint8_t space_id; + uint8_t bit_width; + uint8_t bit_offset; + uint8_t access_size; + uint64_t address; +} __attribute__((packed)); + +/* get a GAS struct from given table and its offset. + * ACPI table stores packed gas, but it is not guaranteed that + * struct acpi_generic_address is packed, so do not use memcpy in function. + * @pre dt_addr != NULL && gas != NULL + */ +static inline void get_acpi_dt_gas(const uint8_t *dt_addr, uint32_t dt_offset, struct acpi_generic_address *gas) { - uint8_t *facp_addr, *facs_addr, *facs_x_addr; + struct packed_gas *dt_gas = (struct packed_gas *)(dt_addr + dt_offset); + + gas->space_id = dt_gas->space_id; + gas->bit_width = dt_gas->bit_width; + gas->bit_offset = dt_gas->bit_offset; + gas->access_size = dt_gas->access_size; + gas->address = dt_gas->address; +} + +/* @pre facp_addr != NULL */ +static void *get_facs_table(const uint8_t *facp_addr) +{ + uint8_t *facs_addr, *facs_x_addr; uint32_t signature, length; - facp_addr = (uint8_t *)get_acpi_tbl(ACPI_SIG_FADT); + facs_addr = (uint8_t *)(uint64_t)get_acpi_dt_dword(facp_addr, OFFSET_FACS_ADDR); - if (facp_addr == NULL) { - facs_addr = NULL; - } else { - facs_addr = (uint8_t *)(uint64_t)get_acpi_dt_dword(facp_addr, OFFSET_FACS_ADDR); + facs_x_addr = (uint8_t *)get_acpi_dt_qword(facp_addr, OFFSET_FACS_X_ADDR); - facs_x_addr = (uint8_t *)get_acpi_dt_qword(facp_addr, OFFSET_FACS_X_ADDR); + if (facs_x_addr != NULL) { + facs_addr = facs_x_addr; + } - if (facs_x_addr != NULL) { - facs_addr = facs_x_addr; - } + if (facs_addr != NULL) { + signature = get_acpi_dt_dword(facs_addr, OFFSET_FACS_SIGNATURE); - if (facs_addr != NULL) { - signature = get_acpi_dt_dword(facs_addr, OFFSET_FACS_SIGNATURE); + if (signature != ACPI_SIG_FACS) { + facs_addr = NULL; + } else { + length = get_acpi_dt_dword(facs_addr, OFFSET_FACS_LENGTH); - if (signature != ACPI_SIG_FACS) { + if (length < 64U) { facs_addr = NULL; - } else { - length = get_acpi_dt_dword(facs_addr, OFFSET_FACS_LENGTH); - - if (length < 64U) { - facs_addr = NULL; - } } } } @@ -406,10 +427,25 @@ static void *get_facs_table(void) /* put all ACPI fix up code here */ void acpi_fixup(void) { - void *facs_addr = get_facs_table(); + uint8_t *facp_addr, *facs_addr; + struct acpi_generic_address pm1a_cnt, pm1a_evt; + struct pm_s_state_data *sx_data = get_host_sstate_data(); - if (facs_addr != NULL) { - set_host_wake_vectors(facs_addr + OFFSET_WAKE_VECTOR_32, facs_addr + OFFSET_WAKE_VECTOR_64); + facp_addr = (uint8_t *)get_acpi_tbl(ACPI_SIG_FADT); + + if (facp_addr != NULL) { + get_acpi_dt_gas(facp_addr, OFFSET_PM1A_EVT, &pm1a_evt); + get_acpi_dt_gas(facp_addr, OFFSET_PM1A_CNT, &pm1a_cnt); + (void)memcpy_s((void *)&sx_data->pm1a_evt, sizeof(struct acpi_generic_address), + (const void *)&pm1a_evt, sizeof(struct acpi_generic_address)); + (void)memcpy_s((void *)&sx_data->pm1a_cnt, sizeof(struct acpi_generic_address), + (const void *)&pm1a_cnt, sizeof(struct acpi_generic_address)); + + facs_addr = (uint8_t *)get_facs_table(facp_addr); + if (facs_addr != NULL) { + sx_data->wake_vector_32 = (uint32_t *)(facs_addr + OFFSET_WAKE_VECTOR_32); + sx_data->wake_vector_64 = (uint64_t *)(facs_addr + OFFSET_WAKE_VECTOR_64); + } } } #endif diff --git a/hypervisor/boot/include/acpi.h b/hypervisor/boot/include/acpi.h index ee58847c0..dc6b93f3a 100644 --- a/hypervisor/boot/include/acpi.h +++ b/hypervisor/boot/include/acpi.h @@ -11,4 +11,8 @@ struct ioapic_info; uint16_t parse_madt(uint32_t lapic_id_array[CONFIG_MAX_PCPU_NUM]); uint16_t parse_madt_ioapic(struct ioapic_info *ioapic_id_array); +#ifndef CONFIG_CONSTANT_ACPI +void acpi_fixup(void); +#endif + #endif /* !ACPI_H */ diff --git a/hypervisor/bsp/firmware_wrapper.c b/hypervisor/bsp/firmware_wrapper.c index 6b6af7251..6284f1951 100644 --- a/hypervisor/bsp/firmware_wrapper.c +++ b/hypervisor/bsp/firmware_wrapper.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include diff --git a/hypervisor/bsp/include/firmware.h b/hypervisor/bsp/include/firmware.h index 7ef827890..1cc44cb66 100644 --- a/hypervisor/bsp/include/firmware.h +++ b/hypervisor/bsp/include/firmware.h @@ -32,8 +32,4 @@ void *firmware_get_rsdp(void); void firmware_init_irq(void); int32_t firmware_init_vm_boot_info(struct acrn_vm *vm); -#ifndef CONFIG_CONSTANT_ACPI -void acpi_fixup(void); -#endif - #endif /* end of include guard: FIRMWARE_H */ diff --git a/hypervisor/include/arch/x86/host_pm.h b/hypervisor/include/arch/x86/host_pm.h index 67cbecaaf..569b75458 100644 --- a/hypervisor/include/arch/x86/host_pm.h +++ b/hypervisor/include/arch/x86/host_pm.h @@ -17,9 +17,7 @@ struct cpu_state_info { const struct cpu_cx_data *cx_data; }; -void set_host_wake_vectors(void *vector_32, void *vector_64); struct pm_s_state_data *get_host_sstate_data(void); - void host_enter_s3(struct pm_s_state_data *sstate_data, uint32_t pm1a_cnt_val, uint32_t pm1b_cnt_val); extern void asm_enter_s3(struct pm_s_state_data *sstate_data, uint32_t pm1a_cnt_val, uint32_t pm1b_cnt_val); extern void restore_s3_context(void);