diff options
Diffstat (limited to 'drivers/acpi/osl.c')
-rw-r--r-- | drivers/acpi/osl.c | 97 |
1 files changed, 93 insertions, 4 deletions
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index c2c585366fa6..27ccd68b8f46 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c | |||
@@ -91,6 +91,10 @@ static DEFINE_SPINLOCK(acpi_res_lock); | |||
91 | #define OSI_STRING_LENGTH_MAX 64 /* arbitrary */ | 91 | #define OSI_STRING_LENGTH_MAX 64 /* arbitrary */ |
92 | static char osi_additional_string[OSI_STRING_LENGTH_MAX]; | 92 | static char osi_additional_string[OSI_STRING_LENGTH_MAX]; |
93 | 93 | ||
94 | #ifdef CONFIG_ACPI_CUSTOM_DSDT_INITRD | ||
95 | static int acpi_no_initrd_override; | ||
96 | #endif | ||
97 | |||
94 | /* | 98 | /* |
95 | * "Ode to _OSI(Linux)" | 99 | * "Ode to _OSI(Linux)" |
96 | * | 100 | * |
@@ -329,6 +333,67 @@ acpi_os_predefined_override(const struct acpi_predefined_names *init_val, | |||
329 | return AE_OK; | 333 | return AE_OK; |
330 | } | 334 | } |
331 | 335 | ||
336 | #ifdef CONFIG_ACPI_CUSTOM_DSDT_INITRD | ||
337 | struct acpi_table_header *acpi_find_dsdt_initrd(void) | ||
338 | { | ||
339 | struct file *firmware_file; | ||
340 | mm_segment_t oldfs; | ||
341 | unsigned long len, len2; | ||
342 | struct acpi_table_header *dsdt_buffer, *ret = NULL; | ||
343 | struct kstat stat; | ||
344 | char *ramfs_dsdt_name = "/DSDT.aml"; | ||
345 | |||
346 | printk(KERN_INFO PREFIX "Checking initramfs for custom DSDT"); | ||
347 | |||
348 | /* | ||
349 | * Never do this at home, only the user-space is allowed to open a file. | ||
350 | * The clean way would be to use the firmware loader. | ||
351 | * But this code must be run before there is any userspace available. | ||
352 | * A static/init firmware infrastructure doesn't exist yet... | ||
353 | */ | ||
354 | if (vfs_stat(ramfs_dsdt_name, &stat) < 0) | ||
355 | return ret; | ||
356 | |||
357 | len = stat.size; | ||
358 | /* check especially against empty files */ | ||
359 | if (len <= 4) { | ||
360 | printk(KERN_ERR PREFIX "Failed: DSDT only %lu bytes.\n", len); | ||
361 | return ret; | ||
362 | } | ||
363 | |||
364 | firmware_file = filp_open(ramfs_dsdt_name, O_RDONLY, 0); | ||
365 | if (IS_ERR(firmware_file)) { | ||
366 | printk(KERN_ERR PREFIX "Failed to open %s.\n", ramfs_dsdt_name); | ||
367 | return ret; | ||
368 | } | ||
369 | |||
370 | dsdt_buffer = kmalloc(len, GFP_ATOMIC); | ||
371 | if (!dsdt_buffer) { | ||
372 | printk(KERN_ERR PREFIX "Failed to allocate %lu bytes.\n", len); | ||
373 | goto err; | ||
374 | } | ||
375 | |||
376 | oldfs = get_fs(); | ||
377 | set_fs(KERNEL_DS); | ||
378 | len2 = vfs_read(firmware_file, (char __user *)dsdt_buffer, len, | ||
379 | &firmware_file->f_pos); | ||
380 | set_fs(oldfs); | ||
381 | if (len2 < len) { | ||
382 | printk(KERN_ERR PREFIX "Failed to read %lu bytes from %s.\n", | ||
383 | len, ramfs_dsdt_name); | ||
384 | ACPI_FREE(dsdt_buffer); | ||
385 | goto err; | ||
386 | } | ||
387 | |||
388 | printk(KERN_INFO PREFIX "Found %lu byte DSDT in %s.\n", | ||
389 | len, ramfs_dsdt_name); | ||
390 | ret = dsdt_buffer; | ||
391 | err: | ||
392 | filp_close(firmware_file, NULL); | ||
393 | return ret; | ||
394 | } | ||
395 | #endif | ||
396 | |||
332 | acpi_status | 397 | acpi_status |
333 | acpi_os_table_override(struct acpi_table_header * existing_table, | 398 | acpi_os_table_override(struct acpi_table_header * existing_table, |
334 | struct acpi_table_header ** new_table) | 399 | struct acpi_table_header ** new_table) |
@@ -336,17 +401,41 @@ acpi_os_table_override(struct acpi_table_header * existing_table, | |||
336 | if (!existing_table || !new_table) | 401 | if (!existing_table || !new_table) |
337 | return AE_BAD_PARAMETER; | 402 | return AE_BAD_PARAMETER; |
338 | 403 | ||
404 | *new_table = NULL; | ||
405 | |||
339 | #ifdef CONFIG_ACPI_CUSTOM_DSDT | 406 | #ifdef CONFIG_ACPI_CUSTOM_DSDT |
340 | if (strncmp(existing_table->signature, "DSDT", 4) == 0) | 407 | if (strncmp(existing_table->signature, "DSDT", 4) == 0) |
341 | *new_table = (struct acpi_table_header *)AmlCode; | 408 | *new_table = (struct acpi_table_header *)AmlCode; |
342 | else | ||
343 | *new_table = NULL; | ||
344 | #else | ||
345 | *new_table = NULL; | ||
346 | #endif | 409 | #endif |
410 | #ifdef CONFIG_ACPI_CUSTOM_DSDT_INITRD | ||
411 | if ((strncmp(existing_table->signature, "DSDT", 4) == 0) && | ||
412 | !acpi_no_initrd_override) { | ||
413 | struct acpi_table_header *initrd_table; | ||
414 | |||
415 | initrd_table = acpi_find_dsdt_initrd(); | ||
416 | if (initrd_table) | ||
417 | *new_table = initrd_table; | ||
418 | } | ||
419 | #endif | ||
420 | if (*new_table != NULL) { | ||
421 | printk(KERN_WARNING PREFIX "Override [%4.4s-%8.8s], " | ||
422 | "this is unsafe: tainting kernel\n", | ||
423 | existing_table->signature, | ||
424 | existing_table->oem_table_id); | ||
425 | add_taint(TAINT_OVERRIDDEN_ACPI_TABLE); | ||
426 | } | ||
347 | return AE_OK; | 427 | return AE_OK; |
348 | } | 428 | } |
349 | 429 | ||
430 | #ifdef CONFIG_ACPI_CUSTOM_DSDT_INITRD | ||
431 | int __init acpi_no_initrd_override_setup(char *s) | ||
432 | { | ||
433 | acpi_no_initrd_override = 1; | ||
434 | return 1; | ||
435 | } | ||
436 | __setup("acpi_no_initrd_override", acpi_no_initrd_override_setup); | ||
437 | #endif | ||
438 | |||
350 | static irqreturn_t acpi_irq(int irq, void *dev_id) | 439 | static irqreturn_t acpi_irq(int irq, void *dev_id) |
351 | { | 440 | { |
352 | u32 handled; | 441 | u32 handled; |