diff options
Diffstat (limited to 'drivers/acpi/tables.c')
-rw-r--r-- | drivers/acpi/tables.c | 76 |
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 | ||
50 | static int acpi_apic_instance __initdata; | 50 | static int acpi_apic_instance __initdata; |
51 | 51 | ||
52 | enum acpi_subtable_type { | ||
53 | ACPI_SUBTABLE_COMMON, | ||
54 | ACPI_SUBTABLE_HMAT, | ||
55 | }; | ||
56 | |||
57 | struct 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 | ||
230 | static unsigned long __init | ||
231 | acpi_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 | |||
242 | static unsigned long __init | ||
243 | acpi_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 | |||
254 | static unsigned long __init | ||
255 | acpi_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 | |||
266 | static enum acpi_subtable_type __init | ||
267 | acpi_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) { |