mirror of
https://github.com/rd-stuffs/msm-4.14.git
synced 2025-02-20 11:45:48 +08:00
ACPICA: Copy dynamically loaded tables to local buffer
Previously, dynamically loaded tables were simply mapped, but on some machines this memory is corrupted after suspend. Now copy the table to a local buffer. For OpRegion case, added checksum verify. Use the table length from the table header, not the region length. For Buffer case, use the table length also. http://bugzilla.kernel.org/show_bug.cgi?id=10734 Signed-off-by: Dennis Noordsij <dennis.noordsij@helsinki.fi> Signed-off-by: Bob Moore <robert.moore@intel.com> Signed-off-by: Lin Ming <ming.m.lin@intel.com> Signed-off-by: Andi Kleen <ak@linux.intel.com> Signed-off-by: Len Brown <len.brown@intel.com>
This commit is contained in:
parent
3fa8749e58
commit
f0e0da8a6c
@ -280,6 +280,7 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
|
|||||||
struct acpi_walk_state *walk_state)
|
struct acpi_walk_state *walk_state)
|
||||||
{
|
{
|
||||||
union acpi_operand_object *ddb_handle;
|
union acpi_operand_object *ddb_handle;
|
||||||
|
struct acpi_table_header *table;
|
||||||
struct acpi_table_desc table_desc;
|
struct acpi_table_desc table_desc;
|
||||||
u32 table_index;
|
u32 table_index;
|
||||||
acpi_status status;
|
acpi_status status;
|
||||||
@ -294,9 +295,8 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
|
|||||||
switch (ACPI_GET_OBJECT_TYPE(obj_desc)) {
|
switch (ACPI_GET_OBJECT_TYPE(obj_desc)) {
|
||||||
case ACPI_TYPE_REGION:
|
case ACPI_TYPE_REGION:
|
||||||
|
|
||||||
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Load from Region %p %s\n",
|
ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
|
||||||
obj_desc,
|
"Load table from Region %p\n", obj_desc));
|
||||||
acpi_ut_get_object_type_name(obj_desc)));
|
|
||||||
|
|
||||||
/* Region must be system_memory (from ACPI spec) */
|
/* Region must be system_memory (from ACPI spec) */
|
||||||
|
|
||||||
@ -316,22 +316,17 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We will simply map the memory region for the table. However, the
|
* Map the table header and get the actual table length. The region
|
||||||
* memory region is technically not guaranteed to remain stable and
|
* length is not guaranteed to be the same as the table length.
|
||||||
* we may eventually have to copy the table to a local buffer.
|
|
||||||
*/
|
*/
|
||||||
table_desc.address = obj_desc->region.address;
|
table = acpi_os_map_memory(obj_desc->region.address,
|
||||||
table_desc.length = obj_desc->region.length;
|
sizeof(struct acpi_table_header));
|
||||||
table_desc.flags = ACPI_TABLE_ORIGIN_MAPPED;
|
if (!table) {
|
||||||
break;
|
return_ACPI_STATUS(AE_NO_MEMORY);
|
||||||
|
}
|
||||||
|
|
||||||
case ACPI_TYPE_BUFFER: /* Buffer or resolved region_field */
|
length = table->length;
|
||||||
|
acpi_os_unmap_memory(table, sizeof(struct acpi_table_header));
|
||||||
ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
|
|
||||||
"Load from Buffer or Field %p %s\n", obj_desc,
|
|
||||||
acpi_ut_get_object_type_name(obj_desc)));
|
|
||||||
|
|
||||||
length = obj_desc->buffer.length;
|
|
||||||
|
|
||||||
/* Must have at least an ACPI table header */
|
/* Must have at least an ACPI table header */
|
||||||
|
|
||||||
@ -339,38 +334,94 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
|
|||||||
return_ACPI_STATUS(AE_INVALID_TABLE_LENGTH);
|
return_ACPI_STATUS(AE_INVALID_TABLE_LENGTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Validate checksum here. It won't get validated in tb_add_table */
|
/*
|
||||||
|
* The memory region is not guaranteed to remain stable and we must
|
||||||
|
* copy the table to a local buffer. For example, the memory region
|
||||||
|
* is corrupted after suspend on some machines. Dynamically loaded
|
||||||
|
* tables are usually small, so this overhead is minimal.
|
||||||
|
*/
|
||||||
|
|
||||||
status =
|
/* Allocate a buffer for the table */
|
||||||
acpi_tb_verify_checksum(ACPI_CAST_PTR
|
|
||||||
(struct acpi_table_header,
|
table_desc.pointer = ACPI_ALLOCATE(length);
|
||||||
obj_desc->buffer.pointer), length);
|
if (!table_desc.pointer) {
|
||||||
if (ACPI_FAILURE(status)) {
|
return_ACPI_STATUS(AE_NO_MEMORY);
|
||||||
return_ACPI_STATUS(status);
|
}
|
||||||
|
|
||||||
|
/* Map the entire table and copy it */
|
||||||
|
|
||||||
|
table = acpi_os_map_memory(obj_desc->region.address, length);
|
||||||
|
if (!table) {
|
||||||
|
ACPI_FREE(table_desc.pointer);
|
||||||
|
return_ACPI_STATUS(AE_NO_MEMORY);
|
||||||
|
}
|
||||||
|
|
||||||
|
ACPI_MEMCPY(table_desc.pointer, table, length);
|
||||||
|
acpi_os_unmap_memory(table, length);
|
||||||
|
|
||||||
|
table_desc.address = obj_desc->region.address;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ACPI_TYPE_BUFFER: /* Buffer or resolved region_field */
|
||||||
|
|
||||||
|
ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
|
||||||
|
"Load table from Buffer or Field %p\n",
|
||||||
|
obj_desc));
|
||||||
|
|
||||||
|
/* Must have at least an ACPI table header */
|
||||||
|
|
||||||
|
if (obj_desc->buffer.length < sizeof(struct acpi_table_header)) {
|
||||||
|
return_ACPI_STATUS(AE_INVALID_TABLE_LENGTH);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the actual table length from the table header */
|
||||||
|
|
||||||
|
table =
|
||||||
|
ACPI_CAST_PTR(struct acpi_table_header,
|
||||||
|
obj_desc->buffer.pointer);
|
||||||
|
length = table->length;
|
||||||
|
|
||||||
|
/* Table cannot extend beyond the buffer */
|
||||||
|
|
||||||
|
if (length > obj_desc->buffer.length) {
|
||||||
|
return_ACPI_STATUS(AE_AML_BUFFER_LIMIT);
|
||||||
|
}
|
||||||
|
if (length < sizeof(struct acpi_table_header)) {
|
||||||
|
return_ACPI_STATUS(AE_INVALID_TABLE_LENGTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We need to copy the buffer since the original buffer could be
|
* Copy the table from the buffer because the buffer could be modified
|
||||||
* changed or deleted in the future
|
* or even deleted in the future
|
||||||
*/
|
*/
|
||||||
table_desc.pointer = ACPI_ALLOCATE(length);
|
table_desc.pointer = ACPI_ALLOCATE(length);
|
||||||
if (!table_desc.pointer) {
|
if (!table_desc.pointer) {
|
||||||
return_ACPI_STATUS(AE_NO_MEMORY);
|
return_ACPI_STATUS(AE_NO_MEMORY);
|
||||||
}
|
}
|
||||||
|
|
||||||
ACPI_MEMCPY(table_desc.pointer, obj_desc->buffer.pointer,
|
ACPI_MEMCPY(table_desc.pointer, table, length);
|
||||||
length);
|
table_desc.address = ACPI_TO_INTEGER(table_desc.pointer);
|
||||||
table_desc.length = length;
|
|
||||||
table_desc.flags = ACPI_TABLE_ORIGIN_ALLOCATED;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
|
return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/* Validate table checksum (will not get validated in tb_add_table) */
|
||||||
* Install the new table into the local data structures
|
|
||||||
*/
|
status = acpi_tb_verify_checksum(table_desc.pointer, length);
|
||||||
|
if (ACPI_FAILURE(status)) {
|
||||||
|
ACPI_FREE(table_desc.pointer);
|
||||||
|
return_ACPI_STATUS(status);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Complete the table descriptor */
|
||||||
|
|
||||||
|
table_desc.length = length;
|
||||||
|
table_desc.flags = ACPI_TABLE_ORIGIN_ALLOCATED;
|
||||||
|
|
||||||
|
/* Install the new table into the local data structures */
|
||||||
|
|
||||||
status = acpi_tb_add_table(&table_desc, &table_index);
|
status = acpi_tb_add_table(&table_desc, &table_index);
|
||||||
if (ACPI_FAILURE(status)) {
|
if (ACPI_FAILURE(status)) {
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
@ -379,7 +430,7 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
|
|||||||
/*
|
/*
|
||||||
* Add the table to the namespace.
|
* Add the table to the namespace.
|
||||||
*
|
*
|
||||||
* Note: We load the table objects relative to the root of the namespace.
|
* Note: Load the table objects relative to the root of the namespace.
|
||||||
* This appears to go against the ACPI specification, but we do it for
|
* This appears to go against the ACPI specification, but we do it for
|
||||||
* compatibility with other ACPI implementations.
|
* compatibility with other ACPI implementations.
|
||||||
*/
|
*/
|
||||||
@ -415,7 +466,7 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
|
|||||||
cleanup:
|
cleanup:
|
||||||
if (ACPI_FAILURE(status)) {
|
if (ACPI_FAILURE(status)) {
|
||||||
|
|
||||||
/* Delete allocated buffer or mapping */
|
/* Delete allocated table buffer */
|
||||||
|
|
||||||
acpi_tb_delete_table(&table_desc);
|
acpi_tb_delete_table(&table_desc);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user