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