Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ACPICA: Use original pointer for virtual origin tables

ACPICA commit dfa3feffa8f760b686207d09dc880cd2f26c72af

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, alter the lifecycle of table descriptors. Internal physical tables
keep the current behaviour where only the address is set on install, and
the pointer is set on acquire. Virtual tables (internal and external)
now store the pointer on initialisation and use that on acquire (which
will redundantly set *table_ptr to itself, but changing that is both
unnecessary and overly complicated as acpi_tb_acquire_table is called with
both a pointer to a variable and a pointer to Table->Pointer itself).

This requires propagating the (possible) table pointer everywhere in
order to make sure pointers make it through to acpi_tb_acquire_temp_table,
which requires a change to the acpi_install_table interface. Instead of
taking an ACPI_PHYSADDR_TYPE and a boolean indicating whether it's
physical or virtual, it is now split into acpi_install_table (that takes
an external virtual table pointer) and acpi_install_physical_table (that
takes an ACPI_PHYSADDR_TYPE for an internal physical table address).
This also has the benefit of providing a cleaner API.

Link: https://github.com/acpica/acpica/commit/dfa3feff
Signed-off-by: Bob Moore <robert.moore@intel.com>
[ rjw: Adjust the code in tables.c to match interface changes ]
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>

authored by

Jessica Clarke and committed by
Rafael J. Wysocki
5d6e5966 ca25f92b

+129 -59
+6 -2
drivers/acpi/acpica/actables.h
··· 35 35 36 36 acpi_status 37 37 acpi_tb_acquire_temp_table(struct acpi_table_desc *table_desc, 38 - acpi_physical_address address, u8 flags); 38 + acpi_physical_address address, 39 + u8 flags, struct acpi_table_header *table); 39 40 40 41 void acpi_tb_release_temp_table(struct acpi_table_desc *table_desc); 41 42 ··· 87 86 acpi_status 88 87 acpi_tb_install_standard_table(acpi_physical_address address, 89 88 u8 flags, 89 + struct acpi_table_header *table, 90 90 u8 reload, u8 override, u32 *table_index); 91 91 92 92 void acpi_tb_uninstall_table(struct acpi_table_desc *table_desc); ··· 97 95 98 96 acpi_status 99 97 acpi_tb_install_and_load_table(acpi_physical_address address, 100 - u8 flags, u8 override, u32 *table_index); 98 + u8 flags, 99 + struct acpi_table_header *table, 100 + u8 override, u32 *table_index); 101 101 102 102 acpi_status acpi_tb_unload_table(u32 table_index); 103 103
+1 -1
drivers/acpi/acpica/exconfig.c
··· 411 411 acpi_ex_exit_interpreter(); 412 412 status = acpi_tb_install_and_load_table(ACPI_PTR_TO_PHYSADDR(table), 413 413 ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL, 414 - TRUE, &table_index); 414 + table, TRUE, &table_index); 415 415 acpi_ex_enter_interpreter(); 416 416 if (ACPI_FAILURE(status)) { 417 417
+63 -30
drivers/acpi/acpica/tbdata.c
··· 89 89 { 90 90 91 91 /* 92 - * Initialize the table descriptor. Set the pointer to NULL, since the 93 - * table is not fully mapped at this time. 92 + * Initialize the table descriptor. Set the pointer to NULL for external 93 + * tables, since the table is not fully mapped at this time. 94 94 */ 95 95 memset(table_desc, 0, sizeof(struct acpi_table_desc)); 96 96 table_desc->address = address; 97 97 table_desc->length = table->length; 98 98 table_desc->flags = flags; 99 99 ACPI_MOVE_32_TO_32(table_desc->signature.ascii, table->signature); 100 + 101 + switch (table_desc->flags & ACPI_TABLE_ORIGIN_MASK) { 102 + case ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL: 103 + case ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL: 104 + 105 + table_desc->pointer = table; 106 + break; 107 + 108 + case ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL: 109 + default: 110 + 111 + break; 112 + } 100 113 } 101 114 102 115 /******************************************************************************* ··· 145 132 case ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL: 146 133 case ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL: 147 134 148 - table = ACPI_CAST_PTR(struct acpi_table_header, 149 - ACPI_PHYSADDR_TO_PTR(table_desc-> 150 - address)); 135 + table = table_desc->pointer; 151 136 break; 152 137 153 138 default: ··· 207 196 * PARAMETERS: table_desc - Table descriptor to be acquired 208 197 * address - Address of the table 209 198 * flags - Allocation flags of the table 199 + * table - Pointer to the table (required for virtual 200 + * origins, optional for physical) 210 201 * 211 202 * RETURN: Status 212 203 * ··· 221 208 222 209 acpi_status 223 210 acpi_tb_acquire_temp_table(struct acpi_table_desc *table_desc, 224 - acpi_physical_address address, u8 flags) 211 + acpi_physical_address address, 212 + u8 flags, struct acpi_table_header *table) 225 213 { 226 - struct acpi_table_header *table_header; 214 + u8 mapped_table = FALSE; 227 215 228 216 switch (flags & ACPI_TABLE_ORIGIN_MASK) { 229 217 case ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL: 230 218 231 219 /* Get the length of the full table from the header */ 232 220 233 - table_header = 234 - acpi_os_map_memory(address, 235 - sizeof(struct acpi_table_header)); 236 - if (!table_header) { 237 - return (AE_NO_MEMORY); 221 + if (!table) { 222 + table = 223 + acpi_os_map_memory(address, 224 + sizeof(struct 225 + acpi_table_header)); 226 + if (!table) { 227 + return (AE_NO_MEMORY); 228 + } 229 + 230 + mapped_table = TRUE; 238 231 } 239 232 240 - acpi_tb_init_table_descriptor(table_desc, address, flags, 241 - table_header); 242 - acpi_os_unmap_memory(table_header, 243 - sizeof(struct acpi_table_header)); 244 - return (AE_OK); 233 + break; 245 234 246 235 case ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL: 247 236 case ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL: 248 237 249 - table_header = ACPI_CAST_PTR(struct acpi_table_header, 250 - ACPI_PHYSADDR_TO_PTR(address)); 251 - if (!table_header) { 252 - return (AE_NO_MEMORY); 238 + if (!table) { 239 + return_ACPI_STATUS(AE_BAD_PARAMETER); 253 240 } 254 241 255 - acpi_tb_init_table_descriptor(table_desc, address, flags, 256 - table_header); 257 - return (AE_OK); 242 + break; 258 243 259 244 default: 260 245 261 - break; 246 + /* Table is not valid yet */ 247 + 248 + return (AE_NO_MEMORY); 262 249 } 263 250 264 - /* Table is not valid yet */ 251 + acpi_tb_init_table_descriptor(table_desc, address, flags, table); 252 + if (mapped_table) { 253 + acpi_os_unmap_memory(table, sizeof(struct acpi_table_header)); 254 + } 265 255 266 - return (AE_NO_MEMORY); 256 + return (AE_OK); 267 257 } 268 258 269 259 /******************************************************************************* ··· 351 335 352 336 acpi_tb_release_table(table_desc->pointer, table_desc->length, 353 337 table_desc->flags); 354 - table_desc->pointer = NULL; 338 + 339 + switch (table_desc->flags & ACPI_TABLE_ORIGIN_MASK) { 340 + case ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL: 341 + 342 + table_desc->pointer = NULL; 343 + break; 344 + 345 + case ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL: 346 + case ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL: 347 + default: 348 + 349 + break; 350 + } 355 351 356 352 return_VOID; 357 353 } ··· 987 959 * 988 960 * PARAMETERS: address - Physical address of the table 989 961 * flags - Allocation flags of the table 962 + * table - Pointer to the table (required for 963 + * virtual origins, optional for 964 + * physical) 990 965 * override - Whether override should be performed 991 966 * table_index - Where table index is returned 992 967 * ··· 1001 970 1002 971 acpi_status 1003 972 acpi_tb_install_and_load_table(acpi_physical_address address, 1004 - u8 flags, u8 override, u32 *table_index) 973 + u8 flags, 974 + struct acpi_table_header *table, 975 + u8 override, u32 *table_index) 1005 976 { 1006 977 acpi_status status; 1007 978 u32 i; ··· 1012 979 1013 980 /* Install the table and load it into the namespace */ 1014 981 1015 - status = acpi_tb_install_standard_table(address, flags, TRUE, 982 + status = acpi_tb_install_standard_table(address, flags, table, TRUE, 1016 983 override, &i); 1017 984 if (ACPI_FAILURE(status)) { 1018 985 goto exit;
+3 -3
drivers/acpi/acpica/tbfadt.c
··· 313 313 acpi_tb_install_standard_table((acpi_physical_address)acpi_gbl_FADT. 314 314 Xdsdt, 315 315 ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL, 316 - FALSE, TRUE, &acpi_gbl_dsdt_index); 316 + NULL, FALSE, TRUE, &acpi_gbl_dsdt_index); 317 317 318 318 /* If Hardware Reduced flag is set, there is no FACS */ 319 319 ··· 322 322 acpi_tb_install_standard_table((acpi_physical_address) 323 323 acpi_gbl_FADT.facs, 324 324 ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL, 325 - FALSE, TRUE, 325 + NULL, FALSE, TRUE, 326 326 &acpi_gbl_facs_index); 327 327 } 328 328 if (acpi_gbl_FADT.Xfacs) { 329 329 acpi_tb_install_standard_table((acpi_physical_address) 330 330 acpi_gbl_FADT.Xfacs, 331 331 ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL, 332 - FALSE, TRUE, 332 + NULL, FALSE, TRUE, 333 333 &acpi_gbl_xfacs_index); 334 334 } 335 335 }
+11 -4
drivers/acpi/acpica/tbinstal.c
··· 79 79 * PARAMETERS: address - Address of the table (might be a virtual 80 80 * address depending on the table_flags) 81 81 * flags - Flags for the table 82 + * table - Pointer to the table (required for virtual 83 + * origins, optional for physical) 82 84 * reload - Whether reload should be performed 83 85 * override - Whether override should be performed 84 86 * table_index - Where the table index is returned ··· 98 96 acpi_status 99 97 acpi_tb_install_standard_table(acpi_physical_address address, 100 98 u8 flags, 99 + struct acpi_table_header *table, 101 100 u8 reload, u8 override, u32 *table_index) 102 101 { 103 102 u32 i; ··· 109 106 110 107 /* Acquire a temporary table descriptor for validation */ 111 108 112 - status = acpi_tb_acquire_temp_table(&new_table_desc, address, flags); 109 + status = 110 + acpi_tb_acquire_temp_table(&new_table_desc, address, flags, table); 113 111 if (ACPI_FAILURE(status)) { 114 112 ACPI_ERROR((AE_INFO, 115 113 "Could not acquire table length at %8.8X%8.8X", ··· 213 209 if (ACPI_SUCCESS(status) && table) { 214 210 acpi_tb_acquire_temp_table(&new_table_desc, 215 211 ACPI_PTR_TO_PHYSADDR(table), 216 - ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL); 212 + ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL, 213 + table); 217 214 ACPI_ERROR_ONLY(override_type = "Logical"); 218 215 goto finish_override; 219 216 } ··· 225 220 &address, &length); 226 221 if (ACPI_SUCCESS(status) && address && length) { 227 222 acpi_tb_acquire_temp_table(&new_table_desc, address, 228 - ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL); 223 + ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL, 224 + NULL); 229 225 ACPI_ERROR_ONLY(override_type = "Physical"); 230 226 goto finish_override; 231 227 } ··· 295 289 296 290 if ((table_desc->flags & ACPI_TABLE_ORIGIN_MASK) == 297 291 ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL) { 298 - ACPI_FREE(ACPI_PHYSADDR_TO_PTR(table_desc->address)); 292 + ACPI_FREE(table_desc->pointer); 293 + table_desc->pointer = NULL; 299 294 } 300 295 301 296 table_desc->address = ACPI_PTR_TO_PHYSADDR(NULL);
+1 -1
drivers/acpi/acpica/tbutils.c
··· 328 328 329 329 status = acpi_tb_install_standard_table(address, 330 330 ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL, 331 - FALSE, TRUE, 331 + NULL, FALSE, TRUE, 332 332 &table_index); 333 333 334 334 if (ACPI_SUCCESS(status) &&
+38 -14
drivers/acpi/acpica/tbxfload.c
··· 227 227 * 228 228 * FUNCTION: acpi_install_table 229 229 * 230 - * PARAMETERS: address - Address of the ACPI table to be installed. 231 - * physical - Whether the address is a physical table 232 - * address or not 230 + * PARAMETERS: table - Pointer to the ACPI table to be installed. 233 231 * 234 232 * RETURN: Status 235 233 * ··· 238 240 ******************************************************************************/ 239 241 240 242 acpi_status ACPI_INIT_FUNCTION 241 - acpi_install_table(acpi_physical_address address, u8 physical) 243 + acpi_install_table(struct acpi_table_header *table) 242 244 { 243 245 acpi_status status; 244 - u8 flags; 245 246 u32 table_index; 246 247 247 248 ACPI_FUNCTION_TRACE(acpi_install_table); 248 249 249 - if (physical) { 250 - flags = ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL; 251 - } else { 252 - flags = ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL; 253 - } 254 - 255 - status = acpi_tb_install_standard_table(address, flags, 256 - FALSE, FALSE, &table_index); 250 + status = acpi_tb_install_standard_table(ACPI_PTR_TO_PHYSADDR(table), 251 + ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL, 252 + table, FALSE, FALSE, 253 + &table_index); 257 254 258 255 return_ACPI_STATUS(status); 259 256 } 260 257 261 258 ACPI_EXPORT_SYMBOL_INIT(acpi_install_table) 259 + 260 + /******************************************************************************* 261 + * 262 + * FUNCTION: acpi_install_physical_table 263 + * 264 + * PARAMETERS: address - Address of the ACPI table to be installed. 265 + * 266 + * RETURN: Status 267 + * 268 + * DESCRIPTION: Dynamically install an ACPI table. 269 + * Note: This function should only be invoked after 270 + * acpi_initialize_tables() and before acpi_load_tables(). 271 + * 272 + ******************************************************************************/ 273 + acpi_status ACPI_INIT_FUNCTION 274 + acpi_install_physical_table(acpi_physical_address address) 275 + { 276 + acpi_status status; 277 + u32 table_index; 278 + 279 + ACPI_FUNCTION_TRACE(acpi_install_physical_table); 280 + 281 + status = acpi_tb_install_standard_table(address, 282 + ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL, 283 + NULL, FALSE, FALSE, 284 + &table_index); 285 + 286 + return_ACPI_STATUS(status); 287 + } 288 + 289 + ACPI_EXPORT_SYMBOL_INIT(acpi_install_physical_table) 262 290 263 291 /******************************************************************************* 264 292 * ··· 322 298 ACPI_INFO(("Host-directed Dynamic ACPI Table Load:")); 323 299 status = acpi_tb_install_and_load_table(ACPI_PTR_TO_PHYSADDR(table), 324 300 ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL, 325 - FALSE, &table_index); 301 + table, FALSE, &table_index); 326 302 if (table_idx) { 327 303 *table_idx = table_index; 328 304 }
+2 -2
drivers/acpi/tables.c
··· 723 723 /* 724 724 * Mark the table to avoid being used in 725 725 * acpi_table_initrd_override(). Though this is not possible 726 - * because override is disabled in acpi_install_table(). 726 + * because override is disabled in acpi_install_physical_table(). 727 727 */ 728 728 if (test_and_set_bit(table_index, acpi_initrd_installed)) { 729 729 acpi_os_unmap_memory(table, ACPI_HEADER_SIZE); ··· 734 734 table->signature, table->oem_id, 735 735 table->oem_table_id); 736 736 acpi_os_unmap_memory(table, ACPI_HEADER_SIZE); 737 - acpi_install_table(acpi_tables_addr + table_offset, TRUE); 737 + acpi_install_physical_table(acpi_tables_addr + table_offset); 738 738 next_table: 739 739 table_offset += table_length; 740 740 table_index++;
+4 -2
include/acpi/acpixf.h
··· 454 454 * ACPI table load/unload interfaces 455 455 */ 456 456 ACPI_EXTERNAL_RETURN_STATUS(acpi_status ACPI_INIT_FUNCTION 457 - acpi_install_table(acpi_physical_address address, 458 - u8 physical)) 457 + acpi_install_table(struct acpi_table_header *table)) 459 458 459 + ACPI_EXTERNAL_RETURN_STATUS(acpi_status ACPI_INIT_FUNCTION 460 + acpi_install_physical_table(acpi_physical_address 461 + address)) 460 462 ACPI_EXTERNAL_RETURN_STATUS(acpi_status 461 463 acpi_load_table(struct acpi_table_header *table, 462 464 u32 *table_idx))