iPXE
Macros | Functions
acpipwr.c File Reference

ACPI power off. More...

#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 (userptr_t 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 40 of file acpipwr.c.

◆ S5_SIGNATURE

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

S5 signature

Definition at line 43 of file acpipwr.c.

Function Documentation

◆ FILE_LICENCE()

FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL  )

◆ acpi_extract_sx()

static int acpi_extract_sx ( userptr_t  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 65 of file acpipwr.c.

66  {
67  unsigned int *sx = data;
68  uint8_t bytes[4];
69  uint8_t *byte;
70 
71  /* Skip signature and package header */
72  offset += ( 4 /* signature */ + 3 /* package header */ );
73 
74  /* Sanity check */
75  if ( ( offset + sizeof ( bytes ) /* value */ ) > len ) {
76  return -EINVAL;
77  }
78 
79  /* Read first four bytes of value */
80  copy_from_user ( bytes, zsdt, offset, sizeof ( bytes ) );
81  DBGC ( colour, "ACPI found \\_Sx containing %02x:%02x:%02x:%02x\n",
82  bytes[0], bytes[1], bytes[2], bytes[3] );
83 
84  /* Extract \Sx value. There are three potential encodings
85  * that we might encounter:
86  *
87  * - SLP_TYPa, SLP_TYPb, rsvd, rsvd
88  *
89  * - <byteprefix>, SLP_TYPa, <byteprefix>, SLP_TYPb, ...
90  *
91  * - <dwordprefix>, SLP_TYPa, SLP_TYPb, 0, 0
92  *
93  * Since <byteprefix> and <dwordprefix> both have bit 3 set,
94  * and valid SLP_TYPx must have bit 3 clear (since SLP_TYPx is
95  * a 3-bit field), we can just skip any bytes with bit 3 set.
96  */
97  byte = bytes;
98  if ( *byte & 0x08 )
99  byte++;
100  *sx = *(byte++);
101  if ( *byte & 0x08 )
102  byte++;
103  *sx |= ( *byte << 8 );
104 
105  return 0;
106 }
#define EINVAL
Invalid argument.
Definition: errno.h:428
static __always_inline void copy_from_user(void *dest, userptr_t src, off_t src_off, size_t len)
Copy data from user buffer.
Definition: uaccess.h:337
#define DBGC(...)
Definition: compiler.h:505
#define colour
Colour for debug messages.
Definition: acpipwr.c:40
static userptr_t size_t offset
Offset of the first segment within the content.
Definition: deflate.h:259
unsigned char uint8_t
Definition: stdint.h:10
unsigned char byte
Definition: smc9000.h:38
uint32_t len
Length.
Definition: ena.h:14
struct arbelprm_port_state_change_st data
Message.
Definition: arbel.h:12
uint8_t bytes[64]
Definition: ib_mad.h:16

References bytes, colour, copy_from_user(), data, DBGC, EINVAL, len, 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 113 of file acpipwr.c.

113  {
114  struct acpi_fadt fadtab;
115  userptr_t fadt;
116  unsigned int pm1a_cnt_blk;
117  unsigned int pm1b_cnt_blk;
118  unsigned int pm1a_cnt;
119  unsigned int pm1b_cnt;
120  unsigned int slp_typa;
121  unsigned int slp_typb;
122  unsigned int s5;
123  int rc;
124 
125  /* Locate FADT */
126  fadt = acpi_table ( FADT_SIGNATURE, 0 );
127  if ( ! fadt ) {
128  DBGC ( colour, "ACPI could not find FADT\n" );
129  return -ENOENT;
130  }
131 
132  /* Read FADT */
133  copy_from_user ( &fadtab, fadt, 0, sizeof ( fadtab ) );
134  pm1a_cnt_blk = le32_to_cpu ( fadtab.pm1a_cnt_blk );
135  pm1b_cnt_blk = le32_to_cpu ( fadtab.pm1b_cnt_blk );
136  pm1a_cnt = ( pm1a_cnt_blk + ACPI_PM1_CNT );
137  pm1b_cnt = ( pm1b_cnt_blk + ACPI_PM1_CNT );
138 
139  /* Extract \_S5 from DSDT or any SSDT */
140  if ( ( rc = acpi_extract ( S5_SIGNATURE, &s5,
141  acpi_extract_sx ) ) != 0 ) {
142  DBGC ( colour, "ACPI could not extract \\_S5: %s\n",
143  strerror ( rc ) );
144  return rc;
145  }
146 
147  /* Power off system */
148  if ( pm1a_cnt_blk ) {
149  slp_typa = ( ( s5 >> 0 ) & 0xff );
150  DBGC ( colour, "ACPI PM1a sleep type %#x => %04x\n",
151  slp_typa, pm1a_cnt );
152  outw ( ( ACPI_PM1_CNT_SLP_TYP ( slp_typa ) |
153  ACPI_PM1_CNT_SLP_EN ), pm1a_cnt );
154  }
155  if ( pm1b_cnt_blk ) {
156  slp_typb = ( ( s5 >> 8 ) & 0xff );
157  DBGC ( colour, "ACPI PM1b sleep type %#x => %04x\n",
158  slp_typb, pm1b_cnt );
159  outw ( ( ACPI_PM1_CNT_SLP_TYP ( slp_typb ) |
160  ACPI_PM1_CNT_SLP_EN ), pm1b_cnt );
161  }
162 
163  /* On some systems, execution will continue briefly. Delay to
164  * avoid potentially confusing log messages.
165  */
166  mdelay ( 1000 );
167 
168  DBGC ( colour, "ACPI power off failed\n" );
169  return -EPROTO;
170 }
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:264
static int acpi_extract_sx(userptr_t zsdt, size_t len, size_t offset, void *data)
Extract _Sx value from DSDT/SSDT.
Definition: acpipwr.c:65
static __always_inline void copy_from_user(void *dest, userptr_t src, off_t src_off, size_t len)
Copy data from user buffer.
Definition: uaccess.h:337
#define DBGC(...)
Definition: compiler.h:505
userptr_t acpi_table(uint32_t signature, unsigned int index)
Locate ACPI table.
Definition: acpi.c:98
#define ENOENT
No such file or directory.
Definition: errno.h:514
#define colour
Colour for debug messages.
Definition: acpipwr.c:40
int acpi_extract(uint32_t signature, void *data, int(*extract)(userptr_t zsdt, size_t len, size_t offset, void *data))
Extract value from DSDT/SSDT.
Definition: acpi.c:240
Fixed ACPI Description Table (FADT)
Definition: acpi.h:244
#define FADT_SIGNATURE
Fixed ACPI Description Table (FADT) signature.
Definition: acpi.h:241
uint32_t pm1a_cnt_blk
PM1a Control Register Block.
Definition: acpi.h:254
#define ACPI_PM1_CNT_SLP_EN
Sleep enable.
Definition: acpi.h:266
#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
#define ACPI_PM1_CNT_SLP_TYP(x)
Sleep type.
Definition: acpi.h:265
uint32_t pm1b_cnt_blk
PM1b Control Register Block.
Definition: acpi.h:256
#define S5_SIGNATURE
S5 signature
Definition: acpipwr.c:43
unsigned long userptr_t
A pointer to a user buffer.
Definition: uaccess.h:33

References acpi_extract(), acpi_extract_sx(), ACPI_PM1_CNT, ACPI_PM1_CNT_SLP_EN, ACPI_PM1_CNT_SLP_TYP, acpi_table(), colour, copy_from_user(), 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().