Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /****************************************************************************** |
2 | * | |
3 | * Module Name: tbxfroot - Find the root ACPI table (RSDT) | |
4 | * | |
5 | *****************************************************************************/ | |
6 | ||
7 | /* | |
8 | * Copyright (C) 2000 - 2005, R. Byron Moore | |
9 | * 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 | ||
44 | #include <linux/module.h> | |
45 | ||
46 | #include <acpi/acpi.h> | |
47 | #include <acpi/actables.h> | |
48 | ||
1da177e4 | 49 | #define _COMPONENT ACPI_TABLES |
4be44fcd | 50 | ACPI_MODULE_NAME("tbxfroot") |
1da177e4 | 51 | |
44f6c012 | 52 | /* Local prototypes */ |
44f6c012 | 53 | static acpi_status |
4be44fcd | 54 | acpi_tb_find_rsdp(struct acpi_table_desc *table_info, u32 flags); |
44f6c012 | 55 | |
4be44fcd | 56 | static u8 *acpi_tb_scan_memory_for_rsdp(u8 * start_address, u32 length); |
1da177e4 | 57 | |
f9f4601f RM |
58 | /******************************************************************************* |
59 | * | |
60 | * FUNCTION: acpi_tb_validate_rsdp | |
61 | * | |
62 | * PARAMETERS: Rsdp - Pointer to unvalidated RSDP | |
63 | * | |
64 | * RETURN: Status | |
65 | * | |
66 | * DESCRIPTION: Validate the RSDP (ptr) | |
67 | * | |
68 | ******************************************************************************/ | |
69 | ||
4be44fcd | 70 | acpi_status acpi_tb_validate_rsdp(struct rsdp_descriptor *rsdp) |
f9f4601f | 71 | { |
4be44fcd | 72 | ACPI_FUNCTION_ENTRY(); |
f9f4601f RM |
73 | |
74 | /* | |
75 | * The signature and checksum must both be correct | |
76 | */ | |
4be44fcd | 77 | if (ACPI_STRNCMP((char *)rsdp, RSDP_SIG, sizeof(RSDP_SIG) - 1) != 0) { |
f9f4601f RM |
78 | /* Nope, BAD Signature */ |
79 | ||
80 | return (AE_BAD_SIGNATURE); | |
81 | } | |
82 | ||
83 | /* Check the standard checksum */ | |
84 | ||
4be44fcd | 85 | if (acpi_tb_generate_checksum(rsdp, ACPI_RSDP_CHECKSUM_LENGTH) != 0) { |
f9f4601f RM |
86 | return (AE_BAD_CHECKSUM); |
87 | } | |
88 | ||
89 | /* Check extended checksum if table version >= 2 */ | |
90 | ||
91 | if ((rsdp->revision >= 2) && | |
4be44fcd LB |
92 | (acpi_tb_generate_checksum(rsdp, ACPI_RSDP_XCHECKSUM_LENGTH) != |
93 | 0)) { | |
f9f4601f RM |
94 | return (AE_BAD_CHECKSUM); |
95 | } | |
96 | ||
97 | return (AE_OK); | |
98 | } | |
99 | ||
1da177e4 LT |
100 | /******************************************************************************* |
101 | * | |
102 | * FUNCTION: acpi_tb_find_table | |
103 | * | |
104 | * PARAMETERS: Signature - String with ACPI table signature | |
105 | * oem_id - String with the table OEM ID | |
44f6c012 RM |
106 | * oem_table_id - String with the OEM Table ID |
107 | * table_ptr - Where the table pointer is returned | |
1da177e4 LT |
108 | * |
109 | * RETURN: Status | |
110 | * | |
111 | * DESCRIPTION: Find an ACPI table (in the RSDT/XSDT) that matches the | |
112 | * Signature, OEM ID and OEM Table ID. | |
113 | * | |
114 | ******************************************************************************/ | |
115 | ||
116 | acpi_status | |
4be44fcd LB |
117 | acpi_tb_find_table(char *signature, |
118 | char *oem_id, | |
119 | char *oem_table_id, struct acpi_table_header ** table_ptr) | |
1da177e4 | 120 | { |
4be44fcd LB |
121 | acpi_status status; |
122 | struct acpi_table_header *table; | |
1da177e4 | 123 | |
4be44fcd | 124 | ACPI_FUNCTION_TRACE("tb_find_table"); |
1da177e4 LT |
125 | |
126 | /* Validate string lengths */ | |
127 | ||
4be44fcd LB |
128 | if ((ACPI_STRLEN(signature) > ACPI_NAME_SIZE) || |
129 | (ACPI_STRLEN(oem_id) > sizeof(table->oem_id)) || | |
130 | (ACPI_STRLEN(oem_table_id) > sizeof(table->oem_table_id))) { | |
131 | return_ACPI_STATUS(AE_AML_STRING_LIMIT); | |
1da177e4 LT |
132 | } |
133 | ||
4be44fcd | 134 | if (!ACPI_STRNCMP(signature, DSDT_SIG, ACPI_NAME_SIZE)) { |
1da177e4 LT |
135 | /* |
136 | * The DSDT pointer is contained in the FADT, not the RSDT. | |
137 | * This code should suffice, because the only code that would perform | |
138 | * a "find" on the DSDT is the data_table_region() AML opcode -- in | |
139 | * which case, the DSDT is guaranteed to be already loaded. | |
140 | * If this becomes insufficient, the FADT will have to be found first. | |
141 | */ | |
142 | if (!acpi_gbl_DSDT) { | |
4be44fcd | 143 | return_ACPI_STATUS(AE_NO_ACPI_TABLES); |
1da177e4 | 144 | } |
1da177e4 | 145 | table = acpi_gbl_DSDT; |
4be44fcd | 146 | } else { |
1da177e4 LT |
147 | /* Find the table */ |
148 | ||
4be44fcd LB |
149 | status = acpi_get_firmware_table(signature, 1, |
150 | ACPI_LOGICAL_ADDRESSING, | |
151 | &table); | |
152 | if (ACPI_FAILURE(status)) { | |
153 | return_ACPI_STATUS(status); | |
1da177e4 LT |
154 | } |
155 | } | |
156 | ||
157 | /* Check oem_id and oem_table_id */ | |
158 | ||
4be44fcd LB |
159 | if ((oem_id[0] && ACPI_STRNCMP(oem_id, table->oem_id, |
160 | sizeof(table->oem_id))) || | |
161 | (oem_table_id[0] && ACPI_STRNCMP(oem_table_id, table->oem_table_id, | |
162 | sizeof(table->oem_table_id)))) { | |
163 | return_ACPI_STATUS(AE_AML_NAME_NOT_FOUND); | |
1da177e4 LT |
164 | } |
165 | ||
4be44fcd LB |
166 | ACPI_DEBUG_PRINT((ACPI_DB_TABLES, "Found table [%4.4s]\n", |
167 | table->signature)); | |
44f6c012 | 168 | |
1da177e4 | 169 | *table_ptr = table; |
4be44fcd | 170 | return_ACPI_STATUS(AE_OK); |
1da177e4 LT |
171 | } |
172 | ||
1da177e4 LT |
173 | /******************************************************************************* |
174 | * | |
175 | * FUNCTION: acpi_get_firmware_table | |
176 | * | |
177 | * PARAMETERS: Signature - Any ACPI table signature | |
178 | * Instance - the non zero instance of the table, allows | |
179 | * support for multiple tables of the same type | |
180 | * Flags - Physical/Virtual support | |
181 | * table_pointer - Where a buffer containing the table is | |
182 | * returned | |
183 | * | |
184 | * RETURN: Status | |
185 | * | |
186 | * DESCRIPTION: This function is called to get an ACPI table. A buffer is | |
187 | * allocated for the table and returned in table_pointer. | |
188 | * This table will be a complete table including the header. | |
189 | * | |
190 | ******************************************************************************/ | |
191 | ||
192 | acpi_status | |
4be44fcd LB |
193 | acpi_get_firmware_table(acpi_string signature, |
194 | u32 instance, | |
195 | u32 flags, struct acpi_table_header **table_pointer) | |
1da177e4 | 196 | { |
4be44fcd LB |
197 | acpi_status status; |
198 | struct acpi_pointer address; | |
199 | struct acpi_table_header *header = NULL; | |
200 | struct acpi_table_desc *table_info = NULL; | |
201 | struct acpi_table_desc *rsdt_info; | |
202 | u32 table_count; | |
203 | u32 i; | |
204 | u32 j; | |
1da177e4 | 205 | |
4be44fcd | 206 | ACPI_FUNCTION_TRACE("acpi_get_firmware_table"); |
1da177e4 LT |
207 | |
208 | /* | |
209 | * Ensure that at least the table manager is initialized. We don't | |
210 | * require that the entire ACPI subsystem is up for this interface. | |
211 | * If we have a buffer, we must have a length too | |
212 | */ | |
4be44fcd LB |
213 | if ((instance == 0) || (!signature) || (!table_pointer)) { |
214 | return_ACPI_STATUS(AE_BAD_PARAMETER); | |
1da177e4 LT |
215 | } |
216 | ||
217 | /* Ensure that we have a RSDP */ | |
218 | ||
219 | if (!acpi_gbl_RSDP) { | |
220 | /* Get the RSDP */ | |
221 | ||
4be44fcd LB |
222 | status = acpi_os_get_root_pointer(flags, &address); |
223 | if (ACPI_FAILURE(status)) { | |
224 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "RSDP not found\n")); | |
225 | return_ACPI_STATUS(AE_NO_ACPI_TABLES); | |
1da177e4 LT |
226 | } |
227 | ||
228 | /* Map and validate the RSDP */ | |
229 | ||
230 | if ((flags & ACPI_MEMORY_MODE) == ACPI_LOGICAL_ADDRESSING) { | |
4be44fcd LB |
231 | status = acpi_os_map_memory(address.pointer.physical, |
232 | sizeof(struct | |
233 | rsdp_descriptor), | |
234 | (void *)&acpi_gbl_RSDP); | |
235 | if (ACPI_FAILURE(status)) { | |
236 | return_ACPI_STATUS(status); | |
1da177e4 | 237 | } |
4be44fcd | 238 | } else { |
1da177e4 LT |
239 | acpi_gbl_RSDP = address.pointer.logical; |
240 | } | |
241 | ||
f9f4601f | 242 | /* The RDSP signature and checksum must both be correct */ |
1da177e4 | 243 | |
4be44fcd LB |
244 | status = acpi_tb_validate_rsdp(acpi_gbl_RSDP); |
245 | if (ACPI_FAILURE(status)) { | |
246 | return_ACPI_STATUS(status); | |
1da177e4 LT |
247 | } |
248 | } | |
249 | ||
250 | /* Get the RSDT address via the RSDP */ | |
251 | ||
4be44fcd LB |
252 | acpi_tb_get_rsdt_address(&address); |
253 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, | |
50eca3eb | 254 | "RSDP located at %p, RSDT physical=%8.8X%8.8X\n", |
4be44fcd LB |
255 | acpi_gbl_RSDP, |
256 | ACPI_FORMAT_UINT64(address.pointer.value))); | |
1da177e4 LT |
257 | |
258 | /* Insert processor_mode flags */ | |
259 | ||
260 | address.pointer_type |= flags; | |
261 | ||
262 | /* Get and validate the RSDT */ | |
263 | ||
4be44fcd | 264 | rsdt_info = ACPI_MEM_CALLOCATE(sizeof(struct acpi_table_desc)); |
1da177e4 | 265 | if (!rsdt_info) { |
4be44fcd | 266 | return_ACPI_STATUS(AE_NO_MEMORY); |
1da177e4 LT |
267 | } |
268 | ||
4be44fcd LB |
269 | status = acpi_tb_get_table(&address, rsdt_info); |
270 | if (ACPI_FAILURE(status)) { | |
1da177e4 LT |
271 | goto cleanup; |
272 | } | |
273 | ||
4be44fcd LB |
274 | status = acpi_tb_validate_rsdt(rsdt_info->pointer); |
275 | if (ACPI_FAILURE(status)) { | |
1da177e4 LT |
276 | goto cleanup; |
277 | } | |
278 | ||
279 | /* Allocate a scratch table header and table descriptor */ | |
280 | ||
4be44fcd | 281 | header = ACPI_MEM_ALLOCATE(sizeof(struct acpi_table_header)); |
1da177e4 LT |
282 | if (!header) { |
283 | status = AE_NO_MEMORY; | |
284 | goto cleanup; | |
285 | } | |
286 | ||
4be44fcd | 287 | table_info = ACPI_MEM_ALLOCATE(sizeof(struct acpi_table_desc)); |
1da177e4 LT |
288 | if (!table_info) { |
289 | status = AE_NO_MEMORY; | |
290 | goto cleanup; | |
291 | } | |
292 | ||
293 | /* Get the number of table pointers within the RSDT */ | |
294 | ||
4be44fcd LB |
295 | table_count = |
296 | acpi_tb_get_table_count(acpi_gbl_RSDP, rsdt_info->pointer); | |
1da177e4 LT |
297 | address.pointer_type = acpi_gbl_table_flags | flags; |
298 | ||
299 | /* | |
300 | * Search the RSDT/XSDT for the correct instance of the | |
301 | * requested table | |
302 | */ | |
303 | for (i = 0, j = 0; i < table_count; i++) { | |
73459f73 RM |
304 | /* |
305 | * Get the next table pointer, handle RSDT vs. XSDT | |
306 | * RSDT pointers are 32 bits, XSDT pointers are 64 bits | |
307 | */ | |
308 | if (acpi_gbl_root_table_type == ACPI_TABLE_TYPE_RSDT) { | |
4be44fcd LB |
309 | address.pointer.value = |
310 | (ACPI_CAST_PTR | |
311 | (RSDT_DESCRIPTOR, | |
312 | rsdt_info->pointer))->table_offset_entry[i]; | |
313 | } else { | |
314 | address.pointer.value = | |
315 | (ACPI_CAST_PTR | |
316 | (XSDT_DESCRIPTOR, | |
317 | rsdt_info->pointer))->table_offset_entry[i]; | |
1da177e4 LT |
318 | } |
319 | ||
320 | /* Get the table header */ | |
321 | ||
4be44fcd LB |
322 | status = acpi_tb_get_table_header(&address, header); |
323 | if (ACPI_FAILURE(status)) { | |
1da177e4 LT |
324 | goto cleanup; |
325 | } | |
326 | ||
327 | /* Compare table signatures and table instance */ | |
328 | ||
4be44fcd | 329 | if (!ACPI_STRNCMP(header->signature, signature, ACPI_NAME_SIZE)) { |
1da177e4 LT |
330 | /* An instance of the table was found */ |
331 | ||
332 | j++; | |
333 | if (j >= instance) { | |
334 | /* Found the correct instance, get the entire table */ | |
335 | ||
4be44fcd LB |
336 | status = |
337 | acpi_tb_get_table_body(&address, header, | |
338 | table_info); | |
339 | if (ACPI_FAILURE(status)) { | |
1da177e4 LT |
340 | goto cleanup; |
341 | } | |
342 | ||
343 | *table_pointer = table_info->pointer; | |
344 | goto cleanup; | |
345 | } | |
346 | } | |
347 | } | |
348 | ||
349 | /* Did not find the table */ | |
350 | ||
351 | status = AE_NOT_EXIST; | |
352 | ||
4be44fcd | 353 | cleanup: |
88ac00f5 | 354 | if (rsdt_info->pointer) { |
4be44fcd LB |
355 | acpi_os_unmap_memory(rsdt_info->pointer, |
356 | (acpi_size) rsdt_info->pointer->length); | |
88ac00f5 | 357 | } |
4be44fcd | 358 | ACPI_MEM_FREE(rsdt_info); |
1da177e4 LT |
359 | |
360 | if (header) { | |
4be44fcd | 361 | ACPI_MEM_FREE(header); |
1da177e4 LT |
362 | } |
363 | if (table_info) { | |
4be44fcd | 364 | ACPI_MEM_FREE(table_info); |
1da177e4 | 365 | } |
4be44fcd | 366 | return_ACPI_STATUS(status); |
1da177e4 | 367 | } |
1da177e4 | 368 | |
4be44fcd | 369 | EXPORT_SYMBOL(acpi_get_firmware_table); |
1da177e4 LT |
370 | |
371 | /* TBD: Move to a new file */ | |
372 | ||
373 | #if ACPI_MACHINE_WIDTH != 16 | |
374 | ||
375 | /******************************************************************************* | |
376 | * | |
377 | * FUNCTION: acpi_find_root_pointer | |
378 | * | |
44f6c012 RM |
379 | * PARAMETERS: Flags - Logical/Physical addressing |
380 | * rsdp_address - Where to place the RSDP address | |
1da177e4 LT |
381 | * |
382 | * RETURN: Status, Physical address of the RSDP | |
383 | * | |
384 | * DESCRIPTION: Find the RSDP | |
385 | * | |
386 | ******************************************************************************/ | |
387 | ||
4be44fcd | 388 | acpi_status acpi_find_root_pointer(u32 flags, struct acpi_pointer *rsdp_address) |
1da177e4 | 389 | { |
4be44fcd LB |
390 | struct acpi_table_desc table_info; |
391 | acpi_status status; | |
1da177e4 | 392 | |
4be44fcd | 393 | ACPI_FUNCTION_TRACE("acpi_find_root_pointer"); |
1da177e4 LT |
394 | |
395 | /* Get the RSDP */ | |
396 | ||
4be44fcd LB |
397 | status = acpi_tb_find_rsdp(&table_info, flags); |
398 | if (ACPI_FAILURE(status)) { | |
399 | ACPI_DEBUG_PRINT((ACPI_DB_ERROR, | |
400 | "RSDP structure not found, %s Flags=%X\n", | |
401 | acpi_format_exception(status), flags)); | |
44f6c012 | 402 | |
4be44fcd | 403 | return_ACPI_STATUS(AE_NO_ACPI_TABLES); |
1da177e4 LT |
404 | } |
405 | ||
406 | rsdp_address->pointer_type = ACPI_PHYSICAL_POINTER; | |
407 | rsdp_address->pointer.physical = table_info.physical_address; | |
4be44fcd | 408 | return_ACPI_STATUS(AE_OK); |
1da177e4 LT |
409 | } |
410 | ||
1da177e4 LT |
411 | /******************************************************************************* |
412 | * | |
413 | * FUNCTION: acpi_tb_scan_memory_for_rsdp | |
414 | * | |
415 | * PARAMETERS: start_address - Starting pointer for search | |
416 | * Length - Maximum length to search | |
417 | * | |
418 | * RETURN: Pointer to the RSDP if found, otherwise NULL. | |
419 | * | |
420 | * DESCRIPTION: Search a block of memory for the RSDP signature | |
421 | * | |
422 | ******************************************************************************/ | |
423 | ||
4be44fcd | 424 | static u8 *acpi_tb_scan_memory_for_rsdp(u8 * start_address, u32 length) |
1da177e4 | 425 | { |
4be44fcd LB |
426 | acpi_status status; |
427 | u8 *mem_rover; | |
428 | u8 *end_address; | |
1da177e4 | 429 | |
4be44fcd | 430 | ACPI_FUNCTION_TRACE("tb_scan_memory_for_rsdp"); |
1da177e4 LT |
431 | |
432 | end_address = start_address + length; | |
433 | ||
434 | /* Search from given start address for the requested length */ | |
435 | ||
436 | for (mem_rover = start_address; mem_rover < end_address; | |
4be44fcd | 437 | mem_rover += ACPI_RSDP_SCAN_STEP) { |
f9f4601f | 438 | /* The RSDP signature and checksum must both be correct */ |
1da177e4 | 439 | |
4be44fcd LB |
440 | status = |
441 | acpi_tb_validate_rsdp(ACPI_CAST_PTR | |
442 | (struct rsdp_descriptor, mem_rover)); | |
443 | if (ACPI_SUCCESS(status)) { | |
f9f4601f | 444 | /* Sig and checksum valid, we have found a real RSDP */ |
1da177e4 | 445 | |
4be44fcd LB |
446 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, |
447 | "RSDP located at physical address %p\n", | |
448 | mem_rover)); | |
449 | return_PTR(mem_rover); | |
1da177e4 LT |
450 | } |
451 | ||
f9f4601f | 452 | /* No sig match or bad checksum, keep searching */ |
1da177e4 LT |
453 | } |
454 | ||
455 | /* Searched entire block, no RSDP was found */ | |
456 | ||
4be44fcd LB |
457 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, |
458 | "Searched entire block from %p, valid RSDP was not found\n", | |
459 | start_address)); | |
460 | return_PTR(NULL); | |
1da177e4 LT |
461 | } |
462 | ||
1da177e4 LT |
463 | /******************************************************************************* |
464 | * | |
465 | * FUNCTION: acpi_tb_find_rsdp | |
466 | * | |
44f6c012 | 467 | * PARAMETERS: table_info - Where the table info is returned |
1da177e4 LT |
468 | * Flags - Current memory mode (logical vs. |
469 | * physical addressing) | |
470 | * | |
471 | * RETURN: Status, RSDP physical address | |
472 | * | |
473 | * DESCRIPTION: search lower 1_mbyte of memory for the root system descriptor | |
474 | * pointer structure. If it is found, set *RSDP to point to it. | |
475 | * | |
476 | * NOTE1: The RSDp must be either in the first 1_k of the Extended | |
477 | * BIOS Data Area or between E0000 and FFFFF (From ACPI Spec.) | |
478 | * Only a 32-bit physical address is necessary. | |
479 | * | |
480 | * NOTE2: This function is always available, regardless of the | |
481 | * initialization state of the rest of ACPI. | |
482 | * | |
483 | ******************************************************************************/ | |
484 | ||
44f6c012 | 485 | static acpi_status |
4be44fcd | 486 | acpi_tb_find_rsdp(struct acpi_table_desc *table_info, u32 flags) |
1da177e4 | 487 | { |
4be44fcd LB |
488 | u8 *table_ptr; |
489 | u8 *mem_rover; | |
490 | u32 physical_address; | |
491 | acpi_status status; | |
1da177e4 | 492 | |
4be44fcd | 493 | ACPI_FUNCTION_TRACE("tb_find_rsdp"); |
1da177e4 LT |
494 | |
495 | /* | |
44f6c012 | 496 | * Scan supports either logical addressing or physical addressing |
1da177e4 LT |
497 | */ |
498 | if ((flags & ACPI_MEMORY_MODE) == ACPI_LOGICAL_ADDRESSING) { | |
44f6c012 RM |
499 | /* 1a) Get the location of the Extended BIOS Data Area (EBDA) */ |
500 | ||
4be44fcd LB |
501 | status = acpi_os_map_memory((acpi_physical_address) |
502 | ACPI_EBDA_PTR_LOCATION, | |
503 | ACPI_EBDA_PTR_LENGTH, | |
504 | (void *)&table_ptr); | |
505 | if (ACPI_FAILURE(status)) { | |
506 | ACPI_DEBUG_PRINT((ACPI_DB_ERROR, | |
507 | "Could not map memory at %8.8X for length %X\n", | |
508 | ACPI_EBDA_PTR_LOCATION, | |
509 | ACPI_EBDA_PTR_LENGTH)); | |
510 | ||
511 | return_ACPI_STATUS(status); | |
1da177e4 LT |
512 | } |
513 | ||
4be44fcd | 514 | ACPI_MOVE_16_TO_32(&physical_address, table_ptr); |
44f6c012 RM |
515 | |
516 | /* Convert segment part to physical address */ | |
517 | ||
518 | physical_address <<= 4; | |
4be44fcd | 519 | acpi_os_unmap_memory(table_ptr, ACPI_EBDA_PTR_LENGTH); |
1da177e4 LT |
520 | |
521 | /* EBDA present? */ | |
522 | ||
523 | if (physical_address > 0x400) { | |
524 | /* | |
44f6c012 RM |
525 | * 1b) Search EBDA paragraphs (EBDa is required to be a |
526 | * minimum of 1_k length) | |
1da177e4 | 527 | */ |
4be44fcd LB |
528 | status = acpi_os_map_memory((acpi_physical_address) |
529 | physical_address, | |
530 | ACPI_EBDA_WINDOW_SIZE, | |
531 | (void *)&table_ptr); | |
532 | if (ACPI_FAILURE(status)) { | |
533 | ACPI_DEBUG_PRINT((ACPI_DB_ERROR, | |
534 | "Could not map memory at %8.8X for length %X\n", | |
535 | physical_address, | |
536 | ACPI_EBDA_WINDOW_SIZE)); | |
537 | ||
538 | return_ACPI_STATUS(status); | |
1da177e4 LT |
539 | } |
540 | ||
4be44fcd LB |
541 | mem_rover = acpi_tb_scan_memory_for_rsdp(table_ptr, |
542 | ACPI_EBDA_WINDOW_SIZE); | |
543 | acpi_os_unmap_memory(table_ptr, ACPI_EBDA_WINDOW_SIZE); | |
1da177e4 LT |
544 | |
545 | if (mem_rover) { | |
f9f4601f | 546 | /* Return the physical address */ |
1da177e4 | 547 | |
4be44fcd LB |
548 | physical_address += |
549 | ACPI_PTR_DIFF(mem_rover, table_ptr); | |
1da177e4 | 550 | |
44f6c012 | 551 | table_info->physical_address = |
4be44fcd LB |
552 | (acpi_physical_address) physical_address; |
553 | return_ACPI_STATUS(AE_OK); | |
1da177e4 LT |
554 | } |
555 | } | |
556 | ||
557 | /* | |
558 | * 2) Search upper memory: 16-byte boundaries in E0000h-FFFFFh | |
559 | */ | |
4be44fcd LB |
560 | status = acpi_os_map_memory((acpi_physical_address) |
561 | ACPI_HI_RSDP_WINDOW_BASE, | |
562 | ACPI_HI_RSDP_WINDOW_SIZE, | |
563 | (void *)&table_ptr); | |
564 | ||
565 | if (ACPI_FAILURE(status)) { | |
566 | ACPI_DEBUG_PRINT((ACPI_DB_ERROR, | |
567 | "Could not map memory at %8.8X for length %X\n", | |
568 | ACPI_HI_RSDP_WINDOW_BASE, | |
569 | ACPI_HI_RSDP_WINDOW_SIZE)); | |
570 | ||
571 | return_ACPI_STATUS(status); | |
1da177e4 LT |
572 | } |
573 | ||
4be44fcd LB |
574 | mem_rover = |
575 | acpi_tb_scan_memory_for_rsdp(table_ptr, | |
576 | ACPI_HI_RSDP_WINDOW_SIZE); | |
577 | acpi_os_unmap_memory(table_ptr, ACPI_HI_RSDP_WINDOW_SIZE); | |
1da177e4 LT |
578 | |
579 | if (mem_rover) { | |
f9f4601f | 580 | /* Return the physical address */ |
1da177e4 | 581 | |
44f6c012 | 582 | physical_address = |
4be44fcd LB |
583 | ACPI_HI_RSDP_WINDOW_BASE + ACPI_PTR_DIFF(mem_rover, |
584 | table_ptr); | |
1da177e4 | 585 | |
44f6c012 | 586 | table_info->physical_address = |
4be44fcd LB |
587 | (acpi_physical_address) physical_address; |
588 | return_ACPI_STATUS(AE_OK); | |
1da177e4 LT |
589 | } |
590 | } | |
591 | ||
592 | /* | |
593 | * Physical addressing | |
594 | */ | |
595 | else { | |
44f6c012 RM |
596 | /* 1a) Get the location of the EBDA */ |
597 | ||
4be44fcd LB |
598 | ACPI_MOVE_16_TO_32(&physical_address, ACPI_EBDA_PTR_LOCATION); |
599 | physical_address <<= 4; /* Convert segment to physical address */ | |
1da177e4 LT |
600 | |
601 | /* EBDA present? */ | |
602 | ||
603 | if (physical_address > 0x400) { | |
604 | /* | |
44f6c012 RM |
605 | * 1b) Search EBDA paragraphs (EBDa is required to be a minimum of |
606 | * 1_k length) | |
1da177e4 | 607 | */ |
4be44fcd LB |
608 | mem_rover = |
609 | acpi_tb_scan_memory_for_rsdp(ACPI_PHYSADDR_TO_PTR | |
610 | (physical_address), | |
611 | ACPI_EBDA_WINDOW_SIZE); | |
1da177e4 | 612 | if (mem_rover) { |
f9f4601f | 613 | /* Return the physical address */ |
1da177e4 | 614 | |
4be44fcd LB |
615 | table_info->physical_address = |
616 | ACPI_TO_INTEGER(mem_rover); | |
617 | return_ACPI_STATUS(AE_OK); | |
1da177e4 LT |
618 | } |
619 | } | |
620 | ||
44f6c012 RM |
621 | /* 2) Search upper memory: 16-byte boundaries in E0000h-FFFFFh */ |
622 | ||
4be44fcd LB |
623 | mem_rover = |
624 | acpi_tb_scan_memory_for_rsdp(ACPI_PHYSADDR_TO_PTR | |
625 | (ACPI_HI_RSDP_WINDOW_BASE), | |
626 | ACPI_HI_RSDP_WINDOW_SIZE); | |
1da177e4 LT |
627 | if (mem_rover) { |
628 | /* Found it, return the physical address */ | |
629 | ||
4be44fcd LB |
630 | table_info->physical_address = |
631 | ACPI_TO_INTEGER(mem_rover); | |
632 | return_ACPI_STATUS(AE_OK); | |
1da177e4 LT |
633 | } |
634 | } | |
635 | ||
f9f4601f | 636 | /* A valid RSDP was not found */ |
1da177e4 | 637 | |
4be44fcd LB |
638 | ACPI_REPORT_ERROR(("No valid RSDP was found\n")); |
639 | return_ACPI_STATUS(AE_NOT_FOUND); | |
1da177e4 LT |
640 | } |
641 | ||
642 | #endif |