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);