tbutils.c 14.6 KB
Newer Older
L
Linus Torvalds 已提交
1 2
/******************************************************************************
 *
3
 * Module Name: tbutils   - table utilities
L
Linus Torvalds 已提交
4 5 6 7
 *
 *****************************************************************************/

/*
B
Bob Moore 已提交
8
 * Copyright (C) 2000 - 2007, R. Byron Moore
L
Linus Torvalds 已提交
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions, and the following disclaimer,
 *    without modification.
 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
 *    substantially similar to the "NO WARRANTY" disclaimer below
 *    ("Disclaimer") and any redistribution must be conditioned upon
 *    including a substantially similar Disclaimer requirement for further
 *    binary redistribution.
 * 3. Neither the names of the above-listed copyright holders nor the names
 *    of any contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * Alternatively, this software may be distributed under the terms of the
 * GNU General Public License ("GPL") version 2 as published by the Free
 * Software Foundation.
 *
 * NO WARRANTY
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGES.
 */

#include <acpi/acpi.h>
#include <acpi/actables.h>

#define _COMPONENT          ACPI_TABLES
L
Len Brown 已提交
48
ACPI_MODULE_NAME("tbutils")
L
Linus Torvalds 已提交
49

R
Robert Moore 已提交
50
/* Local prototypes */
B
Bob Moore 已提交
51 52 53 54
static acpi_physical_address
acpi_tb_get_root_table_entry(u8 * table_entry,
			     acpi_native_uint table_entry_size);

55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
/*******************************************************************************
 *
 * FUNCTION:    acpi_tb_tables_loaded
 *
 * PARAMETERS:  None
 *
 * RETURN:      TRUE if required ACPI tables are loaded
 *
 * DESCRIPTION: Determine if the minimum required ACPI tables are present
 *              (FADT, FACS, DSDT)
 *
 ******************************************************************************/

u8 acpi_tb_tables_loaded(void)
{

	if (acpi_gbl_root_table_list.count >= 3) {
		return (TRUE);
	}

	return (FALSE);
}

78 79
/*******************************************************************************
 *
80
 * FUNCTION:    acpi_tb_print_table_header
81
 *
82 83
 * PARAMETERS:  Address             - Table physical address
 *              Header              - Table header
84
 *
85
 * RETURN:      None
86
 *
87
 * DESCRIPTION: Print an ACPI table header. Special cases for FACS and RSDP.
88 89 90
 *
 ******************************************************************************/

91 92 93
void
acpi_tb_print_table_header(acpi_physical_address address,
			   struct acpi_table_header *header)
94 95
{

96 97 98 99 100 101 102 103 104 105 106 107 108
	if (ACPI_COMPARE_NAME(header->signature, ACPI_SIG_FACS)) {

		/* FACS only has signature and length fields of common table header */

		ACPI_INFO((AE_INFO, "%4.4s @ 0x%p/0x%04X",
			   header->signature, ACPI_CAST_PTR(void, address),
			   header->length));
	} else if (ACPI_COMPARE_NAME(header->signature, ACPI_SIG_RSDP)) {

		/* RSDP has no common fields */

		ACPI_INFO((AE_INFO, "RSDP @ 0x%p/0x%04X (v%3.3d %6.6s)",
			   ACPI_CAST_PTR(void, address),
B
Bob Moore 已提交
109 110 111 112 113 114 115 116
			   (ACPI_CAST_PTR(struct acpi_table_rsdp, header)->
			    revision >
			    0) ? ACPI_CAST_PTR(struct acpi_table_rsdp,
					       header)->length : 20,
			   ACPI_CAST_PTR(struct acpi_table_rsdp,
					 header)->revision,
			   ACPI_CAST_PTR(struct acpi_table_rsdp,
					 header)->oem_id));
117
	} else {
118 119
		/* Standard ACPI table with full common header */

120 121 122 123 124 125 126 127
		ACPI_INFO((AE_INFO,
			   "%4.4s @ 0x%p/0x%04X (v%3.3d %6.6s %8.8s 0x%08X %4.4s 0x%08X)",
			   header->signature, ACPI_CAST_PTR(void, address),
			   header->length, header->revision, header->oem_id,
			   header->oem_table_id, header->oem_revision,
			   header->asl_compiler_id,
			   header->asl_compiler_revision));
	}
128 129
}

130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
/*******************************************************************************
 *
 * FUNCTION:    acpi_tb_validate_checksum
 *
 * PARAMETERS:  Table               - ACPI table to verify
 *              Length              - Length of entire table
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Verifies that the table checksums to zero. Optionally returns
 *              exception on bad checksum.
 *
 ******************************************************************************/

acpi_status acpi_tb_verify_checksum(struct acpi_table_header *table, u32 length)
{
	u8 checksum;

	/* Compute the checksum on the table */

	checksum = acpi_tb_checksum(ACPI_CAST_PTR(u8, table), length);

	/* Checksum ok? (should be zero) */

	if (checksum) {
		ACPI_WARNING((AE_INFO,
			      "Incorrect checksum in table [%4.4s] -  %2.2X, should be %2.2X",
			      table->signature, table->checksum,
			      (u8) (table->checksum - checksum)));

#if (ACPI_CHECKSUM_ABORT)

		return (AE_BAD_CHECKSUM);
#endif
	}

	return (AE_OK);
}

L
Linus Torvalds 已提交
169 170
/*******************************************************************************
 *
171
 * FUNCTION:    acpi_tb_checksum
L
Linus Torvalds 已提交
172
 *
173 174
 * PARAMETERS:  Buffer          - Pointer to memory region to be checked
 *              Length          - Length of this memory region
L
Linus Torvalds 已提交
175
 *
176
 * RETURN:      Checksum (u8)
L
Linus Torvalds 已提交
177
 *
178
 * DESCRIPTION: Calculates circular checksum of memory region.
L
Linus Torvalds 已提交
179 180 181
 *
 ******************************************************************************/

182
u8 acpi_tb_checksum(u8 * buffer, acpi_native_uint length)
B
Bob Moore 已提交
183 184
{
	u8 sum = 0;
185
	u8 *end = buffer + length;
B
Bob Moore 已提交
186

187 188
	while (buffer < end) {
		sum = (u8) (sum + *(buffer++));
B
Bob Moore 已提交
189 190
	}

191
	return sum;
B
Bob Moore 已提交
192 193
}

L
Linus Torvalds 已提交
194 195
/*******************************************************************************
 *
196
 * FUNCTION:    acpi_tb_install_table
L
Linus Torvalds 已提交
197
 *
198 199 200 201 202
 * PARAMETERS:  Address                 - Physical address of DSDT or FACS
 *              Flags                   - Flags
 *              Signature               - Table signature, NULL if no need to
 *                                        match
 *              table_index             - Index into root table array
L
Linus Torvalds 已提交
203
 *
204
 * RETURN:      None
L
Linus Torvalds 已提交
205
 *
206
 * DESCRIPTION: Install an ACPI table into the global data structure.
L
Linus Torvalds 已提交
207 208 209
 *
 ******************************************************************************/

210
void
211 212
acpi_tb_install_table(acpi_physical_address address,
		      u8 flags, char *signature, acpi_native_uint table_index)
L
Linus Torvalds 已提交
213
{
214 215
	struct acpi_table_header *table;

216 217 218 219 220
	if (!address) {
		ACPI_ERROR((AE_INFO,
			    "Null physical address for ACPI table [%s]",
			    signature));
		return;
221 222
	}

223 224 225
	/* Map just the table header */

	table = acpi_os_map_memory(address, sizeof(struct acpi_table_header));
226
	if (!table) {
227 228 229 230 231 232 233 234 235 236
		return;
	}

	/* If a particular signature is expected, signature must match */

	if (signature && !ACPI_COMPARE_NAME(table->signature, signature)) {
		ACPI_ERROR((AE_INFO,
			    "Invalid signature 0x%X for ACPI table [%s]",
			    *ACPI_CAST_PTR(u32, table->signature), signature));
		goto unmap_and_exit;
237 238
	}

239 240 241 242 243
	/* Initialize the table entry */

	acpi_gbl_root_table_list.tables[table_index].address = address;
	acpi_gbl_root_table_list.tables[table_index].length = table->length;
	acpi_gbl_root_table_list.tables[table_index].flags = flags;
244 245

	ACPI_MOVE_32_TO_32(&
246 247
			   (acpi_gbl_root_table_list.tables[table_index].
			    signature), table->signature);
248

249
	acpi_tb_print_table_header(address, table);
250

251
	if (table_index == ACPI_TABLE_INDEX_DSDT) {
252

253
		/* Global integer width is based upon revision of the DSDT */
254

255 256 257 258
		acpi_ut_set_integer_width(table->revision);
	}

      unmap_and_exit:
259
	acpi_os_unmap_memory(table, sizeof(struct acpi_table_header));
260
}
261

B
Bob Moore 已提交
262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305
/*******************************************************************************
 *
 * FUNCTION:    acpi_tb_get_root_table_entry
 *
 * PARAMETERS:  table_entry         - Pointer to the RSDT/XSDT table entry
 *              table_entry_size    - sizeof 32 or 64 (RSDT or XSDT)
 *
 * RETURN:      Physical address extracted from the root table
 *
 * DESCRIPTION: Get one root table entry. Handles 32-bit and 64-bit cases on
 *              both 32-bit and 64-bit platforms
 *
 * NOTE:        acpi_physical_address is 32-bit on 32-bit platforms, 64-bit on
 *              64-bit platforms.
 *
 ******************************************************************************/

static acpi_physical_address
acpi_tb_get_root_table_entry(u8 * table_entry,
			     acpi_native_uint table_entry_size)
{
	u64 address64;

	/*
	 * Get the table physical address (32-bit for RSDT, 64-bit for XSDT):
	 * Note: Addresses are 32-bit aligned (not 64) in both RSDT and XSDT
	 */
	if (table_entry_size == sizeof(u32)) {
		/*
		 * 32-bit platform, RSDT: Return 32-bit table entry
		 * 64-bit platform, RSDT: Expand 32-bit to 64-bit and return
		 */
		return ((acpi_physical_address)
			(*ACPI_CAST_PTR(u32, table_entry)));
	} else {
		/*
		 * 32-bit platform, XSDT: Truncate 64-bit to 32-bit and return
		 * 64-bit platform, XSDT: Move (unaligned) 64-bit to local, return 64-bit
		 */
		ACPI_MOVE_64_TO_64(&address64, table_entry);

#if ACPI_MACHINE_WIDTH == 32
		if (address64 > ACPI_UINT32_MAX) {

306
			/* Will truncate 64-bit address to 32 bits, issue warning */
B
Bob Moore 已提交
307 308 309 310 311 312 313 314 315 316

			ACPI_WARNING((AE_INFO,
				      "64-bit Physical Address in XSDT is too large (%8.8X%8.8X), truncating",
				      ACPI_FORMAT_UINT64(address64)));
		}
#endif
		return ((acpi_physical_address) (address64));
	}
}

B
Bob Moore 已提交
317 318
/*******************************************************************************
 *
319
 * FUNCTION:    acpi_tb_parse_root_table
B
Bob Moore 已提交
320
 *
321 322 323 324
 * PARAMETERS:  Rsdp                    - Pointer to the RSDP
 *              Flags                   - Flags
 *
 * RETURN:      Status
B
Bob Moore 已提交
325
 *
326 327
 * DESCRIPTION: This function is called to parse the Root System Description
 *              Table (RSDT or XSDT)
B
Bob Moore 已提交
328
 *
329 330 331
 * NOTE:        Tables are mapped (not copied) for efficiency. The FACS must
 *              be mapped and cannot be copied because it contains the actual
 *              memory location of the ACPI Global Lock.
B
Bob Moore 已提交
332 333 334
 *
 ******************************************************************************/

335
acpi_status __init
336
acpi_tb_parse_root_table(acpi_physical_address rsdp_address, u8 flags)
B
Bob Moore 已提交
337
{
338 339 340 341
	struct acpi_table_rsdp *rsdp;
	acpi_native_uint table_entry_size;
	acpi_native_uint i;
	u32 table_count;
342 343 344 345 346 347 348 349
	struct acpi_table_header *table;
	acpi_physical_address address;
	u32 length;
	u8 *table_entry;
	acpi_status status;

	ACPI_FUNCTION_TRACE(tb_parse_root_table);

350 351 352 353 354 355 356 357 358 359 360 361
	/*
	 * Map the entire RSDP and extract the address of the RSDT or XSDT
	 */
	rsdp = acpi_os_map_memory(rsdp_address, sizeof(struct acpi_table_rsdp));
	if (!rsdp) {
		return_ACPI_STATUS(AE_NO_MEMORY);
	}

	acpi_tb_print_table_header(rsdp_address,
				   ACPI_CAST_PTR(struct acpi_table_header,
						 rsdp));

362 363 364 365 366 367 368 369
	/* Differentiate between RSDT and XSDT root tables */

	if (rsdp->revision > 1 && rsdp->xsdt_physical_address) {
		/*
		 * Root table is an XSDT (64-bit physical addresses). We must use the
		 * XSDT if the revision is > 1 and the XSDT pointer is present, as per
		 * the ACPI specification.
		 */
370 371
		address = (acpi_physical_address) rsdp->xsdt_physical_address;
		table_entry_size = sizeof(u64);
372 373 374
	} else {
		/* Root table is an RSDT (32-bit physical addresses) */

375 376
		address = (acpi_physical_address) rsdp->rsdt_physical_address;
		table_entry_size = sizeof(u32);
377
	}
B
Bob Moore 已提交
378

379 380 381 382 383 384 385
	/*
	 * It is not possible to map more than one entry in some environments,
	 * so unmap the RSDP here before mapping other tables
	 */
	acpi_os_unmap_memory(rsdp, sizeof(struct acpi_table_rsdp));

	/* Map the RSDT/XSDT table header to get the full table length */
B
Bob Moore 已提交
386

387 388
	table = acpi_os_map_memory(address, sizeof(struct acpi_table_header));
	if (!table) {
389
		return_ACPI_STATUS(AE_NO_MEMORY);
390 391
	}

392 393
	acpi_tb_print_table_header(address, table);

394 395 396 397 398 399 400 401
	/* Get the length of the full table, verify length and map entire table */

	length = table->length;
	acpi_os_unmap_memory(table, sizeof(struct acpi_table_header));

	if (length < sizeof(struct acpi_table_header)) {
		ACPI_ERROR((AE_INFO, "Invalid length 0x%X in RSDT/XSDT",
			    length));
402
		return_ACPI_STATUS(AE_INVALID_TABLE_LENGTH);
403 404 405 406
	}

	table = acpi_os_map_memory(address, length);
	if (!table) {
407
		return_ACPI_STATUS(AE_NO_MEMORY);
408 409 410 411
	}

	/* Validate the root table checksum */

412 413
	status = acpi_tb_verify_checksum(table, length);
	if (ACPI_FAILURE(status)) {
414
		acpi_os_unmap_memory(table, length);
415
		return_ACPI_STATUS(status);
416 417 418 419 420
	}

	/* Calculate the number of tables described in the root table */

	table_count =
B
Bob Moore 已提交
421 422
	    (u32) ((table->length -
		    sizeof(struct acpi_table_header)) / table_entry_size);
B
Bob Moore 已提交
423

424 425 426 427
	/*
	 * First two entries in the table array are reserved for the DSDT and FACS,
	 * which are not actually present in the RSDT/XSDT - they come from the FADT
	 */
428 429 430
	table_entry =
	    ACPI_CAST_PTR(u8, table) + sizeof(struct acpi_table_header);
	acpi_gbl_root_table_list.count = 2;
L
Linus Torvalds 已提交
431

432
	/*
433
	 * Initialize the root table array from the RSDT/XSDT
434
	 */
435
	for (i = 0; i < table_count; i++) {
436 437
		if (acpi_gbl_root_table_list.count >=
		    acpi_gbl_root_table_list.size) {
438 439 440

			/* There is no more room in the root table array, attempt resize */

441 442 443 444 445 446 447 448 449 450 451 452
			status = acpi_tb_resize_root_table_list();
			if (ACPI_FAILURE(status)) {
				ACPI_WARNING((AE_INFO,
					      "Truncating %u table entries!",
					      (unsigned)
					      (acpi_gbl_root_table_list.size -
					       acpi_gbl_root_table_list.
					       count)));
				break;
			}
		}

B
Bob Moore 已提交
453 454 455 456 457
		/* Get the table physical address (32-bit for RSDT, 64-bit for XSDT) */

		acpi_gbl_root_table_list.tables[acpi_gbl_root_table_list.count].
		    address =
		    acpi_tb_get_root_table_entry(table_entry, table_entry_size);
458

459
		table_entry += table_entry_size;
460
		acpi_gbl_root_table_list.count++;
L
Linus Torvalds 已提交
461
	}
B
Bob Moore 已提交
462

463 464 465 466 467 468
	/*
	 * It is not possible to map more than one entry in some environments,
	 * so unmap the root table here before mapping other tables
	 */
	acpi_os_unmap_memory(table, length);

469 470 471 472
	/*
	 * Complete the initialization of the root table array by examining
	 * the header of each table
	 */
473
	for (i = 2; i < acpi_gbl_root_table_list.count; i++) {
474 475
		acpi_tb_install_table(acpi_gbl_root_table_list.tables[i].
				      address, flags, NULL, i);
476

477
		/* Special case for FADT - get the DSDT and FACS */
478

479 480 481 482
		if (ACPI_COMPARE_NAME
		    (&acpi_gbl_root_table_list.tables[i].signature,
		     ACPI_SIG_FADT)) {
			acpi_tb_parse_fadt(i, flags);
483 484 485 486
		}
	}

	return_ACPI_STATUS(AE_OK);
L
Linus Torvalds 已提交
487
}