iPXE
acpipwr.c File Reference

ACPI power off. More...

#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <byteswap.h>
#include <ipxe/io.h>
#include <ipxe/acpi.h>
#include <ipxe/acpipwr.h>

Go to the source code of this file.

Macros

#define colour   FADT_SIGNATURE
 Colour for debug messages.
#define S5_SIGNATURE   ACPI_SIGNATURE ( '_', 'S', '5', '_' )
 S5 signature

Functions

 FILE_LICENCE (GPL2_OR_LATER_OR_UBDL)
static int acpi_extract_sx (const struct acpi_header *zsdt, size_t len, size_t offset, void *data)
 Extract _Sx value from DSDT/SSDT.
int acpi_poweroff (void)
 Power off the computer using ACPI.

Detailed Description

ACPI power off.

Definition in file acpipwr.c.

Macro Definition Documentation

◆ colour

#define colour   FADT_SIGNATURE

Colour for debug messages.

Definition at line 41 of file acpipwr.c.

◆ S5_SIGNATURE

#define S5_SIGNATURE   ACPI_SIGNATURE ( '_', 'S', '5', '_' )

S5 signature

Definition at line 44 of file acpipwr.c.

Referenced by acpi_poweroff().

Function Documentation

◆ FILE_LICENCE()

FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )

◆ acpi_extract_sx()

int acpi_extract_sx ( const struct acpi_header * zsdt,
size_t len,
size_t offset,
void * data )
static

Extract _Sx value from DSDT/SSDT.

Parameters
zsdtDSDT or SSDT
lenLength of DSDT/SSDT
offsetOffset of signature within DSDT/SSDT
dataData buffer
Return values
rcReturn status code

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.

Definition at line 66 of file acpipwr.c.

67 {
68 unsigned int *sx = data;
69 uint8_t bytes[4];
71
72 /* Skip signature and package header */
73 offset += ( 4 /* signature */ + 3 /* package header */ );
74
75 /* Sanity check */
76 if ( ( offset + sizeof ( bytes ) /* value */ ) > len ) {
77 return -EINVAL;
78 }
79
80 /* Read first four bytes of value */
81 memcpy ( bytes, ( ( ( const void * ) zsdt ) + offset ),
82 sizeof ( bytes ) );
83 DBGC ( colour, "ACPI found \\_Sx containing %02x:%02x:%02x:%02x\n",
84 bytes[0], bytes[1], bytes[2], bytes[3] );
85
86 /* Extract \Sx value. There are three potential encodings
87 * that we might encounter:
88 *
89 * - SLP_TYPa, SLP_TYPb, rsvd, rsvd
90 *
91 * - <byteprefix>, SLP_TYPa, <byteprefix>, SLP_TYPb, ...
92 *
93 * - <dwordprefix>, SLP_TYPa, SLP_TYPb, 0, 0
94 *
95 * Since <byteprefix> and <dwordprefix> both have bit 3 set,
96 * and valid SLP_TYPx must have bit 3 clear (since SLP_TYPx is
97 * a 3-bit field), we can just skip any bytes with bit 3 set.
98 */
99 byte = bytes;
100 if ( *byte & 0x08 )
101 byte++;
102 *sx = *(byte++);
103 if ( *byte & 0x08 )
104 byte++;
105 *sx |= ( *byte << 8 );
106
107 return 0;
108}
#define colour
Colour for debug messages.
Definition acpi.c:42
unsigned char uint8_t
Definition stdint.h:10
uint16_t offset
Offset to command line.
Definition bzimage.h:3
ring len
Length.
Definition dwmac.h:226
uint8_t data[48]
Additional event data.
Definition ena.h:11
#define DBGC(...)
Definition compiler.h:505
#define EINVAL
Invalid argument.
Definition errno.h:429
uint8_t bytes[64]
Definition ib_mad.h:5
void * memcpy(void *dest, const void *src, size_t len) __nonnull
unsigned char byte
Definition smc9000.h:38

References bytes, colour, data, DBGC, EINVAL, len, memcpy(), and offset.

Referenced by acpi_poweroff().

◆ acpi_poweroff()

int acpi_poweroff ( void )

Power off the computer using ACPI.

Return values
rcReturn status code

Definition at line 115 of file acpipwr.c.

115 {
116 const struct acpi_fadt *fadt;
117 unsigned int pm1a_cnt_blk;
118 unsigned int pm1b_cnt_blk;
119 unsigned int pm1a_cnt;
120 unsigned int pm1b_cnt;
121 unsigned int slp_typa;
122 unsigned int slp_typb;
123 unsigned int s5;
124 int rc;
125
126 /* Locate FADT */
127 fadt = container_of ( acpi_table ( FADT_SIGNATURE, 0 ),
128 struct acpi_fadt, acpi );
129 if ( ! fadt ) {
130 DBGC ( colour, "ACPI could not find FADT\n" );
131 return -ENOENT;
132 }
133
134 /* Read FADT */
137 pm1a_cnt = ( pm1a_cnt_blk + ACPI_PM1_CNT );
138 pm1b_cnt = ( pm1b_cnt_blk + ACPI_PM1_CNT );
139
140 /* Extract \_S5 from DSDT or any SSDT */
141 if ( ( rc = acpi_extract ( S5_SIGNATURE, &s5,
142 acpi_extract_sx ) ) != 0 ) {
143 DBGC ( colour, "ACPI could not extract \\_S5: %s\n",
144 strerror ( rc ) );
145 return rc;
146 }
147
148 /* Power off system */
149 if ( pm1a_cnt_blk ) {
150 slp_typa = ( ( s5 >> 0 ) & 0xff );
151 DBGC ( colour, "ACPI PM1a sleep type %#x => %04x\n",
152 slp_typa, pm1a_cnt );
153 outw ( ( ACPI_PM1_CNT_SLP_TYP ( slp_typa ) |
154 ACPI_PM1_CNT_SLP_EN ), pm1a_cnt );
155 }
156 if ( pm1b_cnt_blk ) {
157 slp_typb = ( ( s5 >> 8 ) & 0xff );
158 DBGC ( colour, "ACPI PM1b sleep type %#x => %04x\n",
159 slp_typb, pm1b_cnt );
160 outw ( ( ACPI_PM1_CNT_SLP_TYP ( slp_typb ) |
161 ACPI_PM1_CNT_SLP_EN ), pm1b_cnt );
162 }
163
164 /* On some systems, execution will continue briefly. Delay to
165 * avoid potentially confusing log messages.
166 */
167 mdelay ( 1000 );
168
169 DBGC ( colour, "ACPI power off failed\n" );
170 return -EPROTO;
171}
const struct acpi_header * acpi_table(uint32_t signature, unsigned int index)
Locate ACPI table.
Definition acpi.c:93
int acpi_extract(uint32_t signature, void *data, int(*extract)(const struct acpi_header *zsdt, size_t len, size_t offset, void *data))
Extract value from DSDT/SSDT.
Definition acpi.c:228
#define S5_SIGNATURE
S5 signature
Definition acpipwr.c:44
static int acpi_extract_sx(const struct acpi_header *zsdt, size_t len, size_t offset, void *data)
Extract _Sx value from DSDT/SSDT.
Definition acpipwr.c:66
struct arbelprm_rc_send_wqe rc
Definition arbel.h:3
static EFI_ACPI_TABLE_PROTOCOL * acpi
ACPI table protocol protocol.
Definition efi_block.c:67
#define ENOENT
No such file or directory.
Definition errno.h:515
#define EPROTO
Protocol error.
Definition errno.h:625
#define le32_to_cpu(value)
Definition byteswap.h:114
#define FADT_SIGNATURE
Fixed ACPI Description Table (FADT) signature.
Definition acpi.h:258
#define ACPI_PM1_CNT_SLP_TYP(x)
Sleep type.
Definition acpi.h:282
#define ACPI_PM1_CNT_SLP_EN
Sleep enable.
Definition acpi.h:283
#define ACPI_PM1_CNT
ACPI PM1 Control Register (within PM1a_CNT_BLK or PM1A_CNT_BLK)
Definition acpi.h:281
#define outw(data, io_addr)
Definition io.h:320
#define container_of(ptr, type, field)
Get containing structure.
Definition stddef.h:36
char * strerror(int errno)
Retrieve string representation of error number.
Definition strerror.c:79
Fixed ACPI Description Table (FADT)
Definition acpi.h:261
uint32_t pm1a_cnt_blk
PM1a Control Register Block.
Definition acpi.h:271
uint32_t pm1b_cnt_blk
PM1b Control Register Block.
Definition acpi.h:273
void mdelay(unsigned long msecs)
Delay for a fixed number of milliseconds.
Definition timer.c:79

References acpi, acpi_extract(), acpi_extract_sx(), ACPI_PM1_CNT, ACPI_PM1_CNT_SLP_EN, ACPI_PM1_CNT_SLP_TYP, acpi_table(), colour, container_of, DBGC, ENOENT, EPROTO, FADT_SIGNATURE, le32_to_cpu, mdelay(), outw, acpi_fadt::pm1a_cnt_blk, acpi_fadt::pm1b_cnt_blk, rc, S5_SIGNATURE, and strerror().

Referenced by bios_poweroff().