From: Bin Meng Date: Wed, 11 May 2016 14:45:03 +0000 (-0700) Subject: x86: acpi: Switch to ACPI mode by ourselves instead of requested by OSPM X-Git-Tag: v2016.07-rc1~177^2~24 X-Git-Url: https://git.librecmc.org/?a=commitdiff_plain;h=6aef68dc36bc93e1c32c1f7119b580f5eda92182;p=oweals%2Fu-boot.git x86: acpi: Switch to ACPI mode by ourselves instead of requested by OSPM Per ACPI spec, during ACPI OS initialization, OSPM can determine that the ACPI hardware registers are owned by SMI (by way of the SCI_EN bit in the PM1_CNT register), in which case the ACPI OS issues the ACPI_ENABLE command to the SMI_CMD port. The SCI_EN bit effectively tracks the ownership of the ACPI hardware registers. However since U-Boot does not support SMI, we report all 3 fields in FADT (SMI_CMD, ACPI_ENABLE, ACPI_DISABLE) as zero, by following the spec who says: these fields are reserved and must be zero on system that does not support System Management mode. U-Boot seems to behave in a correct way that the ACPI spec allows, at least Linux does not complain, but apparently Windows does not think so. During Windows bring up debugging, it is observed that even these 3 fields are zero, Windows are still trying to issue SMI with hardcoded SMI port address and commands, and expecting SCI_EN to be changed by the firmware. Eventually Windows gives us a BSOD (Blue Screen of Death) saying ACPI_BIOS_ERROR and refuses to start. To fix this, turn on the SCI_EN bit by ourselves. With this patch, now U-Boot can install and boot Windows 8.1/10 successfully with the help of SeaBIOS using legacy interface (non-UEFI mode). Signed-off-by: Bin Meng Reviewed-by: Simon Glass --- diff --git a/arch/x86/include/asm/acpi_table.h b/arch/x86/include/asm/acpi_table.h index ff4802ac15..56aa282127 100644 --- a/arch/x86/include/asm/acpi_table.h +++ b/arch/x86/include/asm/acpi_table.h @@ -296,6 +296,9 @@ struct acpi_mcfg_mmconfig { u8 reserved[4]; }; +/* PM1_CNT bit defines */ +#define PM1_CNT_SCI_EN (1 << 0) + /* These can be used by the target port */ void acpi_fill_header(struct acpi_table_header *header, char *signature); diff --git a/arch/x86/lib/acpi_table.c b/arch/x86/lib/acpi_table.c index be7b824525..855d4a05ae 100644 --- a/arch/x86/lib/acpi_table.c +++ b/arch/x86/lib/acpi_table.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -301,6 +302,25 @@ static void acpi_create_mcfg(struct acpi_mcfg *mcfg) header->checksum = table_compute_checksum((void *)mcfg, header->length); } +static void enter_acpi_mode(int pm1_cnt) +{ + /* + * PM1_CNT register bit0 selects the power management event to be + * either an SCI or SMI interrupt. When this bit is set, then power + * management events will generate an SCI interrupt. When this bit + * is reset power management events will generate an SMI interrupt. + * + * Per ACPI spec, it is the responsibility of the hardware to set + * or reset this bit. OSPM always preserves this bit position. + * + * U-Boot does not support SMI. And we don't have plan to support + * anything running in SMM within U-Boot. To create a legacy-free + * system, and expose ourselves to OSPM as working under ACPI mode + * already, turn this bit on. + */ + outw(PM1_CNT_SCI_EN, pm1_cnt); +} + /* * QEMU's version of write_acpi_tables is defined in * arch/x86/cpu/qemu/acpi_table.c @@ -400,5 +420,11 @@ u32 write_acpi_tables(u32 start) debug("ACPI: done\n"); + /* + * Other than waiting for OSPM to request us to switch to ACPI mode, + * do it by ourselves, since SMI will not be triggered. + */ + enter_acpi_mode(fadt->pm1a_cnt_blk); + return current; }