iPXE
acpi.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of the
7  * License, or any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17  * 02110-1301, USA.
18  *
19  * You can also choose to distribute this program under the terms of
20  * the Unmodified Binary Distribution Licence (as given in the file
21  * COPYING.UBDL), provided that you have satisfied its requirements.
22  */
23 
24 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25 
26 #include <string.h>
27 #include <errno.h>
28 #include <byteswap.h>
29 #include <ipxe/uaccess.h>
30 #include <ipxe/iomap.h>
31 #include <ipxe/acpi.h>
32 #include <ipxe/interface.h>
33 
34 /** @file
35  *
36  * ACPI support functions
37  *
38  */
39 
40 /** Colour for debug messages */
41 #define colour FADT_SIGNATURE
42 
43 /** ACPI table finder
44  *
45  * May be overridden at link time to inject tables for testing.
46  */
48 
49 /******************************************************************************
50  *
51  * Utility functions
52  *
53  ******************************************************************************
54  */
55 
56 /**
57  * Compute ACPI table checksum
58  *
59  * @v acpi Any ACPI table header
60  * @ret checksum 0 if checksum is good
61  */
62 static uint8_t acpi_checksum ( const struct acpi_header *acpi ) {
63  const uint8_t *byte = ( ( const void * ) acpi );
64  size_t len = le32_to_cpu ( acpi->length );
65  uint8_t sum = 0;
66 
67  /* Compute checksum */
68  while ( len-- )
69  sum += *(byte++);
70 
71  return sum;
72 }
73 
74 /**
75  * Fix up ACPI table checksum
76  *
77  * @v acpi ACPI table header
78  */
80 
81  /* Update checksum */
82  acpi->checksum -= acpi_checksum ( acpi );
83 }
84 
85 /**
86  * Locate ACPI table
87  *
88  * @v signature Requested table signature
89  * @v index Requested index of table with this signature
90  * @ret table Table, or NULL if not found
91  */
93  unsigned int index ) {
94 
95  return ( *acpi_finder ) ( signature, index );
96 }
97 
98 /**
99  * Locate ACPI table via RSDT
100  *
101  * @v signature Requested table signature
102  * @v index Requested index of table with this signature
103  * @ret table Table, or NULL if not found
104  */
106  unsigned int index ) {
107  const struct acpi_rsdt *rsdt;
108  const struct acpi_header *table;
109  size_t len;
110  unsigned int count;
111  unsigned int i;
112 
113  /* Locate RSDT */
114  rsdt = acpi_find_rsdt();
115  if ( ! rsdt ) {
116  DBG ( "RSDT not found\n" );
117  return NULL;
118  }
119 
120  /* Read RSDT header */
121  if ( rsdt->acpi.signature != cpu_to_le32 ( RSDT_SIGNATURE ) ) {
122  DBGC ( colour, "RSDT %#08lx has invalid signature:\n",
123  virt_to_phys ( rsdt ) );
124  DBGC_HDA ( colour, virt_to_phys ( rsdt ), &rsdt->acpi,
125  sizeof ( rsdt->acpi ) );
126  return NULL;
127  }
128  len = le32_to_cpu ( rsdt->acpi.length );
129  if ( len < sizeof ( rsdt->acpi ) ) {
130  DBGC ( colour, "RSDT %#08lx has invalid length:\n",
131  virt_to_phys ( rsdt ) );
132  DBGC_HDA ( colour, virt_to_phys ( rsdt ), &rsdt->acpi,
133  sizeof ( rsdt->acpi ) );
134  return NULL;
135  }
136 
137  /* Calculate number of entries */
138  count = ( ( len - sizeof ( rsdt->acpi ) ) /
139  sizeof ( rsdt->entry[0] ) );
140 
141  /* Search through entries */
142  for ( i = 0 ; i < count ; i++ ) {
143 
144  /* Read table header */
145  table = phys_to_virt ( rsdt->entry[i] );
146 
147  /* Check table signature */
148  if ( table->signature != cpu_to_le32 ( signature ) )
149  continue;
150 
151  /* Check index */
152  if ( index-- )
153  continue;
154 
155  /* Check table integrity */
156  if ( acpi_checksum ( table ) != 0 ) {
157  DBGC ( colour, "RSDT %#08lx found %s with bad "
158  "checksum at %#08lx\n", virt_to_phys ( rsdt ),
159  acpi_name ( signature ),
160  virt_to_phys ( table ) );
161  break;
162  }
163 
164  DBGC ( colour, "RSDT %#08lx found %s at %#08lx\n",
165  virt_to_phys ( rsdt ), acpi_name ( signature ),
166  virt_to_phys ( table ) );
167  return table;
168  }
169 
170  DBGC ( colour, "RSDT %#08lx could not find %s\n",
171  virt_to_phys ( rsdt ), acpi_name ( signature ) );
172  return NULL;
173 }
174 
175 /**
176  * Extract value from DSDT/SSDT
177  *
178  * @v zsdt DSDT or SSDT
179  * @v signature Signature (e.g. "_S5_")
180  * @v data Data buffer
181  * @v extract Extraction method
182  * @ret rc Return status code
183  */
184 static int acpi_zsdt ( const struct acpi_header *zsdt,
185  uint32_t signature, void *data,
186  int ( * extract ) ( const struct acpi_header *zsdt,
187  size_t len, size_t offset,
188  void *data ) ) {
189  uint32_t buf;
190  size_t offset;
191  size_t len;
192  int rc;
193 
194  /* Read table header */
195  len = le32_to_cpu ( zsdt->length );
196 
197  /* Locate signature */
198  for ( offset = sizeof ( *zsdt ) ;
199  ( ( offset + sizeof ( buf ) /* signature */ ) < len ) ;
200  offset++ ) {
201 
202  /* Check signature */
203  memcpy ( &buf, ( ( ( const void * ) zsdt ) + offset ),
204  sizeof ( buf ) );
205  if ( buf != cpu_to_le32 ( signature ) )
206  continue;
207  DBGC ( zsdt, "DSDT/SSDT %#08lx found %s at offset %#zx\n",
208  virt_to_phys ( zsdt ), acpi_name ( signature ),
209  offset );
210 
211  /* Attempt to extract data */
212  if ( ( rc = extract ( zsdt, len, offset, data ) ) == 0 )
213  return 0;
214  }
215 
216  return -ENOENT;
217 }
218 
219 /**
220  * Extract value from DSDT/SSDT
221  *
222  * @v signature Signature (e.g. "_S5_")
223  * @v data Data buffer
224  * @v extract Extraction method
225  * @ret rc Return status code
226  */
228  int ( * extract ) ( const struct acpi_header *zsdt,
229  size_t len, size_t offset,
230  void *data ) ) {
231  const struct acpi_fadt *fadt;
232  const struct acpi_header *dsdt;
233  const struct acpi_header *ssdt;
234  unsigned int i;
235  int rc;
236 
237  /* Try DSDT first */
238  fadt = container_of ( acpi_table ( FADT_SIGNATURE, 0 ),
239  struct acpi_fadt, acpi );
240  if ( fadt ) {
241  dsdt = phys_to_virt ( fadt->dsdt );
242  if ( ( rc = acpi_zsdt ( dsdt, signature, data,
243  extract ) ) == 0 )
244  return 0;
245  }
246 
247  /* Try all SSDTs */
248  for ( i = 0 ; ; i++ ) {
249  ssdt = acpi_table ( SSDT_SIGNATURE, i );
250  if ( ! ssdt )
251  break;
252  if ( ( rc = acpi_zsdt ( ssdt, signature, data,
253  extract ) ) == 0 )
254  return 0;
255  }
256 
257  DBGC ( colour, "ACPI could not find \"%s\"\n",
258  acpi_name ( signature ) );
259  return -ENOENT;
260 }
261 
262 /**
263  * Map an ACPI generic address
264  *
265  * @v address Generic address
266  * @v len Length of region
267  * @ret io_addr I/O address, or NULL on error
268  */
269 void * acpi_ioremap ( struct acpi_address *address, size_t len ) {
270  physaddr_t base = le64_to_cpu ( address->address );
271 
272  switch ( address->type ) {
274  return ioremap ( base, len );
276  return ( ( void * ) base );
277  default:
278  return NULL;
279  }
280 }
281 
282 /******************************************************************************
283  *
284  * Descriptors
285  *
286  ******************************************************************************
287  */
288 
289 /**
290  * Add ACPI descriptor
291  *
292  * @v desc ACPI descriptor
293  */
294 void acpi_add ( struct acpi_descriptor *desc ) {
295 
296  /* Add to list of descriptors */
297  ref_get ( desc->refcnt );
298  list_add_tail ( &desc->list, &desc->model->descs );
299 }
300 
301 /**
302  * Remove ACPI descriptor
303  *
304  * @v desc ACPI descriptor
305  */
306 void acpi_del ( struct acpi_descriptor *desc ) {
307 
308  /* Remove from list of descriptors */
309  list_check_contains_entry ( desc, &desc->model->descs, list );
310  list_del ( &desc->list );
311  ref_put ( desc->refcnt );
312 }
313 
314 /**
315  * Get object's ACPI descriptor
316  *
317  * @v intf Interface
318  * @ret desc ACPI descriptor, or NULL
319  */
320 struct acpi_descriptor * acpi_describe ( struct interface *intf ) {
321  struct interface *dest;
322  acpi_describe_TYPE ( void * ) *op =
324  void *object = intf_object ( dest );
325  struct acpi_descriptor *desc;
326 
327  if ( op ) {
328  desc = op ( object );
329  } else {
330  desc = NULL;
331  }
332 
333  intf_put ( dest );
334  return desc;
335 }
336 
337 /**
338  * Install ACPI tables
339  *
340  * @v install Table installation method
341  * @ret rc Return status code
342  */
343 int acpi_install ( int ( * install ) ( struct acpi_header *acpi ) ){
344  struct acpi_model *model;
345  int rc;
346 
347  for_each_table_entry ( model, ACPI_MODELS ) {
348  if ( ( rc = model->install ( install ) ) != 0 )
349  return rc;
350  }
351 
352  return 0;
353 }
#define __attribute__(x)
Definition: compiler.h:10
uint32_t base
Base.
Definition: librm.h:138
#define RSDT_SIGNATURE
Root System Description Table (RSDT) signature.
Definition: acpi.h:246
struct arbelprm_rc_send_wqe rc
Definition: arbel.h:14
uint32_t signature
ACPI signature (4 ASCII characters)
Definition: acpi.h:181
#define le32_to_cpu(value)
Definition: byteswap.h:113
const struct acpi_rsdt * acpi_find_rsdt(void)
Locate ACPI root system description table.
Error codes.
const struct acpi_header *(* acpi_finder)(uint32_t signature, unsigned int index)
const struct acpi_header * acpi_find_via_rsdt(uint32_t signature, unsigned int index)
Locate ACPI table via RSDT.
Definition: acpi.c:105
uint64_t address
Base address.
Definition: ena.h:24
#define DBGC(...)
Definition: compiler.h:505
#define SSDT_SIGNATURE
Secondary System Description Table (SSDT) signature.
Definition: acpi.h:291
long index
Definition: bigint.h:62
#define ENOENT
No such file or directory.
Definition: errno.h:514
FILE_LICENCE(GPL2_OR_LATER_OR_UBDL)
const struct acpi_header * acpi_table(uint32_t signature, unsigned int index)
Locate ACPI table.
Definition: acpi.c:92
static acpi_find(uint32_t signature, unsigned int index)
Locate ACPI table.
Definition: rsdp.h:26
int(* install)(int(*install)(struct acpi_header *acpi))
Install ACPI tables.
Definition: acpi.h:336
ACPI Root System Description Table (RSDT)
Definition: acpi.h:249
void * intf_object(struct interface *intf)
Get pointer to object containing object interface.
Definition: interface.c:159
struct interface * intf
Original interface.
Definition: interface.h:158
void acpi_del(struct acpi_descriptor *desc)
Remove ACPI descriptor.
Definition: acpi.c:306
#define list_del(list)
Delete an entry from a list.
Definition: list.h:119
struct ena_llq_option desc
Descriptor counts.
Definition: ena.h:20
void * memcpy(void *dest, const void *src, size_t len) __nonnull
#define ACPI_ADDRESS_TYPE_IO
An I/O address space type.
Definition: acpi.h:39
#define container_of(ptr, type, field)
Get containing structure.
Definition: stddef.h:35
Access to external ("user") memory.
An object interface.
Definition: interface.h:124
#define colour
Colour for debug messages.
Definition: acpi.c:41
Fixed ACPI Description Table (FADT)
Definition: acpi.h:260
An ACPI table model.
Definition: acpi.h:320
uint32_t length
Length of table, in bytes, including header.
Definition: acpi.h:183
#define DBGC_HDA(...)
Definition: compiler.h:506
Object interfaces.
#define list_add_tail(new, head)
Add a new entry to the tail of a list.
Definition: list.h:93
static EFI_ACPI_TABLE_PROTOCOL * acpi
ACPI table protocol protocol.
Definition: efi_block.c:66
ring len
Length.
Definition: dwmac.h:231
uint32_t entry[0]
ACPI table entries.
Definition: acpi.h:253
#define FADT_SIGNATURE
Fixed ACPI Description Table (FADT) signature.
Definition: acpi.h:257
static unsigned int count
Number of entries.
Definition: dwmac.h:225
void acpi_fix_checksum(struct acpi_header *acpi)
Fix up ACPI table checksum.
Definition: acpi.c:79
#define cpu_to_le32(value)
Definition: byteswap.h:107
int acpi_install(int(*install)(struct acpi_header *acpi))
Install ACPI tables.
Definition: acpi.c:343
ACPI data structures.
#define ref_get(refcnt)
Get additional reference to object.
Definition: refcnt.h:92
#define for_each_table_entry(pointer, table)
Iterate through all entries within a linker table.
Definition: tables.h:385
unsigned char uint8_t
Definition: stdint.h:10
An ACPI description header.
Definition: acpi.h:179
unsigned int uint32_t
Definition: stdint.h:12
struct acpi_descriptor * acpi_describe(struct interface *intf)
Get object's ACPI descriptor.
Definition: acpi.c:320
#define acpi_describe_TYPE(object_type)
Definition: acpi.h:404
struct acpi_header acpi
ACPI header.
Definition: acpi.h:251
unsigned long physaddr_t
Definition: stdint.h:20
static uint16_t struct vmbus_xfer_pages_operations * op
Definition: netvsc.h:327
An ACPI descriptor (used to construct ACPI tables)
Definition: acpi.h:294
uint32_t dsdt
Physical address of DSDT.
Definition: acpi.h:266
void * acpi_ioremap(struct acpi_address *address, size_t len)
Map an ACPI generic address.
Definition: acpi.c:269
#define ACPI_ADDRESS_TYPE_MEM
A memory address space type.
Definition: acpi.h:36
An ACPI generic address structure.
Definition: acpi.h:22
void intf_put(struct interface *intf)
Decrement reference count on an object interface.
Definition: interface.c:149
static const char * acpi_name(uint32_t signature)
Transcribe ACPI table signature (for debugging)
Definition: acpi.h:206
if(len >=6 *4) __asm__ __volatile__("movsl" if(len >=5 *4) __asm__ __volatile__("movsl" if(len >=4 *4) __asm__ __volatile__("movsl" if(len >=3 *4) __asm__ __volatile__("movsl" if(len >=2 *4) __asm__ __volatile__("movsl" if(len >=1 *4) __asm__ __volatile__("movsl" if((len % 4) >=2) __asm__ __volatile__("movsw" if((len % 2) >=1) __asm__ __volatile__("movsb" return dest
Definition: string.h:150
uint8_t data[48]
Additional event data.
Definition: ena.h:22
#define ACPI_MODELS
ACPI models.
Definition: acpi.h:340
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
static int acpi_zsdt(const struct acpi_header *zsdt, 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:184
typeof(acpi_finder=acpi_find)
ACPI table finder.
Definition: acpi.c:47
uint16_t offset
Offset to command line.
Definition: bzimage.h:8
#define DBG(...)
Print a debugging message.
Definition: compiler.h:498
void * ioremap(unsigned long bus_addr, size_t len)
Map bus address as an I/O address.
#define le64_to_cpu(value)
Definition: byteswap.h:114
#define list_check_contains_entry(entry, head, member)
Check list contains a specified entry.
Definition: list.h:549
u8 signature
CPU signature.
Definition: CIB_PRM.h:35
void acpi_add(struct acpi_descriptor *desc)
Add ACPI descriptor.
Definition: acpi.c:294
#define NULL
NULL pointer (VOID *)
Definition: Base.h:321
String functions.
#define intf_get_dest_op(intf, type, dest)
Get object interface destination and operation method.
Definition: interface.h:269
iPXE I/O mapping API
#define ref_put(refcnt)
Drop reference to object.
Definition: refcnt.h:106