iPXE
Macros | Functions
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. More...
 
#define S5_SIGNATURE   ACPI_SIGNATURE ( '_', 'S', '5', '_' )
 S5 signature More...
 

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. More...
 
int acpi_poweroff (void)
 Power off the computer using ACPI. More...
 

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.

Function Documentation

◆ FILE_LICENCE()

FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL  )

◆ acpi_extract_sx()

static 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];
70  uint8_t *byte;
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 EINVAL
Invalid argument.
Definition: errno.h:428
#define DBGC(...)
Definition: compiler.h:505
#define colour
Colour for debug messages.
Definition: acpipwr.c:41
void * memcpy(void *dest, const void *src, size_t len) __nonnull
ring len
Length.
Definition: dwmac.h:231
unsigned char uint8_t
Definition: stdint.h:10
unsigned char byte
Definition: smc9000.h:38
uint8_t data[48]
Additional event data.
Definition: ena.h:22
uint16_t offset
Offset to command line.
Definition: bzimage.h:8
uint8_t bytes[64]
Definition: ib_mad.h:16

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 }
struct arbelprm_rc_send_wqe rc
Definition: arbel.h:14
#define le32_to_cpu(value)
Definition: byteswap.h:113
#define outw(data, io_addr)
Definition: io.h:319
#define ACPI_PM1_CNT
ACPI PM1 Control Register (within PM1a_CNT_BLK or PM1A_CNT_BLK)
Definition: acpi.h:280
#define DBGC(...)
Definition: compiler.h:505
#define ENOENT
No such file or directory.
Definition: errno.h:514
const struct acpi_header * acpi_table(uint32_t signature, unsigned int index)
Locate ACPI table.
Definition: acpi.c:92
#define colour
Colour for debug messages.
Definition: acpipwr.c:41
#define container_of(ptr, type, field)
Get containing structure.
Definition: stddef.h:35
Fixed ACPI Description Table (FADT)
Definition: acpi.h:260
static EFI_ACPI_TABLE_PROTOCOL * acpi
ACPI table protocol protocol.
Definition: efi_block.c:66
#define FADT_SIGNATURE
Fixed ACPI Description Table (FADT) signature.
Definition: acpi.h:257
uint32_t pm1a_cnt_blk
PM1a Control Register Block.
Definition: acpi.h:270
#define ACPI_PM1_CNT_SLP_EN
Sleep enable.
Definition: acpi.h:282
#define EPROTO
Protocol error.
Definition: errno.h:624
char * strerror(int errno)
Retrieve string representation of error number.
Definition: strerror.c:78
void mdelay(unsigned long msecs)
Delay for a fixed number of milliseconds.
Definition: timer.c:78
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
#define ACPI_PM1_CNT_SLP_TYP(x)
Sleep type.
Definition: acpi.h:281
uint32_t pm1b_cnt_blk
PM1b Control Register Block.
Definition: acpi.h:272
#define S5_SIGNATURE
S5 signature
Definition: acpipwr.c:44
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:227

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().