ACPICA: Tables: Combine checksum/duplication verification together
authorLv Zheng <lv.zheng@intel.com>
Mon, 10 Jul 2017 07:23:50 +0000 (15:23 +0800)
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>
Thu, 20 Jul 2017 14:38:25 +0000 (16:38 +0200)
ACPICA commit 182bdffc0644f568be614a6d4debd651e29ca587

They are all mechanisms used to verify if a table is qualified to be
installed and controlled by acpi_gbl_enable_table_validation, so combine them
together. By doing so, table duplication check is applied to the statically
loaded tables (however whether it is actually enabled is still determined
by acpi_gbl_enable_table_validation). Lv Zheng.

Link: https://github.com/acpica/acpica/commit/182bdffc
Signed-off-by: Lv Zheng <lv.zheng@intel.com>
Signed-off-by: Bob Moore <robert.moore@intel.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
drivers/acpi/acpica/actables.h
drivers/acpi/acpica/tbdata.c
drivers/acpi/acpica/tbinstal.c

index 89ed31b..84a3ceb 100644 (file)
@@ -76,7 +76,8 @@ void acpi_tb_release_temp_table(struct acpi_table_desc *table_desc);
 acpi_status acpi_tb_validate_temp_table(struct acpi_table_desc *table_desc);
 
 acpi_status
-acpi_tb_verify_temp_table(struct acpi_table_desc *table_desc, char *signature);
+acpi_tb_verify_temp_table(struct acpi_table_desc *table_desc,
+                         char *signature, u32 *table_index);
 
 u8 acpi_tb_is_table_loaded(u32 table_index);
 
index 24d9971..577361b 100644 (file)
 #define _COMPONENT          ACPI_TABLES
 ACPI_MODULE_NAME("tbdata")
 
+/* Local prototypes */
+static acpi_status
+acpi_tb_check_duplication(struct acpi_table_desc *table_desc, u32 *table_index);
+
+static u8
+acpi_tb_compare_tables(struct acpi_table_desc *table_desc, u32 table_index);
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_tb_compare_tables
+ *
+ * PARAMETERS:  table_desc          - Table 1 descriptor to be compared
+ *              table_index         - Index of table 2 to be compared
+ *
+ * RETURN:      TRUE if both tables are identical.
+ *
+ * DESCRIPTION: This function compares a table with another table that has
+ *              already been installed in the root table list.
+ *
+ ******************************************************************************/
+
+static u8
+acpi_tb_compare_tables(struct acpi_table_desc *table_desc, u32 table_index)
+{
+       acpi_status status = AE_OK;
+       u8 is_identical;
+       struct acpi_table_header *table;
+       u32 table_length;
+       u8 table_flags;
+
+       status =
+           acpi_tb_acquire_table(&acpi_gbl_root_table_list.tables[table_index],
+                                 &table, &table_length, &table_flags);
+       if (ACPI_FAILURE(status)) {
+               return (FALSE);
+       }
+
+       /*
+        * Check for a table match on the entire table length,
+        * not just the header.
+        */
+       is_identical = (u8)((table_desc->length != table_length ||
+                            memcmp(table_desc->pointer, table, table_length)) ?
+                           FALSE : TRUE);
+
+       /* Release the acquired table */
+
+       acpi_tb_release_table(table, table_length, table_flags);
+       return (is_identical);
+}
+
 /*******************************************************************************
  *
  * FUNCTION:    acpi_tb_init_table_descriptor
@@ -64,6 +115,7 @@ ACPI_MODULE_NAME("tbdata")
  * DESCRIPTION: Initialize a new table descriptor
  *
  ******************************************************************************/
+
 void
 acpi_tb_init_table_descriptor(struct acpi_table_desc *table_desc,
                              acpi_physical_address address,
@@ -354,12 +406,78 @@ acpi_status acpi_tb_validate_temp_table(struct acpi_table_desc *table_desc)
        return (acpi_tb_validate_table(table_desc));
 }
 
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_tb_check_duplication
+ *
+ * PARAMETERS:  table_desc          - Table descriptor
+ *              table_index         - Where the table index is returned
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Avoid installing duplicated tables. However table override and
+ *              user aided dynamic table load is allowed, thus comparing the
+ *              address of the table is not sufficient, and checking the entire
+ *              table content is required.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_tb_check_duplication(struct acpi_table_desc *table_desc, u32 *table_index)
+{
+       u32 i;
+
+       ACPI_FUNCTION_TRACE(tb_check_duplication);
+
+       /* Check if table is already registered */
+
+       for (i = 0; i < acpi_gbl_root_table_list.current_table_count; ++i) {
+               /*
+                * Check for a table match on the entire table length,
+                * not just the header.
+                */
+               if (!acpi_tb_compare_tables(table_desc, i)) {
+                       continue;
+               }
+
+               /*
+                * Note: the current mechanism does not unregister a table if it is
+                * dynamically unloaded. The related namespace entries are deleted,
+                * but the table remains in the root table list.
+                *
+                * The assumption here is that the number of different tables that
+                * will be loaded is actually small, and there is minimal overhead
+                * in just keeping the table in case it is needed again.
+                *
+                * If this assumption changes in the future (perhaps on large
+                * machines with many table load/unload operations), tables will
+                * need to be unregistered when they are unloaded, and slots in the
+                * root table list should be reused when empty.
+                */
+               if (acpi_gbl_root_table_list.tables[i].flags &
+                   ACPI_TABLE_IS_LOADED) {
+
+                       /* Table is still loaded, this is an error */
+
+                       return_ACPI_STATUS(AE_ALREADY_EXISTS);
+               } else {
+                       *table_index = i;
+                       return_ACPI_STATUS(AE_CTRL_TERMINATE);
+               }
+       }
+
+       /* Indicate no duplication to the caller */
+
+       return_ACPI_STATUS(AE_OK);
+}
+
 /******************************************************************************
  *
  * FUNCTION:    acpi_tb_verify_temp_table
  *
  * PARAMETERS:  table_desc          - Table descriptor
  *              signature           - Table signature to verify
+ *              table_index         - Where the table index is returned
  *
  * RETURN:      Status
  *
@@ -369,7 +487,8 @@ acpi_status acpi_tb_validate_temp_table(struct acpi_table_desc *table_desc)
  *****************************************************************************/
 
 acpi_status
-acpi_tb_verify_temp_table(struct acpi_table_desc *table_desc, char *signature)
+acpi_tb_verify_temp_table(struct acpi_table_desc *table_desc,
+                         char *signature, u32 *table_index)
 {
        acpi_status status = AE_OK;
 
@@ -392,9 +511,10 @@ acpi_tb_verify_temp_table(struct acpi_table_desc *table_desc, char *signature)
                goto invalidate_and_exit;
        }
 
-       /* Verify the checksum */
-
        if (acpi_gbl_enable_table_validation) {
+
+               /* Verify the checksum */
+
                status =
                    acpi_tb_verify_checksum(table_desc->pointer,
                                            table_desc->length);
@@ -411,9 +531,32 @@ acpi_tb_verify_temp_table(struct acpi_table_desc *table_desc, char *signature)
 
                        goto invalidate_and_exit;
                }
+
+               /* Avoid duplications */
+
+               if (table_index) {
+                       status =
+                           acpi_tb_check_duplication(table_desc, table_index);
+                       if (ACPI_FAILURE(status)) {
+                               if (status != AE_CTRL_TERMINATE) {
+                                       ACPI_EXCEPTION((AE_INFO, AE_NO_MEMORY,
+                                                       "%4.4s 0x%8.8X%8.8X"
+                                                       " Table is duplicated",
+                                                       acpi_ut_valid_nameseg
+                                                       (table_desc->signature.
+                                                        ascii) ? table_desc->
+                                                       signature.
+                                                       ascii : "????",
+                                                       ACPI_FORMAT_UINT64
+                                                       (table_desc->address)));
+                               }
+
+                               goto invalidate_and_exit;
+                       }
+               }
        }
 
-       return_ACPI_STATUS(AE_OK);
+       return_ACPI_STATUS(status);
 
 invalidate_and_exit:
        acpi_tb_invalidate_table(table_desc);
index f7bc362..0dfc0ac 100644 (file)
 #define _COMPONENT          ACPI_TABLES
 ACPI_MODULE_NAME("tbinstal")
 
-/* Local prototypes */
-static u8
-acpi_tb_compare_tables(struct acpi_table_desc *table_desc, u32 table_index);
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_tb_compare_tables
- *
- * PARAMETERS:  table_desc          - Table 1 descriptor to be compared
- *              table_index         - Index of table 2 to be compared
- *
- * RETURN:      TRUE if both tables are identical.
- *
- * DESCRIPTION: This function compares a table with another table that has
- *              already been installed in the root table list.
- *
- ******************************************************************************/
-
-static u8
-acpi_tb_compare_tables(struct acpi_table_desc *table_desc, u32 table_index)
-{
-       acpi_status status = AE_OK;
-       u8 is_identical;
-       struct acpi_table_header *table;
-       u32 table_length;
-       u8 table_flags;
-
-       status =
-           acpi_tb_acquire_table(&acpi_gbl_root_table_list.tables[table_index],
-                                 &table, &table_length, &table_flags);
-       if (ACPI_FAILURE(status)) {
-               return (FALSE);
-       }
-
-       /*
-        * Check for a table match on the entire table length,
-        * not just the header.
-        */
-       is_identical = (u8)((table_desc->length != table_length ||
-                            memcmp(table_desc->pointer, table, table_length)) ?
-                           FALSE : TRUE);
-
-       /* Release the acquired table */
-
-       acpi_tb_release_table(table, table_length, table_flags);
-       return (is_identical);
-}
-
 /*******************************************************************************
  *
  * FUNCTION:    acpi_tb_install_table_with_override
@@ -112,7 +64,6 @@ acpi_tb_compare_tables(struct acpi_table_desc *table_desc, u32 table_index)
  *              table array.
  *
  ******************************************************************************/
-
 void
 acpi_tb_install_table_with_override(struct acpi_table_desc *new_table_desc,
                                    u8 override, u32 *table_index)
@@ -210,67 +161,29 @@ acpi_tb_install_standard_table(acpi_physical_address address,
                goto release_and_exit;
        }
 
-       /* Validate and verify a table before installation */
-
-       status = acpi_tb_verify_temp_table(&new_table_desc, NULL);
-       if (ACPI_FAILURE(status)) {
-               goto release_and_exit;
-       }
-
        /* Acquire the table lock */
 
        (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
 
-       if (acpi_gbl_enable_table_validation) {
-
-               /* Check if table is already registered */
-
-               for (i = 0; i < acpi_gbl_root_table_list.current_table_count;
-                    ++i) {
-                       /*
-                        * Check for a table match on the entire table length,
-                        * not just the header.
-                        */
-                       if (!acpi_tb_compare_tables(&new_table_desc, i)) {
-                               continue;
-                       }
+       /* Validate and verify a table before installation */
 
+       status = acpi_tb_verify_temp_table(&new_table_desc, NULL, &i);
+       if (ACPI_FAILURE(status)) {
+               if (status == AE_CTRL_TERMINATE) {
                        /*
-                        * Note: the current mechanism does not unregister a table if it is
-                        * dynamically unloaded. The related namespace entries are deleted,
-                        * but the table remains in the root table list.
-                        *
-                        * The assumption here is that the number of different tables that
-                        * will be loaded is actually small, and there is minimal overhead
-                        * in just keeping the table in case it is needed again.
-                        *
-                        * If this assumption changes in the future (perhaps on large
-                        * machines with many table load/unload operations), tables will
-                        * need to be unregistered when they are unloaded, and slots in the
-                        * root table list should be reused when empty.
+                        * Table was unloaded, allow it to be reloaded.
+                        * As we are going to return AE_OK to the caller, we should
+                        * take the responsibility of freeing the input descriptor.
+                        * Refill the input descriptor to ensure
+                        * acpi_tb_install_table_with_override() can be called again to
+                        * indicate the re-installation.
                         */
-                       if (acpi_gbl_root_table_list.tables[i].flags &
-                           ACPI_TABLE_IS_LOADED) {
-
-                               /* Table is still loaded, this is an error */
-
-                               status = AE_ALREADY_EXISTS;
-                               goto unlock_and_exit;
-                       } else {
-                               /*
-                                * Table was unloaded, allow it to be reloaded.
-                                * As we are going to return AE_OK to the caller, we should
-                                * take the responsibility of freeing the input descriptor.
-                                * Refill the input descriptor to ensure
-                                * acpi_tb_install_table_with_override() can be called again to
-                                * indicate the re-installation.
-                                */
-                               acpi_tb_uninstall_table(&new_table_desc);
-                               (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
-                               *table_index = i;
-                               return_ACPI_STATUS(AE_OK);
-                       }
+                       acpi_tb_uninstall_table(&new_table_desc);
+                       (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
+                       *table_index = i;
+                       return_ACPI_STATUS(AE_OK);
                }
+               goto unlock_and_exit;
        }
 
        /* Add the table to the global root table list */
@@ -350,9 +263,11 @@ void acpi_tb_override_table(struct acpi_table_desc *old_table_desc)
 
 finish_override:
 
-       /* Validate and verify a table before overriding */
-
-       status = acpi_tb_verify_temp_table(&new_table_desc, NULL);
+       /*
+        * Validate and verify a table before overriding, no nested table
+        * duplication check as it's too complicated and unnecessary.
+        */
+       status = acpi_tb_verify_temp_table(&new_table_desc, NULL, NULL);
        if (ACPI_FAILURE(status)) {
                return;
        }