1
2
3
4
5
6
7
8
9
10#include <acpi/acpi.h>
11#include "accommon.h"
12#include "actables.h"
13
14#define _COMPONENT ACPI_TABLES
15ACPI_MODULE_NAME("tbutils")
16
17
18static acpi_physical_address
19acpi_tb_get_root_table_entry(u8 *table_entry, u32 table_entry_size);
20
21#if (!ACPI_REDUCED_HARDWARE)
22
23
24
25
26
27
28
29
30
31
32
33
34
35acpi_status acpi_tb_initialize_facs(void)
36{
37 struct acpi_table_facs *facs;
38
39
40
41 if (acpi_gbl_reduced_hardware) {
42 acpi_gbl_FACS = NULL;
43 return (AE_OK);
44 } else if (acpi_gbl_FADT.Xfacs &&
45 (!acpi_gbl_FADT.facs
46 || !acpi_gbl_use32_bit_facs_addresses)) {
47 (void)acpi_get_table_by_index(acpi_gbl_xfacs_index,
48 ACPI_CAST_INDIRECT_PTR(struct
49 acpi_table_header,
50 &facs));
51 acpi_gbl_FACS = facs;
52 } else if (acpi_gbl_FADT.facs) {
53 (void)acpi_get_table_by_index(acpi_gbl_facs_index,
54 ACPI_CAST_INDIRECT_PTR(struct
55 acpi_table_header,
56 &facs));
57 acpi_gbl_FACS = facs;
58 }
59
60
61
62 return (AE_OK);
63}
64#endif
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80void acpi_tb_check_dsdt_header(void)
81{
82
83
84
85 if (acpi_gbl_original_dsdt_header.length != acpi_gbl_DSDT->length ||
86 acpi_gbl_original_dsdt_header.checksum != acpi_gbl_DSDT->checksum) {
87 ACPI_BIOS_ERROR((AE_INFO,
88 "The DSDT has been corrupted or replaced - "
89 "old, new headers below"));
90
91 acpi_tb_print_table_header(0, &acpi_gbl_original_dsdt_header);
92 acpi_tb_print_table_header(0, acpi_gbl_DSDT);
93
94 ACPI_ERROR((AE_INFO,
95 "Please send DMI info to linux-acpi@vger.kernel.org\n"
96 "If system does not work as expected, please boot with acpi=copy_dsdt"));
97
98
99
100 acpi_gbl_original_dsdt_header.length = acpi_gbl_DSDT->length;
101 acpi_gbl_original_dsdt_header.checksum =
102 acpi_gbl_DSDT->checksum;
103 }
104}
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120struct acpi_table_header *acpi_tb_copy_dsdt(u32 table_index)
121{
122 struct acpi_table_header *new_table;
123 struct acpi_table_desc *table_desc;
124
125 table_desc = &acpi_gbl_root_table_list.tables[table_index];
126
127 new_table = ACPI_ALLOCATE(table_desc->length);
128 if (!new_table) {
129 ACPI_ERROR((AE_INFO, "Could not copy DSDT of length 0x%X",
130 table_desc->length));
131 return (NULL);
132 }
133
134 memcpy(new_table, table_desc->pointer, table_desc->length);
135 acpi_tb_uninstall_table(table_desc);
136
137 acpi_tb_init_table_descriptor(&acpi_gbl_root_table_list.
138 tables[acpi_gbl_dsdt_index],
139 ACPI_PTR_TO_PHYSADDR(new_table),
140 ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL,
141 new_table);
142
143 ACPI_INFO(("Forced DSDT copy: length 0x%05X copied locally, original unmapped", new_table->length));
144
145 return (new_table);
146}
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165static acpi_physical_address
166acpi_tb_get_root_table_entry(u8 *table_entry, u32 table_entry_size)
167{
168 u64 address64;
169
170
171
172
173
174 if (table_entry_size == ACPI_RSDT_ENTRY_SIZE) {
175
176
177
178
179 return ((acpi_physical_address)
180 (*ACPI_CAST_PTR(u32, table_entry)));
181 } else {
182
183
184
185
186
187 ACPI_MOVE_64_TO_64(&address64, table_entry);
188
189#if ACPI_MACHINE_WIDTH == 32
190 if (address64 > ACPI_UINT32_MAX) {
191
192
193
194 ACPI_BIOS_WARNING((AE_INFO,
195 "64-bit Physical Address in XSDT is too large (0x%8.8X%8.8X),"
196 " truncating",
197 ACPI_FORMAT_UINT64(address64)));
198 }
199#endif
200 return ((acpi_physical_address)(address64));
201 }
202}
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221acpi_status ACPI_INIT_FUNCTION
222acpi_tb_parse_root_table(acpi_physical_address rsdp_address)
223{
224 struct acpi_table_rsdp *rsdp;
225 u32 table_entry_size;
226 u32 i;
227 u32 table_count;
228 struct acpi_table_header *table;
229 acpi_physical_address address;
230 u32 length;
231 u8 *table_entry;
232 acpi_status status;
233 u32 table_index;
234
235 ACPI_FUNCTION_TRACE(tb_parse_root_table);
236
237
238
239 rsdp = acpi_os_map_memory(rsdp_address, sizeof(struct acpi_table_rsdp));
240 if (!rsdp) {
241 return_ACPI_STATUS(AE_NO_MEMORY);
242 }
243
244 acpi_tb_print_table_header(rsdp_address,
245 ACPI_CAST_PTR(struct acpi_table_header,
246 rsdp));
247
248
249
250 if ((rsdp->revision > 1) &&
251 rsdp->xsdt_physical_address && !acpi_gbl_do_not_use_xsdt) {
252
253
254
255
256
257 address = (acpi_physical_address)rsdp->xsdt_physical_address;
258 table_entry_size = ACPI_XSDT_ENTRY_SIZE;
259 } else {
260
261
262 address = (acpi_physical_address)rsdp->rsdt_physical_address;
263 table_entry_size = ACPI_RSDT_ENTRY_SIZE;
264 }
265
266
267
268
269
270 acpi_os_unmap_memory(rsdp, sizeof(struct acpi_table_rsdp));
271
272
273
274 table = acpi_os_map_memory(address, sizeof(struct acpi_table_header));
275 if (!table) {
276 return_ACPI_STATUS(AE_NO_MEMORY);
277 }
278
279 acpi_tb_print_table_header(address, table);
280
281
282
283
284
285 length = table->length;
286 acpi_os_unmap_memory(table, sizeof(struct acpi_table_header));
287
288 if (length < (sizeof(struct acpi_table_header) + table_entry_size)) {
289 ACPI_BIOS_ERROR((AE_INFO,
290 "Invalid table length 0x%X in RSDT/XSDT",
291 length));
292 return_ACPI_STATUS(AE_INVALID_TABLE_LENGTH);
293 }
294
295 table = acpi_os_map_memory(address, length);
296 if (!table) {
297 return_ACPI_STATUS(AE_NO_MEMORY);
298 }
299
300
301
302 status = acpi_tb_verify_checksum(table, length);
303 if (ACPI_FAILURE(status)) {
304 acpi_os_unmap_memory(table, length);
305 return_ACPI_STATUS(status);
306 }
307
308
309
310 table_count = (u32)((table->length - sizeof(struct acpi_table_header)) /
311 table_entry_size);
312 table_entry = ACPI_ADD_PTR(u8, table, sizeof(struct acpi_table_header));
313
314
315
316 for (i = 0; i < table_count; i++) {
317
318
319
320 address =
321 acpi_tb_get_root_table_entry(table_entry, table_entry_size);
322
323
324
325 if (!address) {
326 goto next_table;
327 }
328
329 status = acpi_tb_install_standard_table(address,
330 ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL,
331 FALSE, TRUE,
332 &table_index);
333
334 if (ACPI_SUCCESS(status) &&
335 ACPI_COMPARE_NAME(&acpi_gbl_root_table_list.
336 tables[table_index].signature,
337 ACPI_SIG_FADT)) {
338 acpi_gbl_fadt_index = table_index;
339 acpi_tb_parse_fadt();
340 }
341
342next_table:
343
344 table_entry += table_entry_size;
345 }
346
347 acpi_os_unmap_memory(table, length);
348 return_ACPI_STATUS(AE_OK);
349}
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367acpi_status
368acpi_tb_get_table(struct acpi_table_desc *table_desc,
369 struct acpi_table_header **out_table)
370{
371 acpi_status status;
372
373 ACPI_FUNCTION_TRACE(acpi_tb_get_table);
374
375 if (table_desc->validation_count == 0) {
376
377
378
379 status = acpi_tb_validate_table(table_desc);
380 if (ACPI_FAILURE(status)) {
381 return_ACPI_STATUS(status);
382 }
383 }
384
385 if (table_desc->validation_count < ACPI_MAX_TABLE_VALIDATIONS) {
386 table_desc->validation_count++;
387
388
389
390
391
392 if (table_desc->validation_count >= ACPI_MAX_TABLE_VALIDATIONS) {
393 ACPI_WARNING((AE_INFO,
394 "Table %p, Validation count overflows\n",
395 table_desc));
396 }
397 }
398
399 *out_table = table_desc->pointer;
400 return_ACPI_STATUS(AE_OK);
401}
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418void acpi_tb_put_table(struct acpi_table_desc *table_desc)
419{
420
421 ACPI_FUNCTION_TRACE(acpi_tb_put_table);
422
423 if (table_desc->validation_count < ACPI_MAX_TABLE_VALIDATIONS) {
424 table_desc->validation_count--;
425
426
427
428
429
430 if (table_desc->validation_count >= ACPI_MAX_TABLE_VALIDATIONS) {
431 ACPI_WARNING((AE_INFO,
432 "Table %p, Validation count underflows\n",
433 table_desc));
434 return_VOID;
435 }
436 }
437
438 if (table_desc->validation_count == 0) {
439
440
441
442 acpi_tb_invalidate_table(table_desc);
443 }
444
445 return_VOID;
446}
447