blob: 2f4ab751d7787dbd9a5ada801db5a33ae6db1574 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/******************************************************************************
2 *
Bob Mooref3d2e782007-02-02 19:48:18 +03003 * Module Name: tbutils - table utilities
Linus Torvalds1da177e2005-04-16 15:20:36 -07004 *
5 *****************************************************************************/
6
7/*
Bob Moore4a90c7e2006-01-13 16:22:00 -05008 * Copyright (C) 2000 - 2006, R. Byron Moore
Linus Torvalds1da177e2005-04-16 15:20:36 -07009 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions, and the following disclaimer,
16 * without modification.
17 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18 * substantially similar to the "NO WARRANTY" disclaimer below
19 * ("Disclaimer") and any redistribution must be conditioned upon
20 * including a substantially similar Disclaimer requirement for further
21 * binary redistribution.
22 * 3. Neither the names of the above-listed copyright holders nor the names
23 * of any contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * Alternatively, this software may be distributed under the terms of the
27 * GNU General Public License ("GPL") version 2 as published by the Free
28 * Software Foundation.
29 *
30 * NO WARRANTY
31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41 * POSSIBILITY OF SUCH DAMAGES.
42 */
43
Linus Torvalds1da177e2005-04-16 15:20:36 -070044#include <acpi/acpi.h>
45#include <acpi/actables.h>
46
Linus Torvalds1da177e2005-04-16 15:20:36 -070047#define _COMPONENT ACPI_TABLES
Len Brown4be44fc2005-08-05 00:44:28 -040048ACPI_MODULE_NAME("tbutils")
Linus Torvalds1da177e2005-04-16 15:20:36 -070049
Robert Moore44f6c012005-04-18 22:49:35 -040050/* Local prototypes */
Bob Moorec5fc42a2007-02-02 19:48:19 +030051static void acpi_tb_parse_fadt(acpi_native_uint table_index, u8 flags);
52
53static void acpi_tb_convert_fadt(void);
54
55static void
56acpi_tb_install_table(acpi_physical_address address,
57 u8 flags, char *signature, acpi_native_uint table_index);
Bob Mooref3d2e782007-02-02 19:48:18 +030058
59static void inline
60acpi_tb_init_generic_address(struct acpi_generic_address *new_gas_struct,
Bob Moorec5fc42a2007-02-02 19:48:19 +030061 u8 bit_width, u64 address);
62
63/* Table used for conversion of FADT to common format */
64
65typedef struct acpi_fadt_conversion {
66 u8 target;
67 u8 source;
68 u8 length;
69
70} acpi_fadt_conversion;
71
72static struct acpi_fadt_conversion fadt_conversion_table[] = {
73 {ACPI_FADT_OFFSET(xpm1a_event_block),
74 ACPI_FADT_OFFSET(pm1a_event_block),
75 ACPI_FADT_OFFSET(pm1_event_length)},
76 {ACPI_FADT_OFFSET(xpm1b_event_block),
77 ACPI_FADT_OFFSET(pm1b_event_block),
78 ACPI_FADT_OFFSET(pm1_event_length)},
79 {ACPI_FADT_OFFSET(xpm1a_control_block),
80 ACPI_FADT_OFFSET(pm1a_control_block),
81 ACPI_FADT_OFFSET(pm1_control_length)},
82 {ACPI_FADT_OFFSET(xpm1b_control_block),
83 ACPI_FADT_OFFSET(pm1b_control_block),
84 ACPI_FADT_OFFSET(pm1_control_length)},
85 {ACPI_FADT_OFFSET(xpm2_control_block),
86 ACPI_FADT_OFFSET(pm2_control_block),
87 ACPI_FADT_OFFSET(pm2_control_length)},
88 {ACPI_FADT_OFFSET(xpm_timer_block), ACPI_FADT_OFFSET(pm_timer_block),
89 ACPI_FADT_OFFSET(pm_timer_length)},
90 {ACPI_FADT_OFFSET(xgpe0_block), ACPI_FADT_OFFSET(gpe0_block),
91 ACPI_FADT_OFFSET(gpe0_block_length)},
92 {ACPI_FADT_OFFSET(xgpe1_block), ACPI_FADT_OFFSET(gpe1_block),
93 ACPI_FADT_OFFSET(gpe1_block_length)}
94};
95
96#define ACPI_FADT_CONVERSION_ENTRIES (sizeof (fadt_conversion_table) / sizeof (struct acpi_fadt_conversion))
Linus Torvalds1da177e2005-04-16 15:20:36 -070097
Linus Torvalds1da177e2005-04-16 15:20:36 -070098/*******************************************************************************
99 *
Bob Mooref3d2e782007-02-02 19:48:18 +0300100 * FUNCTION: acpi_tb_print_table_header
Robert Moore0c9938c2005-07-29 15:15:00 -0700101 *
Bob Mooref3d2e782007-02-02 19:48:18 +0300102 * PARAMETERS: Address - Table physical address
103 * Header - Table header
Robert Moore0c9938c2005-07-29 15:15:00 -0700104 *
Bob Mooref3d2e782007-02-02 19:48:18 +0300105 * RETURN: None
Robert Moore0c9938c2005-07-29 15:15:00 -0700106 *
Bob Moorec5fc42a2007-02-02 19:48:19 +0300107 * DESCRIPTION: Print an ACPI table header. Special cases for FACS and RSDP.
Robert Moore0c9938c2005-07-29 15:15:00 -0700108 *
109 ******************************************************************************/
110
Bob Mooref3d2e782007-02-02 19:48:18 +0300111void
112acpi_tb_print_table_header(acpi_physical_address address,
113 struct acpi_table_header *header)
Robert Moore0c9938c2005-07-29 15:15:00 -0700114{
Robert Moore0c9938c2005-07-29 15:15:00 -0700115
Bob Moorec5fc42a2007-02-02 19:48:19 +0300116 if (ACPI_COMPARE_NAME(header->signature, ACPI_SIG_FACS)) {
117
118 /* FACS only has signature and length fields of common table header */
119
120 ACPI_INFO((AE_INFO, "%4.4s @ 0x%p/0x%04X",
121 header->signature, ACPI_CAST_PTR(void, address),
122 header->length));
123 } else if (ACPI_COMPARE_NAME(header->signature, ACPI_SIG_RSDP)) {
124
125 /* RSDP has no common fields */
126
127 ACPI_INFO((AE_INFO, "RSDP @ 0x%p/0x%04X (v%3.3d %6.6s)",
128 ACPI_CAST_PTR(void, address),
129 (((struct acpi_table_rsdp *)header)->revision > 0) ?
130 ((struct acpi_table_rsdp *)header)->length : 20,
131 ((struct acpi_table_rsdp *)header)->revision,
132 ((struct acpi_table_rsdp *)header)->oem_id));
133 } else {
134 ACPI_INFO((AE_INFO,
135 "%4.4s @ 0x%p/0x%04X (v%3.3d %6.6s %8.8s 0x%08X %4.4s 0x%08X)",
136 header->signature, ACPI_CAST_PTR(void, address),
137 header->length, header->revision, header->oem_id,
138 header->oem_table_id, header->oem_revision,
139 header->asl_compiler_id,
140 header->asl_compiler_revision));
141 }
Bob Mooref3d2e782007-02-02 19:48:18 +0300142}
Robert Moore0c9938c2005-07-29 15:15:00 -0700143
Bob Mooref3d2e782007-02-02 19:48:18 +0300144/*******************************************************************************
145 *
146 * FUNCTION: acpi_tb_init_generic_address
147 *
148 * PARAMETERS: new_gas_struct - GAS struct to be initialized
149 * bit_width - Width of this register
150 * Address - Address of the register
151 *
152 * RETURN: None
153 *
154 * DESCRIPTION: Initialize a GAS structure.
155 *
156 ******************************************************************************/
Robert Moore0c9938c2005-07-29 15:15:00 -0700157
Bob Mooref3d2e782007-02-02 19:48:18 +0300158static void inline
159acpi_tb_init_generic_address(struct acpi_generic_address *new_gas_struct,
Bob Moorec5fc42a2007-02-02 19:48:19 +0300160 u8 bit_width, u64 address)
Bob Mooref3d2e782007-02-02 19:48:18 +0300161{
Robert Moore0c9938c2005-07-29 15:15:00 -0700162
Bob Mooref3d2e782007-02-02 19:48:18 +0300163 ACPI_STORE_ADDRESS(new_gas_struct->address, address);
164 new_gas_struct->space_id = ACPI_ADR_SPACE_SYSTEM_IO;
165 new_gas_struct->bit_width = bit_width;
166 new_gas_struct->bit_offset = 0;
167 new_gas_struct->access_width = 0;
168}
Robert Moore0c9938c2005-07-29 15:15:00 -0700169
Bob Mooref3d2e782007-02-02 19:48:18 +0300170/*******************************************************************************
171 *
Bob Moorec5fc42a2007-02-02 19:48:19 +0300172 * FUNCTION: acpi_tb_validate_checksum
173 *
174 * PARAMETERS: Table - ACPI table to verify
175 * Length - Length of entire table
176 *
177 * RETURN: Status
178 *
179 * DESCRIPTION: Verifies that the table checksums to zero. Optionally returns
180 * exception on bad checksum.
181 *
182 ******************************************************************************/
183
184acpi_status acpi_tb_verify_checksum(struct acpi_table_header *table, u32 length)
185{
186 u8 checksum;
187
188 /* Compute the checksum on the table */
189
190 checksum = acpi_tb_checksum(ACPI_CAST_PTR(u8, table), length);
191
192 /* Checksum ok? (should be zero) */
193
194 if (checksum) {
195 ACPI_WARNING((AE_INFO,
196 "Incorrect checksum in table [%4.4s] - %2.2X, should be %2.2X",
197 table->signature, table->checksum,
198 (u8) (table->checksum - checksum)));
199
200#if (ACPI_CHECKSUM_ABORT)
201
202 return (AE_BAD_CHECKSUM);
203#endif
204 }
205
206 return (AE_OK);
207}
208
209/*******************************************************************************
210 *
Bob Mooref3d2e782007-02-02 19:48:18 +0300211 * FUNCTION: acpi_tb_checksum
212 *
213 * PARAMETERS: Buffer - Pointer to memory region to be checked
214 * Length - Length of this memory region
215 *
216 * RETURN: Checksum (u8)
217 *
218 * DESCRIPTION: Calculates circular checksum of memory region.
219 *
220 ******************************************************************************/
221
222u8 acpi_tb_checksum(u8 * buffer, acpi_native_uint length)
223{
224 u8 sum = 0;
225 u8 *end = buffer + length;
226
227 while (buffer < end) {
228 sum = (u8) (sum + *(buffer++));
229 }
230
231 return sum;
232}
233
234/*******************************************************************************
235 *
236 * FUNCTION: acpi_tb_convert_fadt
237 *
Bob Moorec5fc42a2007-02-02 19:48:19 +0300238 * PARAMETERS: None, uses acpi_gbl_FADT
Bob Mooref3d2e782007-02-02 19:48:18 +0300239 *
240 * RETURN: None
241 *
Bob Moorec5fc42a2007-02-02 19:48:19 +0300242 * DESCRIPTION: Converts all versions of the FADT to a common internal format.
243 *
244 * NOTE: acpi_gbl_FADT must be of size (struct acpi_table_fadt), and must contain
245 * a copy of the actual FADT.
246 *
247 * ACPICA will use the "X" fields of the FADT for all addresses.
248 *
249 * "X" fields are optional extensions to the original V1.0 fields. Even if
250 * they are present in the structure, they can be optionally not used by
251 * setting them to zero. Therefore, we must selectively expand V1.0 fields
252 * if the corresponding X field is zero.
253 *
254 * For ACPI 1.0 FADTs, all address fields are expanded to the corresponding
255 * "X" fields.
256 *
257 * For ACPI 2.0 FADTs, any "X" fields that are NULL are filled in by
258 * expanding the corresponding ACPI 1.0 field.
Bob Mooref3d2e782007-02-02 19:48:18 +0300259 *
260 ******************************************************************************/
261
Bob Moorec5fc42a2007-02-02 19:48:19 +0300262static void acpi_tb_convert_fadt(void)
Bob Mooref3d2e782007-02-02 19:48:18 +0300263{
Bob Moorec5fc42a2007-02-02 19:48:19 +0300264 u8 pm1_register_length;
265 struct acpi_generic_address *target;
266 acpi_native_uint i;
Bob Mooref3d2e782007-02-02 19:48:18 +0300267
Bob Moorec5fc42a2007-02-02 19:48:19 +0300268 /* Expand the FACS and DSDT addresses as necessary */
269
Bob Mooref3d2e782007-02-02 19:48:18 +0300270 if (!acpi_gbl_FADT.Xfacs) {
271 acpi_gbl_FADT.Xfacs = (u64) acpi_gbl_FADT.facs;
272 }
273
274 if (!acpi_gbl_FADT.Xdsdt) {
275 acpi_gbl_FADT.Xdsdt = (u64) acpi_gbl_FADT.dsdt;
276 }
277
278 /*
Bob Moorec5fc42a2007-02-02 19:48:19 +0300279 * Expand the V1.0 addresses to the "X" generic address structs,
280 * as necessary.
Bob Mooref3d2e782007-02-02 19:48:18 +0300281 */
Bob Moorec5fc42a2007-02-02 19:48:19 +0300282 for (i = 0; i < ACPI_FADT_CONVERSION_ENTRIES; i++) {
283 target =
284 ACPI_ADD_PTR(struct acpi_generic_address, &acpi_gbl_FADT,
285 fadt_conversion_table[i].target);
286
287 if (!target->address) {
288 acpi_tb_init_generic_address(target,
289 *ACPI_ADD_PTR(u8,
290 &acpi_gbl_FADT,
291 fadt_conversion_table
292 [i].length),
293 *ACPI_ADD_PTR(u64,
294 &acpi_gbl_FADT,
295 fadt_conversion_table
296 [i].source));
297 }
298 }
Bob Mooref3d2e782007-02-02 19:48:18 +0300299
300 /*
Bob Moorec5fc42a2007-02-02 19:48:19 +0300301 * Calculate separate GAS structs for the PM1 Enable registers.
302 * These addresses do not appear (directly) in the FADT, so it is
303 * useful to calculate them once, here.
Bob Mooref3d2e782007-02-02 19:48:18 +0300304 */
Bob Moorec5fc42a2007-02-02 19:48:19 +0300305 pm1_register_length = (u8) ACPI_DIV_2(acpi_gbl_FADT.pm1_event_length);
306
307 /* PM1A is required */
308
Bob Mooref3d2e782007-02-02 19:48:18 +0300309 acpi_tb_init_generic_address(&acpi_gbl_xpm1a_enable,
Bob Moorec5fc42a2007-02-02 19:48:19 +0300310 pm1_register_length,
311 (u64) (acpi_gbl_FADT.xpm1a_event_block.
312 address + pm1_register_length));
Bob Mooref3d2e782007-02-02 19:48:18 +0300313
Bob Moorec5fc42a2007-02-02 19:48:19 +0300314 /* PM1B is optional; leave null if not present */
315
Bob Mooref3d2e782007-02-02 19:48:18 +0300316 if (acpi_gbl_FADT.xpm1b_event_block.address) {
317 acpi_tb_init_generic_address(&acpi_gbl_xpm1b_enable,
Bob Moorec5fc42a2007-02-02 19:48:19 +0300318 pm1_register_length,
319 (u64) (acpi_gbl_FADT.
320 xpm1b_event_block.address +
321 pm1_register_length));
Bob Mooref3d2e782007-02-02 19:48:18 +0300322 }
323
324 /* Global FADT is the new common V2.0 FADT */
325
326 acpi_gbl_FADT.header.length = sizeof(struct acpi_table_fadt);
327}
328
329/*******************************************************************************
330 *
Bob Moorec5fc42a2007-02-02 19:48:19 +0300331 * FUNCTION: acpi_tb_install_table
Bob Mooref3d2e782007-02-02 19:48:18 +0300332 *
Bob Moorec5fc42a2007-02-02 19:48:19 +0300333 * PARAMETERS: Address - Physical address of DSDT or FACS
334 * Flags - Flags
335 * Signature - Table signature, NULL if no need to
336 * match
337 * table_index - Index into root table array
Bob Mooref3d2e782007-02-02 19:48:18 +0300338 *
Bob Moorec5fc42a2007-02-02 19:48:19 +0300339 * RETURN: None
Bob Mooref3d2e782007-02-02 19:48:18 +0300340 *
Bob Moorec5fc42a2007-02-02 19:48:19 +0300341 * DESCRIPTION: Install an ACPI table into the global data structure.
Bob Mooref3d2e782007-02-02 19:48:18 +0300342 *
343 ******************************************************************************/
344
Bob Moorec5fc42a2007-02-02 19:48:19 +0300345static void
346acpi_tb_install_table(acpi_physical_address address,
347 u8 flags, char *signature, acpi_native_uint table_index)
Bob Mooref3d2e782007-02-02 19:48:18 +0300348{
Bob Mooref3d2e782007-02-02 19:48:18 +0300349 struct acpi_table_header *table;
350
Bob Moorec5fc42a2007-02-02 19:48:19 +0300351 if (!address) {
352 ACPI_ERROR((AE_INFO,
353 "Null physical address for ACPI table [%s]",
354 signature));
Bob Mooref3d2e782007-02-02 19:48:18 +0300355 return;
356 }
357
Bob Moorec5fc42a2007-02-02 19:48:19 +0300358 /* Map just the table header */
359
360 table = acpi_os_map_memory(address, sizeof(struct acpi_table_header));
Bob Mooref3d2e782007-02-02 19:48:18 +0300361 if (!table) {
362 return;
363 }
364
Bob Moorec5fc42a2007-02-02 19:48:19 +0300365 /* If a particular signature is expected, signature must match */
366
367 if (signature && !ACPI_COMPARE_NAME(table->signature, signature)) {
368 ACPI_ERROR((AE_INFO,
369 "Invalid signature 0x%X for ACPI table [%s]",
370 *ACPI_CAST_PTR(u32, table->signature), signature));
371 goto unmap_and_exit;
372 }
373
374 /* Initialize the table entry */
375
376 acpi_gbl_root_table_list.tables[table_index].address = address;
377 acpi_gbl_root_table_list.tables[table_index].length = table->length;
378 acpi_gbl_root_table_list.tables[table_index].flags = flags;
Bob Mooref3d2e782007-02-02 19:48:18 +0300379
380 ACPI_MOVE_32_TO_32(&
Bob Moorec5fc42a2007-02-02 19:48:19 +0300381 (acpi_gbl_root_table_list.tables[table_index].
382 signature), table->signature);
Bob Mooref3d2e782007-02-02 19:48:18 +0300383
Bob Moorec5fc42a2007-02-02 19:48:19 +0300384 acpi_tb_print_table_header(address, table);
Bob Mooref3d2e782007-02-02 19:48:18 +0300385
Bob Moorec5fc42a2007-02-02 19:48:19 +0300386 if (table_index == ACPI_TABLE_INDEX_DSDT) {
Bob Mooref3d2e782007-02-02 19:48:18 +0300387
Bob Moorec5fc42a2007-02-02 19:48:19 +0300388 /* Global integer width is based upon revision of the DSDT */
389
390 acpi_ut_set_integer_width(table->revision);
391 }
392
393 unmap_and_exit:
Bob Mooref3d2e782007-02-02 19:48:18 +0300394 acpi_os_unmap_memory(table, sizeof(struct acpi_table_header));
395}
396
397/*******************************************************************************
398 *
Bob Moorec5fc42a2007-02-02 19:48:19 +0300399 * FUNCTION: acpi_tb_parse_fadt
400 *
401 * PARAMETERS: table_index - Index for the FADT
402 * Flags - Flags
403 *
404 * RETURN: None
405 *
406 * DESCRIPTION: Initialize the FADT, DSDT and FACS tables
407 * (FADT contains the addresses of the DSDT and FACS)
408 *
409 ******************************************************************************/
410
411static void acpi_tb_parse_fadt(acpi_native_uint table_index, u8 flags)
412{
413 u32 length;
414 struct acpi_table_header *table;
415
416 /*
417 * Special case for the FADT because of multiple versions and the fact
418 * that it contains pointers to both the DSDT and FACS tables.
419 *
420 * Get a local copy of the FADT and convert it to a common format
421 * Map entire FADT, assumed to be smaller than one page.
422 */
423 length = acpi_gbl_root_table_list.tables[table_index].length;
424
425 table =
426 acpi_os_map_memory(acpi_gbl_root_table_list.tables[table_index].
427 address, length);
428 if (!table) {
429 return;
430 }
431
432 /*
433 * Validate the FADT checksum before we copy the table. Ignore
434 * checksum error as we want to try to get the DSDT and FACS.
435 */
436 (void)acpi_tb_verify_checksum(table, length);
437
438 /* Copy the entire FADT locally */
439
440 ACPI_MEMSET(&acpi_gbl_FADT, sizeof(struct acpi_table_fadt), 0);
441
442 ACPI_MEMCPY(&acpi_gbl_FADT, table,
443 ACPI_MIN(length, sizeof(struct acpi_table_fadt)));
444 acpi_os_unmap_memory(table, length);
445
446 /* Convert local FADT to the common internal format */
447
448 acpi_tb_convert_fadt();
449
450 /* Extract the DSDT and FACS tables from the FADT */
451
452 acpi_tb_install_table((acpi_physical_address) acpi_gbl_FADT.Xdsdt,
453 flags, ACPI_SIG_DSDT, ACPI_TABLE_INDEX_DSDT);
454
455 acpi_tb_install_table((acpi_physical_address) acpi_gbl_FADT.Xfacs,
456 flags, ACPI_SIG_FACS, ACPI_TABLE_INDEX_FACS);
457}
458
459/*******************************************************************************
460 *
Bob Mooref3d2e782007-02-02 19:48:18 +0300461 * FUNCTION: acpi_tb_parse_root_table
462 *
463 * PARAMETERS: Rsdp - Pointer to the RSDP
464 * Flags - Flags
465 *
466 * RETURN: Status
467 *
468 * DESCRIPTION: This function is called to parse the Root System Description
469 * Table (RSDT or XSDT)
470 *
471 * NOTE: Tables are mapped (not copied) for efficiency. The FACS must
472 * be mapped and cannot be copied because it contains the actual
473 * memory location of the ACPI Global Lock.
474 *
475 ******************************************************************************/
476
Bob Moorec5fc42a2007-02-02 19:48:19 +0300477acpi_status
478acpi_tb_parse_root_table(acpi_physical_address rsdp_address, u8 flags)
Bob Mooref3d2e782007-02-02 19:48:18 +0300479{
Bob Moorec5fc42a2007-02-02 19:48:19 +0300480 struct acpi_table_rsdp *rsdp;
481 acpi_native_uint table_entry_size;
482 acpi_native_uint i;
483 u32 table_count;
Bob Mooref3d2e782007-02-02 19:48:18 +0300484 struct acpi_table_header *table;
485 acpi_physical_address address;
486 u32 length;
487 u8 *table_entry;
Bob Mooref3d2e782007-02-02 19:48:18 +0300488 acpi_status status;
489
490 ACPI_FUNCTION_TRACE(tb_parse_root_table);
491
Bob Moorec5fc42a2007-02-02 19:48:19 +0300492 /*
493 * Map the entire RSDP and extract the address of the RSDT or XSDT
494 */
495 rsdp = acpi_os_map_memory(rsdp_address, sizeof(struct acpi_table_rsdp));
496 if (!rsdp) {
497 return_ACPI_STATUS(AE_NO_MEMORY);
498 }
499
500 acpi_tb_print_table_header(rsdp_address,
501 ACPI_CAST_PTR(struct acpi_table_header,
502 rsdp));
503
Bob Mooref3d2e782007-02-02 19:48:18 +0300504 /* Differentiate between RSDT and XSDT root tables */
505
506 if (rsdp->revision > 1 && rsdp->xsdt_physical_address) {
Bob Moorea18ecf42005-08-15 03:42:00 -0800507 /*
Bob Mooref3d2e782007-02-02 19:48:18 +0300508 * Root table is an XSDT (64-bit physical addresses). We must use the
509 * XSDT if the revision is > 1 and the XSDT pointer is present, as per
510 * the ACPI specification.
Bob Moorea18ecf42005-08-15 03:42:00 -0800511 */
Bob Moorec5fc42a2007-02-02 19:48:19 +0300512 address = (acpi_physical_address) rsdp->xsdt_physical_address;
513 table_entry_size = sizeof(u64);
Bob Mooref3d2e782007-02-02 19:48:18 +0300514 } else {
515 /* Root table is an RSDT (32-bit physical addresses) */
Bob Moore52fc0b02006-10-02 00:00:00 -0400516
Bob Moorec5fc42a2007-02-02 19:48:19 +0300517 address = (acpi_physical_address) rsdp->rsdt_physical_address;
518 table_entry_size = sizeof(u32);
Bob Mooref3d2e782007-02-02 19:48:18 +0300519 }
Robert Moore0c9938c2005-07-29 15:15:00 -0700520
Bob Moorec5fc42a2007-02-02 19:48:19 +0300521 /*
522 * It is not possible to map more than one entry in some environments,
523 * so unmap the RSDP here before mapping other tables
524 */
525 acpi_os_unmap_memory(rsdp, sizeof(struct acpi_table_rsdp));
526
527 /* Map the RSDT/XSDT table header to get the full table length */
Robert Moore0c9938c2005-07-29 15:15:00 -0700528
Bob Mooref3d2e782007-02-02 19:48:18 +0300529 table = acpi_os_map_memory(address, sizeof(struct acpi_table_header));
530 if (!table) {
Bob Moorec5fc42a2007-02-02 19:48:19 +0300531 return_ACPI_STATUS(AE_NO_MEMORY);
Bob Mooref3d2e782007-02-02 19:48:18 +0300532 }
Robert Moore0c9938c2005-07-29 15:15:00 -0700533
Bob Moorec5fc42a2007-02-02 19:48:19 +0300534 acpi_tb_print_table_header(address, table);
535
Bob Mooref3d2e782007-02-02 19:48:18 +0300536 /* Get the length of the full table, verify length and map entire table */
537
538 length = table->length;
539 acpi_os_unmap_memory(table, sizeof(struct acpi_table_header));
540
541 if (length < sizeof(struct acpi_table_header)) {
542 ACPI_ERROR((AE_INFO, "Invalid length 0x%X in RSDT/XSDT",
543 length));
Bob Moorec5fc42a2007-02-02 19:48:19 +0300544 return_ACPI_STATUS(AE_INVALID_TABLE_LENGTH);
Bob Mooref3d2e782007-02-02 19:48:18 +0300545 }
546
547 table = acpi_os_map_memory(address, length);
548 if (!table) {
Bob Moorec5fc42a2007-02-02 19:48:19 +0300549 return_ACPI_STATUS(AE_NO_MEMORY);
Bob Mooref3d2e782007-02-02 19:48:18 +0300550 }
551
552 /* Validate the root table checksum */
553
Bob Moorec5fc42a2007-02-02 19:48:19 +0300554 status = acpi_tb_verify_checksum(table, length);
555 if (ACPI_FAILURE(status)) {
Bob Mooref3d2e782007-02-02 19:48:18 +0300556 acpi_os_unmap_memory(table, length);
Bob Moorec5fc42a2007-02-02 19:48:19 +0300557 return_ACPI_STATUS(status);
Bob Mooref3d2e782007-02-02 19:48:18 +0300558 }
Bob Mooref3d2e782007-02-02 19:48:18 +0300559
560 /* Calculate the number of tables described in the root table */
561
562 table_count =
Bob Moorec5fc42a2007-02-02 19:48:19 +0300563 (table->length -
564 sizeof(struct acpi_table_header)) / table_entry_size;
Bob Mooref3d2e782007-02-02 19:48:18 +0300565
Bob Moorec5fc42a2007-02-02 19:48:19 +0300566 /*
567 * First two entries in the table array are reserved for the DSDT and FACS,
568 * which are not actually present in the RSDT/XSDT - they come from the FADT
569 */
Bob Mooref3d2e782007-02-02 19:48:18 +0300570 table_entry =
571 ACPI_CAST_PTR(u8, table) + sizeof(struct acpi_table_header);
572 acpi_gbl_root_table_list.count = 2;
573
574 /*
Bob Moorec5fc42a2007-02-02 19:48:19 +0300575 * Initialize the root table array from the RSDT/XSDT
Bob Mooref3d2e782007-02-02 19:48:18 +0300576 */
Bob Moorec5fc42a2007-02-02 19:48:19 +0300577 for (i = 0; i < table_count; i++) {
Bob Mooref3d2e782007-02-02 19:48:18 +0300578 if (acpi_gbl_root_table_list.count >=
579 acpi_gbl_root_table_list.size) {
Bob Moorec5fc42a2007-02-02 19:48:19 +0300580
581 /* There is no more room in the root table array, attempt resize */
582
Bob Mooref3d2e782007-02-02 19:48:18 +0300583 status = acpi_tb_resize_root_table_list();
584 if (ACPI_FAILURE(status)) {
585 ACPI_WARNING((AE_INFO,
586 "Truncating %u table entries!",
587 (unsigned)
588 (acpi_gbl_root_table_list.size -
589 acpi_gbl_root_table_list.
590 count)));
591 break;
592 }
Robert Moore0c9938c2005-07-29 15:15:00 -0700593 }
594
Bob Moorec5fc42a2007-02-02 19:48:19 +0300595 /*
596 * Get the table physical address (32-bit for RSDT, 64-bit for XSDT)
597 */
598 if ((table_entry_size == sizeof(u32)) ||
599 (sizeof(acpi_physical_address) == sizeof(u32))) {
600 /*
601 * 32-bit platform, RSDT: Move 32-bit to 32-bit
602 * 32-bit platform, XSDT: Truncate 64-bit to 32-bit
603 * 64-bit platform, RSDT: Expand 32-bit to 64-bit
604 *
605 * Note: Addresses are 32-bit aligned in both RSDT and XSDT
606 */
Bob Mooref3d2e782007-02-02 19:48:18 +0300607 acpi_gbl_root_table_list.
608 tables[acpi_gbl_root_table_list.count].address =
609 (acpi_physical_address) (*ACPI_CAST_PTR
610 (u32, table_entry));
611 } else {
Bob Moorec5fc42a2007-02-02 19:48:19 +0300612 /*
613 * 64-bit platform, XSDT: Move 64-bit to 64-bit
614 *
615 * Note: 64-bit addresses are only 32-bit aligned in the XSDT
616 */
617 ACPI_MOVE_64_TO_64(&acpi_gbl_root_table_list.
618 tables[acpi_gbl_root_table_list.
619 count].address, table_entry);
Bob Mooref3d2e782007-02-02 19:48:18 +0300620 }
621
Bob Moorec5fc42a2007-02-02 19:48:19 +0300622 table_entry += table_entry_size;
Bob Mooref3d2e782007-02-02 19:48:18 +0300623 acpi_gbl_root_table_list.count++;
624 }
625
626 /*
627 * It is not possible to map more than one entry in some environments,
628 * so unmap the root table here before mapping other tables
629 */
630 acpi_os_unmap_memory(table, length);
631
Bob Moorec5fc42a2007-02-02 19:48:19 +0300632 /*
633 * Complete the initialization of the root table array by examining
634 * the header of each table
635 */
Bob Mooref3d2e782007-02-02 19:48:18 +0300636 for (i = 2; i < acpi_gbl_root_table_list.count; i++) {
Bob Moorec5fc42a2007-02-02 19:48:19 +0300637 acpi_tb_install_table(acpi_gbl_root_table_list.tables[i].
638 address, flags, NULL, i);
Bob Mooref3d2e782007-02-02 19:48:18 +0300639
Bob Moorec5fc42a2007-02-02 19:48:19 +0300640 /* Special case for FADT - get the DSDT and FACS */
Bob Mooref3d2e782007-02-02 19:48:18 +0300641
Bob Moorec5fc42a2007-02-02 19:48:19 +0300642 if (ACPI_COMPARE_NAME
643 (&acpi_gbl_root_table_list.tables[i].signature,
644 ACPI_SIG_FADT)) {
645 acpi_tb_parse_fadt(i, flags);
Bob Mooref3d2e782007-02-02 19:48:18 +0300646 }
Robert Moore0c9938c2005-07-29 15:15:00 -0700647 }
648
Len Brown4be44fc2005-08-05 00:44:28 -0400649 return_ACPI_STATUS(AE_OK);
Robert Moore0c9938c2005-07-29 15:15:00 -0700650}
651
Bob Mooref3d2e782007-02-02 19:48:18 +0300652/******************************************************************************
Robert Moore0c9938c2005-07-29 15:15:00 -0700653 *
Bob Mooref3d2e782007-02-02 19:48:18 +0300654 * FUNCTION: acpi_tb_map
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655 *
Bob Mooref3d2e782007-02-02 19:48:18 +0300656 * PARAMETERS: Address - Address to be mapped
657 * Length - Length to be mapped
658 * Flags - Logical or physical addressing mode
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659 *
Bob Mooref3d2e782007-02-02 19:48:18 +0300660 * RETURN: Pointer to mapped region
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661 *
Bob Mooref3d2e782007-02-02 19:48:18 +0300662 * DESCRIPTION: Maps memory according to flag
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663 *
Bob Mooref3d2e782007-02-02 19:48:18 +0300664 *****************************************************************************/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665
Bob Mooref3d2e782007-02-02 19:48:18 +0300666void *acpi_tb_map(acpi_physical_address address, u32 length, u32 flags)
Bob Moore793c2382006-03-31 00:00:00 -0500667{
668
Bob Mooref3d2e782007-02-02 19:48:18 +0300669 if (flags == ACPI_TABLE_ORIGIN_MAPPED) {
670 return (acpi_os_map_memory(address, length));
671 } else {
672 return (ACPI_CAST_PTR(void, address));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674}
675
Bob Mooref3d2e782007-02-02 19:48:18 +0300676/******************************************************************************
Robert Moore44f6c012005-04-18 22:49:35 -0400677 *
Bob Mooref3d2e782007-02-02 19:48:18 +0300678 * FUNCTION: acpi_tb_unmap
Robert Moore44f6c012005-04-18 22:49:35 -0400679 *
Bob Mooref3d2e782007-02-02 19:48:18 +0300680 * PARAMETERS: Pointer - To mapped region
681 * Length - Length to be unmapped
682 * Flags - Logical or physical addressing mode
Robert Moore44f6c012005-04-18 22:49:35 -0400683 *
Bob Mooref3d2e782007-02-02 19:48:18 +0300684 * RETURN: None
Robert Moore44f6c012005-04-18 22:49:35 -0400685 *
Bob Mooref3d2e782007-02-02 19:48:18 +0300686 * DESCRIPTION: Unmaps memory according to flag
687 *
688 *****************************************************************************/
Robert Moore44f6c012005-04-18 22:49:35 -0400689
Bob Mooref3d2e782007-02-02 19:48:18 +0300690void acpi_tb_unmap(void *pointer, u32 length, u32 flags)
Robert Moore44f6c012005-04-18 22:49:35 -0400691{
Robert Moore44f6c012005-04-18 22:49:35 -0400692
Bob Mooref3d2e782007-02-02 19:48:18 +0300693 if (flags == ACPI_TABLE_ORIGIN_MAPPED) {
694 acpi_os_unmap_memory(pointer, length);
Robert Moore44f6c012005-04-18 22:49:35 -0400695 }
Robert Moore44f6c012005-04-18 22:49:35 -0400696}