summaryrefslogtreecommitdiffstats
path: root/drivers/acpi/tables.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/acpi/tables.c')
-rw-r--r--drivers/acpi/tables.c76
1 files changed, 66 insertions, 10 deletions
diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c
index d7bf936b1646..3b5d04fd5e3e 100644
--- a/drivers/acpi/tables.c
+++ b/drivers/acpi/tables.c
@@ -49,6 +49,16 @@ static struct acpi_table_desc initial_tables[ACPI_MAX_TABLES] __initdata;
49 49
50static int acpi_apic_instance __initdata; 50static int acpi_apic_instance __initdata;
51 51
52enum acpi_subtable_type {
53 ACPI_SUBTABLE_COMMON,
54 ACPI_SUBTABLE_HMAT,
55};
56
57struct acpi_subtable_entry {
58 union acpi_subtable_headers *hdr;
59 enum acpi_subtable_type type;
60};
61
52/* 62/*
53 * Disable table checksum verification for the early stage due to the size 63 * Disable table checksum verification for the early stage due to the size
54 * limitation of the current x86 early mapping implementation. 64 * limitation of the current x86 early mapping implementation.
@@ -217,6 +227,50 @@ void acpi_table_print_madt_entry(struct acpi_subtable_header *header)
217 } 227 }
218} 228}
219 229
230static unsigned long __init
231acpi_get_entry_type(struct acpi_subtable_entry *entry)
232{
233 switch (entry->type) {
234 case ACPI_SUBTABLE_COMMON:
235 return entry->hdr->common.type;
236 case ACPI_SUBTABLE_HMAT:
237 return entry->hdr->hmat.type;
238 }
239 return 0;
240}
241
242static unsigned long __init
243acpi_get_entry_length(struct acpi_subtable_entry *entry)
244{
245 switch (entry->type) {
246 case ACPI_SUBTABLE_COMMON:
247 return entry->hdr->common.length;
248 case ACPI_SUBTABLE_HMAT:
249 return entry->hdr->hmat.length;
250 }
251 return 0;
252}
253
254static unsigned long __init
255acpi_get_subtable_header_length(struct acpi_subtable_entry *entry)
256{
257 switch (entry->type) {
258 case ACPI_SUBTABLE_COMMON:
259 return sizeof(entry->hdr->common);
260 case ACPI_SUBTABLE_HMAT:
261 return sizeof(entry->hdr->hmat);
262 }
263 return 0;
264}
265
266static enum acpi_subtable_type __init
267acpi_get_subtable_type(char *id)
268{
269 if (strncmp(id, ACPI_SIG_HMAT, 4) == 0)
270 return ACPI_SUBTABLE_HMAT;
271 return ACPI_SUBTABLE_COMMON;
272}
273
220/** 274/**
221 * acpi_parse_entries_array - for each proc_num find a suitable subtable 275 * acpi_parse_entries_array - for each proc_num find a suitable subtable
222 * 276 *
@@ -245,8 +299,8 @@ static int __init acpi_parse_entries_array(char *id, unsigned long table_size,
245 struct acpi_subtable_proc *proc, int proc_num, 299 struct acpi_subtable_proc *proc, int proc_num,
246 unsigned int max_entries) 300 unsigned int max_entries)
247{ 301{
248 struct acpi_subtable_header *entry; 302 struct acpi_subtable_entry entry;
249 unsigned long table_end; 303 unsigned long table_end, subtable_len, entry_len;
250 int count = 0; 304 int count = 0;
251 int errs = 0; 305 int errs = 0;
252 int i; 306 int i;
@@ -269,19 +323,20 @@ static int __init acpi_parse_entries_array(char *id, unsigned long table_size,
269 323
270 /* Parse all entries looking for a match. */ 324 /* Parse all entries looking for a match. */
271 325
272 entry = (struct acpi_subtable_header *) 326 entry.type = acpi_get_subtable_type(id);
327 entry.hdr = (union acpi_subtable_headers *)
273 ((unsigned long)table_header + table_size); 328 ((unsigned long)table_header + table_size);
329 subtable_len = acpi_get_subtable_header_length(&entry);
274 330
275 while (((unsigned long)entry) + sizeof(struct acpi_subtable_header) < 331 while (((unsigned long)entry.hdr) + subtable_len < table_end) {
276 table_end) {
277 if (max_entries && count >= max_entries) 332 if (max_entries && count >= max_entries)
278 break; 333 break;
279 334
280 for (i = 0; i < proc_num; i++) { 335 for (i = 0; i < proc_num; i++) {
281 if (entry->type != proc[i].id) 336 if (acpi_get_entry_type(&entry) != proc[i].id)
282 continue; 337 continue;
283 if (!proc[i].handler || 338 if (!proc[i].handler ||
284 (!errs && proc[i].handler(entry, table_end))) { 339 (!errs && proc[i].handler(entry.hdr, table_end))) {
285 errs++; 340 errs++;
286 continue; 341 continue;
287 } 342 }
@@ -296,13 +351,14 @@ static int __init acpi_parse_entries_array(char *id, unsigned long table_size,
296 * If entry->length is 0, break from this loop to avoid 351 * If entry->length is 0, break from this loop to avoid
297 * infinite loop. 352 * infinite loop.
298 */ 353 */
299 if (entry->length == 0) { 354 entry_len = acpi_get_entry_length(&entry);
355 if (entry_len == 0) {
300 pr_err("[%4.4s:0x%02x] Invalid zero length\n", id, proc->id); 356 pr_err("[%4.4s:0x%02x] Invalid zero length\n", id, proc->id);
301 return -EINVAL; 357 return -EINVAL;
302 } 358 }
303 359
304 entry = (struct acpi_subtable_header *) 360 entry.hdr = (union acpi_subtable_headers *)
305 ((unsigned long)entry + entry->length); 361 ((unsigned long)entry.hdr + entry_len);
306 } 362 }
307 363
308 if (max_entries && count > max_entries) { 364 if (max_entries && count > max_entries) {