[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