[SeaBIOS] [PATCH v3] apm: fix shutdown
Kevin O'Connor
kevin at koconnor.net
Sat Jul 27 04:14:48 CEST 2013
On Fri, Jul 26, 2013 at 06:37:08PM +0200, Gerd Hoffmann wrote:
> Qemu commit 9ee59f3 removed the bochs bios apm interface emulation at
> port 0x8900. That broke poweroff via APM. Fix it by powering off the
> machine using the acpi pm control register.
>
> Old code is left in, so seabios wil try both poweroff methods. Cleaning
> that eventually up is left for another patch, after checking it isn't
> needed. Qemu never implemented "Standby" and "Suspend", only
> "Shutdown", so it looks like there might be non-qemu use cases (bochs
> probably).
>
> Easiest way to test this is the syslinux poweroff module; modern linux
> distros usually have CONFIG_APM turned off.
>
> Reported-by: Sebastian Herbszt <herbszt at gmx.de>
> Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
> ---
> src/acpi.c | 5 +++++
> src/acpi.h | 1 +
> src/apm.c | 2 ++
> 3 files changed, 8 insertions(+)
>
> diff --git a/src/acpi.c b/src/acpi.c
> index 3699898..44ba507 100644
> --- a/src/acpi.c
> +++ b/src/acpi.c
> @@ -18,6 +18,8 @@
>
> #include "acpi-dsdt.hex"
>
> +u32 acpi_pm1a_cnt VARLOW = PORT_ACPI_PM_BASE + 0x04;
> +
> static void
> build_header(struct acpi_table_header *h, u32 sig, int len, u8 rev)
> {
> @@ -730,9 +732,12 @@ find_acpi_features(void)
> if (!fadt)
> return;
> u32 pm_tmr = le32_to_cpu(fadt->pm_tmr_blk);
> + u32 pm1a_cnt = le32_to_cpu(fadt->pm1a_cnt_blk);
> dprintf(4, "pm_tmr_blk=%x\n", pm_tmr);
> if (pm_tmr)
> pmtimer_setup(pm_tmr, 3579);
> + if (pm1a_cnt)
> + acpi_pm1a_cnt = pm1a_cnt;
>
> // Theoretically we should check the 'reset_reg_sup' flag, but Windows
> // doesn't and thus nobody seems to *set* it. If the table is large enough
> diff --git a/src/acpi.h b/src/acpi.h
> index 5d1e104..f0d24d4 100644
> --- a/src/acpi.h
> +++ b/src/acpi.h
> @@ -36,6 +36,7 @@ struct rsdp_descriptor { /* Root System Descriptor Pointer */
> };
>
> extern struct rsdp_descriptor *RsdpAddr;
> +extern u32 acpi_pm1a_cnt;
>
> /* Table structure from Linux kernel (the ACPI tables are under the
> BSD license) */
> diff --git a/src/apm.c b/src/apm.c
> index b2eac6d..b3b351c 100644
> --- a/src/apm.c
> +++ b/src/apm.c
> @@ -12,6 +12,7 @@
> #include "config.h" // CONFIG_*
> #include "biosvar.h" // GET_GLOBAL
> #include "paravirt.h" // runningOnQEMU
> +#include "acpi.h" // acpi_pm_ctl
>
> static void
> out_str(const char *str_cs)
> @@ -109,6 +110,7 @@ void
> apm_shutdown(void)
> {
> irq_disable();
> + outw(0x2000, acpi_pm1a_cnt);
This code is also run from 16bit protected mode and 32bit protected
mode, so only GET_GLOBAL() access is permitted. Also, it can't
default to PORT_ACPI_PM_BASE, because if a valid ACPI table isn't
found we don't want to touch random ports.
Is the code to write always guaranteed to be 0x2000?
-Kevin
More information about the SeaBIOS
mailing list