]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[acpi] Add support for ACPI power off
authorMichael Brown <mcb30@ipxe.org>
Sun, 10 Jul 2016 18:25:26 +0000 (19:25 +0100)
committerMichael Brown <mcb30@ipxe.org>
Mon, 11 Jul 2016 13:05:18 +0000 (14:05 +0100)
Signed-off-by: Michael Brown <mcb30@ipxe.org>
src/arch/x86/include/bios.h
src/arch/x86/include/bits/errfile.h
src/arch/x86/include/ipxe/acpipwr.h [new file with mode: 0644]
src/arch/x86/include/ipxe/apm.h [new file with mode: 0644]
src/arch/x86/interface/pcbios/acpipwr.c [new file with mode: 0644]
src/arch/x86/interface/pcbios/apm.c
src/arch/x86/interface/pcbios/bios_reboot.c
src/core/acpi.c
src/include/ipxe/acpi.h

index 988bbc62b506c351a5975877ccdfe06963340be3..a5a5d887c448c6c1d4df12531baec50582071770 100644 (file)
@@ -4,6 +4,7 @@
 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 
 #define BDA_SEG 0x0040
+#define BDA_EBDA 0x000e
 #define BDA_EQUIPMENT_WORD 0x0010
 #define BDA_FBMS 0x0013
 #define BDA_REBOOT 0x0072
index 79b6f882e86f2bc6289e80fff0533a22f2ce6f06..f4816e62a2c4c8037ee7b3b6684d305130305eaf 100644 (file)
@@ -24,6 +24,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 #define ERRFILE_int13con       ( ERRFILE_ARCH | ERRFILE_CORE | 0x000d0000 )
 #define ERRFILE_gdbmach                ( ERRFILE_ARCH | ERRFILE_CORE | 0x000e0000 )
 #define ERRFILE_rtc_entropy    ( ERRFILE_ARCH | ERRFILE_CORE | 0x000f0000 )
+#define ERRFILE_acpipwr                ( ERRFILE_ARCH | ERRFILE_CORE | 0x00100000 )
 
 #define ERRFILE_bootsector     ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00000000 )
 #define ERRFILE_bzimage               ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00010000 )
diff --git a/src/arch/x86/include/ipxe/acpipwr.h b/src/arch/x86/include/ipxe/acpipwr.h
new file mode 100644 (file)
index 0000000..93da094
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef _IPXE_ACPIPWR_H
+#define _IPXE_ACPIPWR_H
+
+/** @file
+ *
+ * ACPI power off
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+extern int acpi_poweroff ( void );
+
+#endif /* _IPXE_ACPIPWR_H */
diff --git a/src/arch/x86/include/ipxe/apm.h b/src/arch/x86/include/ipxe/apm.h
new file mode 100644 (file)
index 0000000..21d913a
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef _IPXE_APM_H
+#define _IPXE_APM_H
+
+/** @file
+ *
+ * Advanced Power Management
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+extern int apm_poweroff ( void );
+
+#endif /* _IPXE_APM_H */
diff --git a/src/arch/x86/interface/pcbios/acpipwr.c b/src/arch/x86/interface/pcbios/acpipwr.c
new file mode 100644 (file)
index 0000000..63b986b
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2016 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <errno.h>
+#include <byteswap.h>
+#include <realmode.h>
+#include <bios.h>
+#include <ipxe/io.h>
+#include <ipxe/acpi.h>
+#include <ipxe/acpipwr.h>
+
+/** @file
+ *
+ * ACPI power off
+ *
+ */
+
+/** Colour for debug messages */
+#define colour FADT_SIGNATURE
+
+/** _S5_ signature */
+#define S5_SIGNATURE ACPI_SIGNATURE ( '_', 'S', '5', '_' )
+
+/**
+ * Power off the computer using ACPI
+ *
+ * @ret rc             Return status code
+ */
+int acpi_poweroff ( void ) {
+       struct acpi_fadt fadtab;
+       uint16_t ebda;
+       userptr_t rsdt;
+       userptr_t fadt;
+       unsigned int pm1a_cnt_blk;
+       unsigned int pm1b_cnt_blk;
+       unsigned int pm1a_cnt;
+       unsigned int pm1b_cnt;
+       unsigned int slp_typa;
+       unsigned int slp_typb;
+       int s5;
+       int rc;
+
+       /* Locate EBDA */
+       get_real ( ebda, BDA_SEG, BDA_EBDA );
+
+       /* Locate RSDT */
+       rsdt = acpi_find_rsdt ( real_to_user ( ebda, 0 ) );
+       if ( ! rsdt ) {
+               DBGC ( colour, "ACPI could not find RSDT (EBDA %04x)\n", ebda );
+               return -ENOENT;
+       }
+
+       /* Locate FADT */
+       fadt = acpi_find ( rsdt, FADT_SIGNATURE, 0 );
+       if ( ! fadt ) {
+               DBGC ( colour, "ACPI could not find FADT\n" );
+               return -ENOENT;
+       }
+
+       /* Read FADT */
+       copy_from_user ( &fadtab, fadt, 0, sizeof ( fadtab ) );
+       pm1a_cnt_blk = le32_to_cpu ( fadtab.pm1a_cnt_blk );
+       pm1b_cnt_blk = le32_to_cpu ( fadtab.pm1b_cnt_blk );
+       pm1a_cnt = ( pm1a_cnt_blk + ACPI_PM1_CNT );
+       pm1b_cnt = ( pm1b_cnt_blk + ACPI_PM1_CNT );
+
+       /* Extract \_S5 from DSDT or any SSDT */
+       s5 = acpi_sx ( rsdt, S5_SIGNATURE );
+       if ( s5 < 0 ) {
+               rc = s5;
+               DBGC ( colour, "ACPI could not extract \\_S5: %s\n",
+                      strerror ( rc ) );
+               return rc;
+       }
+
+       /* Power off system */
+       if ( pm1a_cnt_blk ) {
+               slp_typa = ( ( s5 >> 0 ) & 0xff );
+               DBGC ( colour, "ACPI PM1a sleep type %#x => %04x\n",
+                      slp_typa, pm1a_cnt );
+               outw ( ( ACPI_PM1_CNT_SLP_TYP ( slp_typa ) |
+                        ACPI_PM1_CNT_SLP_EN ), pm1a_cnt );
+       }
+       if ( pm1b_cnt_blk ) {
+               slp_typb = ( ( s5 >> 8 ) & 0xff );
+               DBGC ( colour, "ACPI PM1b sleep type %#x => %04x\n",
+                      slp_typb, pm1b_cnt );
+               outw ( ( ACPI_PM1_CNT_SLP_TYP ( slp_typb ) |
+                        ACPI_PM1_CNT_SLP_EN ), pm1b_cnt );
+       }
+
+       DBGC ( colour, "ACPI power off failed\n" );
+       return -EPROTO;
+}
index 50b19cb81dd53c92700705268218053c1abd2d12..680dbb16a8c87b595688170c168d2401e8629382 100644 (file)
@@ -32,14 +32,14 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 
 #include <errno.h>
 #include <realmode.h>
-#include <ipxe/reboot.h>
+#include <ipxe/apm.h>
 
 /**
  * Power off the computer using APM
  *
  * @ret rc             Return status code
  */
-static int apm_poweroff ( void ) {
+int apm_poweroff ( void ) {
        uint16_t apm_version;
        uint16_t apm_signature;
        uint16_t apm_flags;
@@ -108,5 +108,3 @@ static int apm_poweroff ( void ) {
        /* Should never happen */
        return -ECANCELED;
 }
-
-PROVIDE_REBOOT ( pcbios, poweroff, apm_poweroff );
index ed18dde0ba6431bed6adf0c23c509d90c516d75b..c6c5a5a914dee9bce46f561514514a1e3d6cd579 100644 (file)
@@ -32,6 +32,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 #include <ipxe/reboot.h>
 #include <realmode.h>
 #include <bios.h>
+#include <ipxe/apm.h>
+#include <ipxe/acpipwr.h>
 
 /**
  * Reboot system
@@ -49,4 +51,24 @@ static void bios_reboot ( int warm ) {
        __asm__ __volatile__ ( REAL_CODE ( "ljmp $0xf000, $0xfff0" ) );
 }
 
+/**
+ * Power off system
+ *
+ * @ret rc             Return status code
+ */
+static int bios_poweroff ( void ) {
+       int rc;
+
+       /* Try APM */
+       if ( ( rc = apm_poweroff() ) != 0 )
+               DBG ( "APM power off failed: %s\n", strerror ( rc ) );
+
+       /* Try ACPI */
+       if ( ( rc = acpi_poweroff() ) != 0 )
+               DBG ( "ACPI power off failed: %s\n", strerror ( rc ) );
+
+       return rc;
+}
+
 PROVIDE_REBOOT ( pcbios, reboot, bios_reboot );
+PROVIDE_REBOOT ( pcbios, poweroff, bios_poweroff );
index b0ccfa78ddf8220d6b9fac6fb9966b16e140e506..955637e0069845e9ab7521bd4df475a2aee3a008 100644 (file)
@@ -24,6 +24,8 @@
 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 
 #include <errno.h>
+#include <byteswap.h>
+#include <ipxe/uaccess.h>
 #include <ipxe/acpi.h>
 #include <ipxe/interface.h>
 
@@ -40,6 +42,22 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
  ******************************************************************************
  */
 
+/**
+ * Transcribe ACPI table signature (for debugging)
+ *
+ * @v signature                ACPI table signature
+ * @ret name           ACPI table signature name
+ */
+static const char * acpi_name ( uint32_t signature ) {
+       static union {
+               uint32_t signature;
+               char name[5];
+       } u;
+
+       u.signature = cpu_to_le32 ( signature );
+       return u.name;
+}
+
 /**
  * Fix up ACPI table checksum
  *
@@ -55,6 +73,262 @@ void acpi_fix_checksum ( struct acpi_description_header *acpi ) {
        acpi->checksum -= sum;
 }
 
+/**
+ * Locate ACPI root system description table within a memory range
+ *
+ * @v start            Start address to search
+ * @v len              Length to search
+ * @ret rsdt           ACPI root system description table, or UNULL
+ */
+static userptr_t acpi_find_rsdt_range ( userptr_t start, size_t len ) {
+       static const char signature[8] = RSDP_SIGNATURE;
+       struct acpi_rsdp rsdp;
+       userptr_t rsdt;
+       size_t offset;
+       uint8_t sum;
+       unsigned int i;
+
+       /* Search for RSDP */
+       for ( offset = 0 ; ( ( offset + sizeof ( rsdp ) ) < len ) ;
+             offset += RSDP_STRIDE ) {
+
+               /* Check signature and checksum */
+               copy_from_user ( &rsdp, start, offset, sizeof ( rsdp ) );
+               if ( memcmp ( rsdp.signature, signature,
+                             sizeof ( signature ) ) != 0 )
+                       continue;
+               for ( sum = 0, i = 0 ; i < sizeof ( rsdp ) ; i++ )
+                       sum += *( ( ( uint8_t * ) &rsdp ) + i );
+               if ( sum != 0 )
+                       continue;
+
+               /* Extract RSDT */
+               rsdt = phys_to_user ( le32_to_cpu ( rsdp.rsdt ) );
+               DBGC ( rsdt, "RSDT %#08lx found via RSDP %#08lx\n",
+                      user_to_phys ( rsdt, 0 ),
+                      user_to_phys ( start, offset ) );
+               return rsdt;
+       }
+
+       return UNULL;
+}
+
+/**
+ * Locate ACPI root system description table
+ *
+ * @v ebda             Extended BIOS data area, or UNULL
+ * @ret rsdt           ACPI root system description table, or UNULL
+ */
+userptr_t acpi_find_rsdt ( userptr_t ebda ) {
+       userptr_t rsdt;
+
+       /* Search EBDA, if applicable */
+       if ( ebda ) {
+               rsdt = acpi_find_rsdt_range ( ebda, RSDP_EBDA_LEN );
+               if ( rsdt )
+                       return rsdt;
+       }
+
+       /* Search fixed BIOS area */
+       rsdt = acpi_find_rsdt_range ( phys_to_user ( RSDP_BIOS_START ),
+                                     RSDP_BIOS_LEN );
+       if ( rsdt )
+               return rsdt;
+
+       return UNULL;
+}
+
+/**
+ * Locate ACPI table
+ *
+ * @v rsdt             ACPI root system description table
+ * @v signature                Requested table signature
+ * @v index            Requested index of table with this signature
+ * @ret table          Table, or UNULL if not found
+ */
+userptr_t acpi_find ( userptr_t rsdt, uint32_t signature, unsigned int index ) {
+       struct acpi_description_header acpi;
+       struct acpi_rsdt *rsdtab;
+       typeof ( rsdtab->entry[0] ) entry;
+       userptr_t table;
+       size_t len;
+       unsigned int count;
+       unsigned int i;
+
+       /* Read RSDT header */
+       copy_from_user ( &acpi, rsdt, 0, sizeof ( acpi ) );
+       if ( acpi.signature != cpu_to_le32 ( RSDT_SIGNATURE ) ) {
+               DBGC ( rsdt, "RSDT %#08lx has invalid signature:\n",
+                      user_to_phys ( rsdt, 0 ) );
+               DBGC_HDA ( rsdt, user_to_phys ( rsdt, 0 ), &acpi,
+                          sizeof ( acpi ) );
+               return UNULL;
+       }
+       len = le32_to_cpu ( acpi.length );
+       if ( len < sizeof ( rsdtab->acpi ) ) {
+               DBGC ( rsdt, "RSDT %#08lx has invalid length:\n",
+                      user_to_phys ( rsdt, 0 ) );
+               DBGC_HDA ( rsdt, user_to_phys ( rsdt, 0 ), &acpi,
+                          sizeof ( acpi ) );
+               return UNULL;
+       }
+
+       /* Calculate number of entries */
+       count = ( ( len - sizeof ( rsdtab->acpi ) ) / sizeof ( entry ) );
+
+       /* Search through entries */
+       for ( i = 0 ; i < count ; i++ ) {
+
+               /* Get table address */
+               copy_from_user ( &entry, rsdt,
+                                offsetof ( typeof ( *rsdtab ), entry[i] ),
+                                sizeof ( entry ) );
+
+               /* Read table header */
+               table = phys_to_user ( entry );
+               copy_from_user ( &acpi.signature, table, 0,
+                                sizeof ( acpi.signature ) );
+
+               /* Check table signature */
+               if ( acpi.signature != cpu_to_le32 ( signature ) )
+                       continue;
+
+               /* Check index */
+               if ( index-- )
+                       continue;
+
+               DBGC ( rsdt, "RSDT %#08lx found %s at %08lx\n",
+                      user_to_phys ( rsdt, 0 ), acpi_name ( signature ),
+                      user_to_phys ( table, 0 ) );
+               return table;
+       }
+
+       DBGC ( rsdt, "RSDT %#08lx could not find %s\n",
+              user_to_phys ( rsdt, 0 ), acpi_name ( signature ) );
+       return UNULL;
+}
+
+/**
+ * Extract \_Sx value from DSDT/SSDT
+ *
+ * @v zsdt             DSDT or SSDT
+ * @v signature                Signature (e.g. "_S5_")
+ * @ret sx             \_Sx value, or negative error
+ *
+ * In theory, extracting the \_Sx value from the DSDT/SSDT requires a
+ * full ACPI parser plus some heuristics to work around the various
+ * broken encodings encountered in real ACPI implementations.
+ *
+ * In practice, we can get the same result by scanning through the
+ * DSDT/SSDT for the signature (e.g. "_S5_"), extracting the first
+ * four bytes, removing any bytes with bit 3 set, and treating
+ * whatever is left as a little-endian value.  This is one of the
+ * uglier hacks I have ever implemented, but it's still prettier than
+ * the ACPI specification itself.
+ */
+static int acpi_sx_zsdt ( userptr_t zsdt, uint32_t signature ) {
+       struct acpi_description_header acpi;
+       union {
+               uint32_t dword;
+               uint8_t byte[4];
+       } buf;
+       size_t offset;
+       size_t len;
+       unsigned int sx;
+       uint8_t *byte;
+
+       /* Read table header */
+       copy_from_user ( &acpi, zsdt, 0, sizeof ( acpi ) );
+       len = le32_to_cpu ( acpi.length );
+
+       /* Locate signature */
+       for ( offset = sizeof ( acpi ) ;
+             ( ( offset + sizeof ( buf ) /* signature */ + 3 /* pkg header */
+                 + sizeof ( buf ) /* value */ ) < len ) ;
+             offset++ ) {
+
+               /* Check signature */
+               copy_from_user ( &buf, zsdt, offset, sizeof ( buf ) );
+               if ( buf.dword != cpu_to_le32 ( signature ) )
+                       continue;
+               DBGC ( zsdt, "DSDT/SSDT %#08lx found %s at offset %#zx\n",
+                      user_to_phys ( zsdt, 0 ), acpi_name ( signature ),
+                      offset );
+               offset += sizeof ( buf );
+
+               /* Read first four bytes of value */
+               copy_from_user ( &buf, zsdt, ( offset + 3 /* pkg header */ ),
+                                sizeof ( buf ) );
+               DBGC ( zsdt, "DSDT/SSDT %#08lx found %s containing "
+                      "%02x:%02x:%02x:%02x\n", user_to_phys ( zsdt, 0 ),
+                      acpi_name ( signature ), buf.byte[0], buf.byte[1],
+                      buf.byte[2], buf.byte[3] );
+
+               /* Extract \Sx value.  There are three potential
+                * encodings that we might encounter:
+                *
+                * - SLP_TYPa, SLP_TYPb, rsvd, rsvd
+                *
+                * - <byteprefix>, SLP_TYPa, <byteprefix>, SLP_TYPb, ...
+                *
+                * - <dwordprefix>, SLP_TYPa, SLP_TYPb, 0, 0
+                *
+                * Since <byteprefix> and <dwordprefix> both have bit
+                * 3 set, and valid SLP_TYPx must have bit 3 clear
+                * (since SLP_TYPx is a 3-bit field), we can just skip
+                * any bytes with bit 3 set.
+                */
+               byte = &buf.byte[0];
+               if ( *byte & 0x08 )
+                       byte++;
+               sx = *(byte++);
+               if ( *byte & 0x08 )
+                       byte++;
+               sx |= ( *byte << 8 );
+               return sx;
+       }
+
+       return -ENOENT;
+}
+
+/**
+ * Extract \_Sx value from DSDT/SSDT
+ *
+ * @v rsdt             ACPI root system description table
+ * @v signature                Signature (e.g. "_S5_")
+ * @ret sx             \_Sx value, or negative error
+ */
+int acpi_sx ( userptr_t rsdt, uint32_t signature ) {
+       struct acpi_fadt fadtab;
+       userptr_t fadt;
+       userptr_t dsdt;
+       userptr_t ssdt;
+       unsigned int i;
+       int sx;
+
+       /* Try DSDT first */
+       fadt = acpi_find ( rsdt, FADT_SIGNATURE, 0 );
+       if ( fadt ) {
+               copy_from_user ( &fadtab, fadt, 0, sizeof ( fadtab ) );
+               dsdt = phys_to_user ( fadtab.dsdt );
+               if ( ( sx = acpi_sx_zsdt ( dsdt, signature ) ) >= 0 )
+                       return sx;
+       }
+
+       /* Try all SSDTs */
+       for ( i = 0 ; ; i++ ) {
+               ssdt = acpi_find ( rsdt, SSDT_SIGNATURE, i );
+               if ( ! ssdt )
+                       break;
+               if ( ( sx = acpi_sx_zsdt ( ssdt, signature ) ) >= 0 )
+                       return sx;
+       }
+
+       DBGC ( rsdt, "RSDT %#08lx could not find \\_Sx \"%s\"\n",
+              user_to_phys ( rsdt, 0 ), acpi_name ( signature ) );
+       return -ENOENT;
+}
+
 /******************************************************************************
  *
  * Interface methods
index 2ccd691edb09e06ff7cc9c2b910eb6b510375137..17d29b9dfbc83e27e5399dabbbe26a2bf6a13e30 100644 (file)
@@ -11,6 +11,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 
 #include <stdint.h>
 #include <ipxe/interface.h>
+#include <ipxe/uaccess.h>
 
 /**
  * An ACPI description header
@@ -51,6 +52,76 @@ struct acpi_description_header {
 #define ACPI_SIGNATURE( a, b, c, d ) \
        ( ( (a) << 0 ) | ( (b) << 8 ) | ( (c) << 16 ) | ( (d) << 24 ) )
 
+/** Root System Description Pointer signature */
+#define RSDP_SIGNATURE { 'R', 'S', 'D', ' ', 'P', 'T', 'R', ' ' }
+
+/** Root System Description Pointer */
+struct acpi_rsdp {
+       /** Signature */
+       char signature[8];
+       /** To make sum of entire table == 0 */
+       uint8_t checksum;
+       /** OEM identification */
+       char oem_id[6];
+       /** Revision */
+       uint8_t revision;
+       /** Physical address of RSDT */
+       uint32_t rsdt;
+} __attribute__ (( packed ));
+
+/** EBDA RSDP length */
+#define RSDP_EBDA_LEN 0x400
+
+/** Fixed BIOS area RSDP start address */
+#define RSDP_BIOS_START 0xe0000
+
+/** Fixed BIOS area RSDP length */
+#define RSDP_BIOS_LEN 0x20000
+
+/** Stride at which to search for RSDP */
+#define RSDP_STRIDE 16
+
+/** Root System Description Table (RSDT) signature */
+#define RSDT_SIGNATURE ACPI_SIGNATURE ( 'R', 'S', 'D', 'T' )
+
+/** ACPI Root System Description Table (RSDT) */
+struct acpi_rsdt {
+       /** ACPI header */
+       struct acpi_description_header acpi;
+       /** ACPI table entries */
+       uint32_t entry[0];
+} __attribute__ (( packed ));
+
+/** Fixed ACPI Description Table (FADT) signature */
+#define FADT_SIGNATURE ACPI_SIGNATURE ( 'F', 'A', 'C', 'P' )
+
+/** Fixed ACPI Description Table (FADT) */
+struct acpi_fadt {
+       /** ACPI header */
+       struct acpi_description_header acpi;
+       /** Physical address of FACS */
+       uint32_t facs;
+       /** Physical address of DSDT */
+       uint32_t dsdt;
+       /** Unused by iPXE */
+       uint8_t unused[20];
+       /** PM1a Control Register Block */
+       uint32_t pm1a_cnt_blk;
+       /** PM1b Control Register Block */
+       uint32_t pm1b_cnt_blk;
+} __attribute__ (( packed ));
+
+/** ACPI PM1 Control Register (within PM1a_CNT_BLK or PM1A_CNT_BLK) */
+#define ACPI_PM1_CNT 0
+#define ACPI_PM1_CNT_SLP_TYP(x) ( (x) << 10 )  /**< Sleep type */
+#define ACPI_PM1_CNT_SLP_EN ( 1 << 13 )                /**< Sleep enable */
+
+/** Differentiated System Description Table (DSDT) signature */
+#define DSDT_SIGNATURE ACPI_SIGNATURE ( 'D', 'S', 'D', 'T' )
+
+/** Secondary System Description Table (SSDT) signature */
+#define SSDT_SIGNATURE ACPI_SIGNATURE ( 'S', 'S', 'D', 'T' )
+
 extern int acpi_describe ( struct interface *interface,
                           struct acpi_description_header *acpi, size_t len );
 #define acpi_describe_TYPE( object_type )                              \
@@ -59,5 +130,9 @@ extern int acpi_describe ( struct interface *interface,
                       size_t len ) )
 
 extern void acpi_fix_checksum ( struct acpi_description_header *acpi );
+extern userptr_t acpi_find_rsdt ( userptr_t ebda );
+extern userptr_t acpi_find ( userptr_t rsdt, uint32_t signature,
+                            unsigned int index );
+extern int acpi_sx ( userptr_t rsdt, uint32_t signature );
 
 #endif /* _IPXE_ACPI_H */