ACPICA: Use original data_table_region pointer for accesses
authorJessica Clarke <jrtc27@jrtc27.com>
Wed, 22 Dec 2021 16:21:25 +0000 (17:21 +0100)
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>
Mon, 27 Dec 2021 16:01:28 +0000 (17:01 +0100)
ACPICA commit d9eb82bd7515989f0b29d79deeeb758db4d6529c

Currently the pointer to the table is cast to acpi_physical_address and
later cast back to a pointer to be dereferenced. Whether or not this is
supported is implementation-defined.

On CHERI, and thus Arm's experimental Morello prototype architecture,
pointers are represented as capabilities, which are unforgeable bounded
pointers, providing always-on fine-grained spatial memory safety. This
means that any pointer cast to a plain integer will lose all its
associated metadata, and when cast back to a pointer it will give a
null-derived pointer (one that has the same metadata as null but an
address equal to the integer) that will trap on any dereference. As a
result, this is an implementation where acpi_physical_address cannot be
used as a hack to store real pointers.

Thus, add a new field to struct acpi_object_region to store the pointer for
table regions, and propagate it to acpi_ex_data_table_space_handler via the
region context, to use a more portable implementation that supports
CHERI.

Link: https://github.com/acpica/acpica/commit/d9eb82bd
Signed-off-by: Bob Moore <robert.moore@intel.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
drivers/acpi/acpica/acevents.h
drivers/acpi/acpica/acobject.h
drivers/acpi/acpica/dsopcode.c
drivers/acpi/acpica/evhandler.c
drivers/acpi/acpica/evrgnini.c
drivers/acpi/acpica/excreate.c
drivers/acpi/acpica/exregion.c
include/acpi/actypes.h

index 82a75964343b2211992e10dee21585a70fb0cd71..b29ba436944ad5a29065c326c409aa3eedee916c 100644 (file)
@@ -223,6 +223,11 @@ acpi_ev_pci_bar_region_setup(acpi_handle handle,
                             u32 function,
                             void *handler_context, void **region_context);
 
+acpi_status
+acpi_ev_data_table_region_setup(acpi_handle handle,
+                               u32 function,
+                               void *handler_context, void **region_context);
+
 acpi_status
 acpi_ev_default_region_setup(acpi_handle handle,
                             u32 function,
index 9db5ae0f79ea04b93dbd006c334a5370cbe7f97f..0aa0d847cb255002513f6c9f79235e378510a280 100644 (file)
@@ -138,6 +138,7 @@ struct acpi_object_region {
        union acpi_operand_object *next;
        acpi_physical_address address;
        u32 length;
+       void *pointer;          /* Only for data table regions */
 };
 
 struct acpi_object_method {
index 639635291ab76bb874a2000ff67f9296844d19d6..44c448269861a3aea8edbbe4ce837d4d815e4a6f 100644 (file)
@@ -531,6 +531,7 @@ acpi_ds_eval_table_region_operands(struct acpi_walk_state *walk_state,
 
        obj_desc->region.address = ACPI_PTR_TO_PHYSADDR(table);
        obj_desc->region.length = table->length;
+       obj_desc->region.pointer = table;
 
        ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "RgnObj %p Addr %8.8X%8.8X Len %X\n",
                          obj_desc,
index c0cd7147a5a394cf2bb94f8c70c9ce23066a264a..8f43d38dc4ca203efed8352b608771e5f240b758 100644 (file)
@@ -386,7 +386,7 @@ acpi_ev_install_space_handler(struct acpi_namespace_node *node,
                case ACPI_ADR_SPACE_DATA_TABLE:
 
                        handler = acpi_ex_data_table_space_handler;
-                       setup = NULL;
+                       setup = acpi_ev_data_table_region_setup;
                        break;
 
                default:
index 984c172453bfc5675f3115883389de9a0be647db..d28dee929e61a72c4fc9fb952ffd0cb07ee7a832 100644 (file)
@@ -406,6 +406,58 @@ acpi_ev_cmos_region_setup(acpi_handle handle,
        return_ACPI_STATUS(AE_OK);
 }
 
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ev_data_table_region_setup
+ *
+ * PARAMETERS:  handle              - Region we are interested in
+ *              function            - Start or stop
+ *              handler_context     - Address space handler context
+ *              region_context      - Region specific context
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Setup a data_table_region
+ *
+ * MUTEX:       Assumes namespace is not locked
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ev_data_table_region_setup(acpi_handle handle,
+                               u32 function,
+                               void *handler_context, void **region_context)
+{
+       union acpi_operand_object *region_desc =
+           (union acpi_operand_object *)handle;
+       struct acpi_data_table_space_context *local_region_context;
+
+       ACPI_FUNCTION_TRACE(ev_data_table_region_setup);
+
+       if (function == ACPI_REGION_DEACTIVATE) {
+               if (*region_context) {
+                       ACPI_FREE(*region_context);
+                       *region_context = NULL;
+               }
+               return_ACPI_STATUS(AE_OK);
+       }
+
+       /* Create a new context */
+
+       local_region_context =
+           ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_data_table_space_context));
+       if (!(local_region_context)) {
+               return_ACPI_STATUS(AE_NO_MEMORY);
+       }
+
+       /* Save the data table pointer for use in the handler */
+
+       local_region_context->pointer = region_desc->region.pointer;
+
+       *region_context = local_region_context;
+       return_ACPI_STATUS(AE_OK);
+}
+
 /*******************************************************************************
  *
  * FUNCTION:    acpi_ev_default_region_setup
index 80b52ad55775977b8a11df6f89305d6d2bd6f3c0..deb3674ae726feff83417ee56780a1a5cefb1b37 100644 (file)
@@ -279,6 +279,7 @@ acpi_ex_create_region(u8 * aml_start,
        obj_desc->region.space_id = space_id;
        obj_desc->region.address = 0;
        obj_desc->region.length = 0;
+       obj_desc->region.pointer = NULL;
        obj_desc->region.node = node;
        obj_desc->region.handler = NULL;
        obj_desc->common.flags &=
index 82b713a9a1939a7c25f196fe1a58d3f0a503d488..48c19908fa4e4b701b12f0538fedf8487dc21567 100644 (file)
@@ -509,8 +509,15 @@ acpi_ex_data_table_space_handler(u32 function,
                                 u64 *value,
                                 void *handler_context, void *region_context)
 {
+       struct acpi_data_table_space_context *mapping;
+       char *pointer;
+
        ACPI_FUNCTION_TRACE(ex_data_table_space_handler);
 
+       mapping = (struct acpi_data_table_space_context *) region_context;
+       pointer = ACPI_CAST_PTR(char, mapping->pointer) +
+           (address - ACPI_PTR_TO_PHYSADDR(mapping->pointer));
+
        /*
         * Perform the memory read or write. The bit_width was already
         * validated.
@@ -518,14 +525,14 @@ acpi_ex_data_table_space_handler(u32 function,
        switch (function) {
        case ACPI_READ:
 
-               memcpy(ACPI_CAST_PTR(char, value),
-                      ACPI_PHYSADDR_TO_PTR(address), ACPI_DIV_8(bit_width));
+               memcpy(ACPI_CAST_PTR(char, value), pointer,
+                      ACPI_DIV_8(bit_width));
                break;
 
        case ACPI_WRITE:
 
-               memcpy(ACPI_PHYSADDR_TO_PTR(address),
-                      ACPI_CAST_PTR(char, value), ACPI_DIV_8(bit_width));
+               memcpy(pointer, ACPI_CAST_PTR(char, value),
+                      ACPI_DIV_8(bit_width));
                break;
 
        default:
index 248242dca28d34515cf49c58bdd0c16d074b6c9b..700c2449e85ae8589883bb90aacb5eece8a3fbde 100644 (file)
@@ -1221,6 +1221,10 @@ struct acpi_mem_space_context {
        struct acpi_mem_mapping *first_mm;
 };
 
+struct acpi_data_table_space_context {
+       void *pointer;
+};
+
 /*
  * struct acpi_memory_list is used only if the ACPICA local cache is enabled
  */