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 FILE_SECBOOT ( PERMITTED );
26 
27 #include <string.h>
28 #include <errno.h>
29 #include <byteswap.h>
30 #include <ipxe/uaccess.h>
31 #include <ipxe/iomap.h>
32 #include <ipxe/acpi.h>
33 #include <ipxe/interface.h>
34 
35 /** @file
36  *
37  * ACPI support functions
38  *
39  */
40 
41 /** Colour for debug messages */
42 #define colour FADT_SIGNATURE
43 
44 /** ACPI table finder
45  *
46  * May be overridden at link time to inject tables for testing.
47  */
49 
50 /******************************************************************************
51  *
52  * Utility functions
53  *
54  ******************************************************************************
55  */
56 
57 /**
58  * Compute ACPI table checksum
59  *
60  * @v acpi Any ACPI table header
61  * @ret checksum 0 if checksum is good
62  */
63 static uint8_t acpi_checksum ( const struct acpi_header *acpi ) {
64  const uint8_t *byte = ( ( const void * ) acpi );
65  size_t len = le32_to_cpu ( acpi->length );
66  uint8_t sum = 0;
67 
68  /* Compute checksum */
69  while ( len-- )
70  sum += *(byte++);
71 
72  return sum;
73 }
74 
75 /**
76  * Fix up ACPI table checksum
77  *
78  * @v acpi ACPI table header
79  */
81 
82  /* Update checksum */
83  acpi->checksum -= acpi_checksum ( acpi );
84 }
85 
86 /**
87  * Locate ACPI table
88  *
89  * @v signature Requested table signature
90  * @v index Requested index of table with this signature
91  * @ret table Table, or NULL if not found
92  */
94  unsigned int index ) {
95 
96  return ( *acpi_finder ) ( signature, index );
97 }
98 
99 /**
100  * Locate ACPI table via RSDT
101  *
102  * @v signature Requested table signature
103  * @v index Requested index of table with this signature
104  * @ret table Table, or NULL if not found
105  */
107  unsigned int index ) {
108  const struct acpi_rsdt *rsdt;
109  const struct acpi_header *table;
110  size_t len;
111  unsigned int count;
112  unsigned int i;
113 
114  /* Locate RSDT */
115  rsdt = acpi_find_rsdt();
116  if ( ! rsdt ) {
117  DBG ( "RSDT not found\n" );
118  return NULL;
119  }
120 
121  /* Read RSDT header */
122  if ( rsdt->acpi.signature != cpu_to_le32 ( RSDT_SIGNATURE ) ) {
123  DBGC ( colour, "RSDT %#08lx has invalid signature:\n",
124  virt_to_phys ( rsdt ) );
125  DBGC_HDA ( colour, virt_to_phys ( rsdt ), &rsdt->acpi,
126  sizeof ( rsdt->acpi ) );
127  return NULL;
128  }
129  len = le32_to_cpu ( rsdt->acpi.length );
130  if ( len < sizeof ( rsdt->acpi ) ) {
131  DBGC ( colour, "RSDT %#08lx has invalid length:\n",
132  virt_to_phys ( rsdt ) );
133  DBGC_HDA ( colour, virt_to_phys ( rsdt ), &rsdt->acpi,
134  sizeof ( rsdt->acpi ) );
135  return NULL;
136  }
137 
138  /* Calculate number of entries */
139  count = ( ( len - sizeof ( rsdt->acpi ) ) /
140  sizeof ( rsdt->entry[0] ) );
141 
142  /* Search through entries */
143  for ( i = 0 ; i < count ; i++ ) {
144 
145  /* Read table header */
146  table = phys_to_virt ( rsdt->entry[i] );
147 
148  /* Check table signature */
149  if ( table->signature != cpu_to_le32 ( signature ) )
150  continue;
151 
152  /* Check index */
153  if ( index-- )
154  continue;
155 
156  /* Check table integrity */
157  if ( acpi_checksum ( table ) != 0 ) {
158  DBGC ( colour, "RSDT %#08lx found %s with bad "
159  "checksum at %#08lx\n", virt_to_phys ( rsdt ),
160  acpi_name ( signature ),
161  virt_to_phys ( table ) );
162  break;
163  }
164 
165  DBGC ( colour, "RSDT %#08lx found %s at %#08lx\n",
166  virt_to_phys ( rsdt ), acpi_name ( signature ),
167  virt_to_phys ( table ) );
168  return table;
169  }
170 
171  DBGC ( colour, "RSDT %#08lx could not find %s\n",
172  virt_to_phys ( rsdt ), acpi_name ( signature ) );
173  return NULL;
174 }
175 
176 /**
177  * Extract value from DSDT/SSDT
178  *
179  * @v zsdt DSDT or SSDT
180  * @v signature Signature (e.g. "_S5_")
181  * @v data Data buffer
182  * @v extract Extraction method
183  * @ret rc Return status code
184  */
185 static int acpi_zsdt ( const struct acpi_header *zsdt,
186  uint32_t signature, void *data,
187  int ( * extract ) ( const struct acpi_header *zsdt,
188  size_t len, size_t offset,
189  void *data ) ) {
190  uint32_t buf;
191  size_t offset;
192  size_t len;
193  int rc;
194 
195  /* Read table header */
196  len = le32_to_cpu ( zsdt->length );
197 
198  /* Locate signature */
199  for ( offset = sizeof ( *zsdt ) ;
200  ( ( offset + sizeof ( buf ) /* signature */ ) < len ) ;
201  offset++ ) {
202 
203  /* Check signature */
204  memcpy ( &buf, ( ( ( const void * ) zsdt ) + offset ),
205  sizeof ( buf ) );
206  if ( buf != cpu_to_le32 ( signature ) )
207  continue;
208  DBGC ( zsdt, "DSDT/SSDT %#08lx found %s at offset %#zx\n",
209  virt_to_phys ( zsdt ), acpi_name ( signature ),
210  offset );
211 
212  /* Attempt to extract data */
213  if ( ( rc = extract ( zsdt, len, offset, data ) ) == 0 )
214  return 0;
215  }
216 
217  return -ENOENT;
218 }
219 
220 /**
221  * Extract value from DSDT/SSDT
222  *
223  * @v signature Signature (e.g. "_S5_")
224  * @v data Data buffer
225  * @v extract Extraction method
226  * @ret rc Return status code
227  */
229  int ( * extract ) ( const struct acpi_header *zsdt,
230  size_t len, size_t offset,
231  void *data ) ) {
232  const struct acpi_fadt *fadt;
233  const struct acpi_header *dsdt;
234  const struct acpi_header *ssdt;
235  unsigned int i;
236  int rc;
237 
238  /* Try DSDT first */
239  fadt = container_of ( acpi_table ( FADT_SIGNATURE, 0 ),
240  struct acpi_fadt, acpi );
241  if ( fadt ) {
242  dsdt = phys_to_virt ( fadt->dsdt );
243  if ( ( rc = acpi_zsdt ( dsdt, signature, data,
244  extract ) ) == 0 )
245  return 0;
246  }
247 
248  /* Try all SSDTs */
249  for ( i = 0 ; ; i++ ) {
250  ssdt = acpi_table ( SSDT_SIGNATURE, i );
251  if ( ! ssdt )
252  break;
253  if ( ( rc = acpi_zsdt ( ssdt, signature, data,
254  extract ) ) == 0 )
255  return 0;
256  }
257 
258  DBGC ( colour, "ACPI could not find \"%s\"\n",
259  acpi_name ( signature ) );
260  return -ENOENT;
261 }
262 
263 /**
264  * Map an ACPI generic address
265  *
266  * @v address Generic address
267  * @v len Length of region
268  * @ret io_addr I/O address, or NULL on error
269  */
270 void * acpi_ioremap ( struct acpi_address *address, size_t len ) {
271  physaddr_t base = le64_to_cpu ( address->address );
272 
273  switch ( address->type ) {
275  return ioremap ( base, len );
277  return ( ( void * ) base );
278  default:
279  return NULL;
280  }
281 }
282 
283 /******************************************************************************
284  *
285  * Descriptors
286  *
287  ******************************************************************************
288  */
289 
290 /**
291  * Add ACPI descriptor
292  *
293  * @v desc ACPI descriptor
294  */
295 void acpi_add ( struct acpi_descriptor *desc ) {
296 
297  /* Add to list of descriptors */
298  ref_get ( desc->refcnt );
299  list_add_tail ( &desc->list, &desc->model->descs );
300 }
301 
302 /**
303  * Remove ACPI descriptor
304  *
305  * @v desc ACPI descriptor
306  */
307 void acpi_del ( struct acpi_descriptor *desc ) {
308 
309  /* Remove from list of descriptors */
310  list_check_contains_entry ( desc, &desc->model->descs, list );
311  list_del ( &desc->list );
312  ref_put ( desc->refcnt );
313 }
314 
315 /**
316  * Get object's ACPI descriptor
317  *
318  * @v intf Interface
319  * @ret desc ACPI descriptor, or NULL
320  */
321 struct acpi_descriptor * acpi_describe ( struct interface *intf ) {
322  struct interface *dest;
323  acpi_describe_TYPE ( void * ) *op =
325  void *object = intf_object ( dest );
326  struct acpi_descriptor *desc;
327 
328  if ( op ) {
329  desc = op ( object );
330  } else {
331  desc = NULL;
332  }
333 
334  intf_put ( dest );
335  return desc;
336 }
337 
338 /**
339  * Install ACPI tables
340  *
341  * @v install Table installation method
342  * @ret rc Return status code
343  */
344 int acpi_install ( int ( * install ) ( struct acpi_header *acpi ) ){
345  struct acpi_model *model;
346  int rc;
347 
348  for_each_table_entry ( model, ACPI_MODELS ) {
349  if ( ( rc = model->install ( install ) ) != 0 )
350  return rc;
351  }
352 
353  return 0;
354 }
#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:247
struct arbelprm_rc_send_wqe rc
Definition: arbel.h:14
FILE_SECBOOT(PERMITTED)
uint32_t signature
ACPI signature (4 ASCII characters)
Definition: acpi.h:182
#define le32_to_cpu(value)
Definition: byteswap.h:114
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:106
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:292
long index
Definition: bigint.h:65
#define ENOENT
No such file or directory.
Definition: errno.h:515
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:93
static acpi_find(uint32_t signature, unsigned int index)
Locate ACPI table.
Definition: rsdp.h:27
int(* install)(int(*install)(struct acpi_header *acpi))
Install ACPI tables.
Definition: acpi.h:337
ACPI Root System Description Table (RSDT)
Definition: acpi.h:250
void * intf_object(struct interface *intf)
Get pointer to object containing object interface.
Definition: interface.c:160
struct interface * intf
Original interface.
Definition: interface.h:159
void acpi_del(struct acpi_descriptor *desc)
Remove ACPI descriptor.
Definition: acpi.c:307
#define list_del(list)
Delete an entry from a list.
Definition: list.h:120
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:40
#define container_of(ptr, type, field)
Get containing structure.
Definition: stddef.h:36
Access to external ("user") memory.
An object interface.
Definition: interface.h:125
#define colour
Colour for debug messages.
Definition: acpi.c:42
Fixed ACPI Description Table (FADT)
Definition: acpi.h:261
An ACPI table model.
Definition: acpi.h:321
uint32_t length
Length of table, in bytes, including header.
Definition: acpi.h:184
#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:94
static EFI_ACPI_TABLE_PROTOCOL * acpi
ACPI table protocol protocol.
Definition: efi_block.c:67
ring len
Length.
Definition: dwmac.h:231
uint32_t entry[0]
ACPI table entries.
Definition: acpi.h:254
#define FADT_SIGNATURE
Fixed ACPI Description Table (FADT) signature.
Definition: acpi.h:258
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:80
#define cpu_to_le32(value)
Definition: byteswap.h:108
int acpi_install(int(*install)(struct acpi_header *acpi))
Install ACPI tables.
Definition: acpi.c:344
ACPI data structures.
#define ref_get(refcnt)
Get additional reference to object.
Definition: refcnt.h:93
#define for_each_table_entry(pointer, table)
Iterate through all entries within a linker table.
Definition: tables.h:386
unsigned char uint8_t
Definition: stdint.h:10
An ACPI description header.
Definition: acpi.h:180
unsigned int uint32_t
Definition: stdint.h:12
struct acpi_descriptor * acpi_describe(struct interface *intf)
Get object's ACPI descriptor.
Definition: acpi.c:321
#define acpi_describe_TYPE(object_type)
Definition: acpi.h:405
struct acpi_header acpi
ACPI header.
Definition: acpi.h:252
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:295
uint32_t dsdt
Physical address of DSDT.
Definition: acpi.h:267
void * acpi_ioremap(struct acpi_address *address, size_t len)
Map an ACPI generic address.
Definition: acpi.c:270
#define ACPI_ADDRESS_TYPE_MEM
A memory address space type.
Definition: acpi.h:37
An ACPI generic address structure.
Definition: acpi.h:23
void intf_put(struct interface *intf)
Decrement reference count on an object interface.
Definition: interface.c:150
static const char * acpi_name(uint32_t signature)
Transcribe ACPI table signature (for debugging)
Definition: acpi.h:207
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:151
uint8_t data[48]
Additional event data.
Definition: ena.h:22
#define ACPI_MODELS
ACPI models.
Definition: acpi.h:341
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
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:185
typeof(acpi_finder=acpi_find)
ACPI table finder.
Definition: acpi.c:48
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:115
#define list_check_contains_entry(entry, head, member)
Check list contains a specified entry.
Definition: list.h:550
u8 signature
CPU signature.
Definition: CIB_PRM.h:35
void acpi_add(struct acpi_descriptor *desc)
Add ACPI descriptor.
Definition: acpi.c:295
#define NULL
NULL pointer (VOID *)
Definition: Base.h:322
String functions.
#define intf_get_dest_op(intf, type, dest)
Get object interface destination and operation method.
Definition: interface.h:270
iPXE I/O mapping API
#define ref_put(refcnt)
Drop reference to object.
Definition: refcnt.h:107