nsxfname.c (16400B)
1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 2/****************************************************************************** 3 * 4 * Module Name: nsxfname - Public interfaces to the ACPI subsystem 5 * ACPI Namespace oriented interfaces 6 * 7 * Copyright (C) 2000 - 2022, Intel Corp. 8 * 9 *****************************************************************************/ 10 11#define EXPORT_ACPI_INTERFACES 12 13#include <acpi/acpi.h> 14#include "accommon.h" 15#include "acnamesp.h" 16#include "acparser.h" 17#include "amlcode.h" 18 19#define _COMPONENT ACPI_NAMESPACE 20ACPI_MODULE_NAME("nsxfname") 21 22/* Local prototypes */ 23static char *acpi_ns_copy_device_id(struct acpi_pnp_device_id *dest, 24 struct acpi_pnp_device_id *source, 25 char *string_area); 26 27/****************************************************************************** 28 * 29 * FUNCTION: acpi_get_handle 30 * 31 * PARAMETERS: parent - Object to search under (search scope). 32 * pathname - Pointer to an asciiz string containing the 33 * name 34 * ret_handle - Where the return handle is returned 35 * 36 * RETURN: Status 37 * 38 * DESCRIPTION: This routine will search for a caller specified name in the 39 * name space. The caller can restrict the search region by 40 * specifying a non NULL parent. The parent value is itself a 41 * namespace handle. 42 * 43 ******************************************************************************/ 44 45acpi_status 46acpi_get_handle(acpi_handle parent, 47 acpi_string pathname, acpi_handle *ret_handle) 48{ 49 acpi_status status; 50 struct acpi_namespace_node *node = NULL; 51 struct acpi_namespace_node *prefix_node = NULL; 52 53 ACPI_FUNCTION_ENTRY(); 54 55 /* Parameter Validation */ 56 57 if (!ret_handle || !pathname) { 58 return (AE_BAD_PARAMETER); 59 } 60 61 /* Convert a parent handle to a prefix node */ 62 63 if (parent) { 64 prefix_node = acpi_ns_validate_handle(parent); 65 if (!prefix_node) { 66 return (AE_BAD_PARAMETER); 67 } 68 } 69 70 /* 71 * Valid cases are: 72 * 1) Fully qualified pathname 73 * 2) Parent + Relative pathname 74 * 75 * Error for <null Parent + relative path> 76 */ 77 if (ACPI_IS_ROOT_PREFIX(pathname[0])) { 78 79 /* Pathname is fully qualified (starts with '\') */ 80 81 /* Special case for root-only, since we can't search for it */ 82 83 if (!strcmp(pathname, ACPI_NS_ROOT_PATH)) { 84 *ret_handle = 85 ACPI_CAST_PTR(acpi_handle, acpi_gbl_root_node); 86 return (AE_OK); 87 } 88 } else if (!prefix_node) { 89 90 /* Relative path with null prefix is disallowed */ 91 92 return (AE_BAD_PARAMETER); 93 } 94 95 /* Find the Node and convert to a handle */ 96 97 status = 98 acpi_ns_get_node(prefix_node, pathname, ACPI_NS_NO_UPSEARCH, &node); 99 if (ACPI_SUCCESS(status)) { 100 *ret_handle = ACPI_CAST_PTR(acpi_handle, node); 101 } 102 103 return (status); 104} 105 106ACPI_EXPORT_SYMBOL(acpi_get_handle) 107 108/****************************************************************************** 109 * 110 * FUNCTION: acpi_get_name 111 * 112 * PARAMETERS: handle - Handle to be converted to a pathname 113 * name_type - Full pathname or single segment 114 * buffer - Buffer for returned path 115 * 116 * RETURN: Pointer to a string containing the fully qualified Name. 117 * 118 * DESCRIPTION: This routine returns the fully qualified name associated with 119 * the Handle parameter. This and the acpi_pathname_to_handle are 120 * complementary functions. 121 * 122 ******************************************************************************/ 123acpi_status 124acpi_get_name(acpi_handle handle, u32 name_type, struct acpi_buffer *buffer) 125{ 126 acpi_status status; 127 128 /* Parameter validation */ 129 130 if (name_type > ACPI_NAME_TYPE_MAX) { 131 return (AE_BAD_PARAMETER); 132 } 133 134 status = acpi_ut_validate_buffer(buffer); 135 if (ACPI_FAILURE(status)) { 136 return (status); 137 } 138 139 /* 140 * Wants the single segment ACPI name. 141 * Validate handle and convert to a namespace Node 142 */ 143 status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); 144 if (ACPI_FAILURE(status)) { 145 return (status); 146 } 147 148 if (name_type == ACPI_FULL_PATHNAME || 149 name_type == ACPI_FULL_PATHNAME_NO_TRAILING) { 150 151 /* Get the full pathname (From the namespace root) */ 152 153 status = acpi_ns_handle_to_pathname(handle, buffer, 154 name_type == 155 ACPI_FULL_PATHNAME ? FALSE : 156 TRUE); 157 } else { 158 /* Get the single name */ 159 160 status = acpi_ns_handle_to_name(handle, buffer); 161 } 162 163 (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); 164 return (status); 165} 166 167ACPI_EXPORT_SYMBOL(acpi_get_name) 168 169/****************************************************************************** 170 * 171 * FUNCTION: acpi_ns_copy_device_id 172 * 173 * PARAMETERS: dest - Pointer to the destination PNP_DEVICE_ID 174 * source - Pointer to the source PNP_DEVICE_ID 175 * string_area - Pointer to where to copy the dest string 176 * 177 * RETURN: Pointer to the next string area 178 * 179 * DESCRIPTION: Copy a single PNP_DEVICE_ID, including the string data. 180 * 181 ******************************************************************************/ 182static char *acpi_ns_copy_device_id(struct acpi_pnp_device_id *dest, 183 struct acpi_pnp_device_id *source, 184 char *string_area) 185{ 186 /* Create the destination PNP_DEVICE_ID */ 187 188 dest->string = string_area; 189 dest->length = source->length; 190 191 /* Copy actual string and return a pointer to the next string area */ 192 193 memcpy(string_area, source->string, source->length); 194 return (string_area + source->length); 195} 196 197/****************************************************************************** 198 * 199 * FUNCTION: acpi_get_object_info 200 * 201 * PARAMETERS: handle - Object Handle 202 * return_buffer - Where the info is returned 203 * 204 * RETURN: Status 205 * 206 * DESCRIPTION: Returns information about an object as gleaned from the 207 * namespace node and possibly by running several standard 208 * control methods (Such as in the case of a device.) 209 * 210 * For Device and Processor objects, run the Device _HID, _UID, _CID, 211 * _CLS, _ADR, _sx_w, and _sx_d methods. 212 * 213 * Note: Allocates the return buffer, must be freed by the caller. 214 * 215 * Note: This interface is intended to be used during the initial device 216 * discovery namespace traversal. Therefore, no complex methods can be 217 * executed, especially those that access operation regions. Therefore, do 218 * not add any additional methods that could cause problems in this area. 219 * Because of this reason support for the following methods has been removed: 220 * 1) _SUB method was removed (11/2015) 221 * 2) _STA method was removed (02/2018) 222 * 223 ******************************************************************************/ 224 225acpi_status 226acpi_get_object_info(acpi_handle handle, 227 struct acpi_device_info **return_buffer) 228{ 229 struct acpi_namespace_node *node; 230 struct acpi_device_info *info; 231 struct acpi_pnp_device_id_list *cid_list = NULL; 232 struct acpi_pnp_device_id *hid = NULL; 233 struct acpi_pnp_device_id *uid = NULL; 234 struct acpi_pnp_device_id *cls = NULL; 235 char *next_id_string; 236 acpi_object_type type; 237 acpi_name name; 238 u8 param_count = 0; 239 u16 valid = 0; 240 u32 info_size; 241 u32 i; 242 acpi_status status; 243 244 /* Parameter validation */ 245 246 if (!handle || !return_buffer) { 247 return (AE_BAD_PARAMETER); 248 } 249 250 status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); 251 if (ACPI_FAILURE(status)) { 252 return (status); 253 } 254 255 node = acpi_ns_validate_handle(handle); 256 if (!node) { 257 (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); 258 return (AE_BAD_PARAMETER); 259 } 260 261 /* Get the namespace node data while the namespace is locked */ 262 263 info_size = sizeof(struct acpi_device_info); 264 type = node->type; 265 name = node->name.integer; 266 267 if (node->type == ACPI_TYPE_METHOD) { 268 param_count = node->object->method.param_count; 269 } 270 271 status = acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); 272 if (ACPI_FAILURE(status)) { 273 return (status); 274 } 275 276 if ((type == ACPI_TYPE_DEVICE) || (type == ACPI_TYPE_PROCESSOR)) { 277 /* 278 * Get extra info for ACPI Device/Processor objects only: 279 * Run the Device _HID, _UID, _CLS, and _CID methods. 280 * 281 * Note: none of these methods are required, so they may or may 282 * not be present for this device. The Info->Valid bitfield is used 283 * to indicate which methods were found and run successfully. 284 */ 285 286 /* Execute the Device._HID method */ 287 288 status = acpi_ut_execute_HID(node, &hid); 289 if (ACPI_SUCCESS(status)) { 290 info_size += hid->length; 291 valid |= ACPI_VALID_HID; 292 } 293 294 /* Execute the Device._UID method */ 295 296 status = acpi_ut_execute_UID(node, &uid); 297 if (ACPI_SUCCESS(status)) { 298 info_size += uid->length; 299 valid |= ACPI_VALID_UID; 300 } 301 302 /* Execute the Device._CID method */ 303 304 status = acpi_ut_execute_CID(node, &cid_list); 305 if (ACPI_SUCCESS(status)) { 306 307 /* Add size of CID strings and CID pointer array */ 308 309 info_size += 310 (cid_list->list_size - 311 sizeof(struct acpi_pnp_device_id_list)); 312 valid |= ACPI_VALID_CID; 313 } 314 315 /* Execute the Device._CLS method */ 316 317 status = acpi_ut_execute_CLS(node, &cls); 318 if (ACPI_SUCCESS(status)) { 319 info_size += cls->length; 320 valid |= ACPI_VALID_CLS; 321 } 322 } 323 324 /* 325 * Now that we have the variable-length data, we can allocate the 326 * return buffer 327 */ 328 info = ACPI_ALLOCATE_ZEROED(info_size); 329 if (!info) { 330 status = AE_NO_MEMORY; 331 goto cleanup; 332 } 333 334 /* Get the fixed-length data */ 335 336 if ((type == ACPI_TYPE_DEVICE) || (type == ACPI_TYPE_PROCESSOR)) { 337 /* 338 * Get extra info for ACPI Device/Processor objects only: 339 * Run the _ADR and, sx_w, and _sx_d methods. 340 * 341 * Notes: none of these methods are required, so they may or may 342 * not be present for this device. The Info->Valid bitfield is used 343 * to indicate which methods were found and run successfully. 344 */ 345 346 /* Execute the Device._ADR method */ 347 348 status = acpi_ut_evaluate_numeric_object(METHOD_NAME__ADR, node, 349 &info->address); 350 if (ACPI_SUCCESS(status)) { 351 valid |= ACPI_VALID_ADR; 352 } 353 354 /* Execute the Device._sx_w methods */ 355 356 status = acpi_ut_execute_power_methods(node, 357 acpi_gbl_lowest_dstate_names, 358 ACPI_NUM_sx_w_METHODS, 359 info->lowest_dstates); 360 if (ACPI_SUCCESS(status)) { 361 valid |= ACPI_VALID_SXWS; 362 } 363 364 /* Execute the Device._sx_d methods */ 365 366 status = acpi_ut_execute_power_methods(node, 367 acpi_gbl_highest_dstate_names, 368 ACPI_NUM_sx_d_METHODS, 369 info->highest_dstates); 370 if (ACPI_SUCCESS(status)) { 371 valid |= ACPI_VALID_SXDS; 372 } 373 } 374 375 /* 376 * Create a pointer to the string area of the return buffer. 377 * Point to the end of the base struct acpi_device_info structure. 378 */ 379 next_id_string = ACPI_CAST_PTR(char, info->compatible_id_list.ids); 380 if (cid_list) { 381 382 /* Point past the CID PNP_DEVICE_ID array */ 383 384 next_id_string += 385 ((acpi_size)cid_list->count * 386 sizeof(struct acpi_pnp_device_id)); 387 } 388 389 /* 390 * Copy the HID, UID, and CIDs to the return buffer. The variable-length 391 * strings are copied to the reserved area at the end of the buffer. 392 * 393 * For HID and CID, check if the ID is a PCI Root Bridge. 394 */ 395 if (hid) { 396 next_id_string = acpi_ns_copy_device_id(&info->hardware_id, 397 hid, next_id_string); 398 399 if (acpi_ut_is_pci_root_bridge(hid->string)) { 400 info->flags |= ACPI_PCI_ROOT_BRIDGE; 401 } 402 } 403 404 if (uid) { 405 next_id_string = acpi_ns_copy_device_id(&info->unique_id, 406 uid, next_id_string); 407 } 408 409 if (cid_list) { 410 info->compatible_id_list.count = cid_list->count; 411 info->compatible_id_list.list_size = cid_list->list_size; 412 413 /* Copy each CID */ 414 415 for (i = 0; i < cid_list->count; i++) { 416 next_id_string = 417 acpi_ns_copy_device_id(&info->compatible_id_list. 418 ids[i], &cid_list->ids[i], 419 next_id_string); 420 421 if (acpi_ut_is_pci_root_bridge(cid_list->ids[i].string)) { 422 info->flags |= ACPI_PCI_ROOT_BRIDGE; 423 } 424 } 425 } 426 427 if (cls) { 428 (void)acpi_ns_copy_device_id(&info->class_code, 429 cls, next_id_string); 430 } 431 432 /* Copy the fixed-length data */ 433 434 info->info_size = info_size; 435 info->type = type; 436 info->name = name; 437 info->param_count = param_count; 438 info->valid = valid; 439 440 *return_buffer = info; 441 status = AE_OK; 442 443cleanup: 444 if (hid) { 445 ACPI_FREE(hid); 446 } 447 if (uid) { 448 ACPI_FREE(uid); 449 } 450 if (cid_list) { 451 ACPI_FREE(cid_list); 452 } 453 if (cls) { 454 ACPI_FREE(cls); 455 } 456 return (status); 457} 458 459ACPI_EXPORT_SYMBOL(acpi_get_object_info) 460 461/****************************************************************************** 462 * 463 * FUNCTION: acpi_install_method 464 * 465 * PARAMETERS: buffer - An ACPI table containing one control method 466 * 467 * RETURN: Status 468 * 469 * DESCRIPTION: Install a control method into the namespace. If the method 470 * name already exists in the namespace, it is overwritten. The 471 * input buffer must contain a valid DSDT or SSDT containing a 472 * single control method. 473 * 474 ******************************************************************************/ 475acpi_status acpi_install_method(u8 *buffer) 476{ 477 struct acpi_table_header *table = 478 ACPI_CAST_PTR(struct acpi_table_header, buffer); 479 u8 *aml_buffer; 480 u8 *aml_start; 481 char *path; 482 struct acpi_namespace_node *node; 483 union acpi_operand_object *method_obj; 484 struct acpi_parse_state parser_state; 485 u32 aml_length; 486 u16 opcode; 487 u8 method_flags; 488 acpi_status status; 489 490 /* Parameter validation */ 491 492 if (!buffer) { 493 return (AE_BAD_PARAMETER); 494 } 495 496 /* Table must be a DSDT or SSDT */ 497 498 if (!ACPI_COMPARE_NAMESEG(table->signature, ACPI_SIG_DSDT) && 499 !ACPI_COMPARE_NAMESEG(table->signature, ACPI_SIG_SSDT)) { 500 return (AE_BAD_HEADER); 501 } 502 503 /* First AML opcode in the table must be a control method */ 504 505 parser_state.aml = buffer + sizeof(struct acpi_table_header); 506 opcode = acpi_ps_peek_opcode(&parser_state); 507 if (opcode != AML_METHOD_OP) { 508 return (AE_BAD_PARAMETER); 509 } 510 511 /* Extract method information from the raw AML */ 512 513 parser_state.aml += acpi_ps_get_opcode_size(opcode); 514 parser_state.pkg_end = acpi_ps_get_next_package_end(&parser_state); 515 path = acpi_ps_get_next_namestring(&parser_state); 516 517 method_flags = *parser_state.aml++; 518 aml_start = parser_state.aml; 519 aml_length = (u32)ACPI_PTR_DIFF(parser_state.pkg_end, aml_start); 520 521 /* 522 * Allocate resources up-front. We don't want to have to delete a new 523 * node from the namespace if we cannot allocate memory. 524 */ 525 aml_buffer = ACPI_ALLOCATE(aml_length); 526 if (!aml_buffer) { 527 return (AE_NO_MEMORY); 528 } 529 530 method_obj = acpi_ut_create_internal_object(ACPI_TYPE_METHOD); 531 if (!method_obj) { 532 ACPI_FREE(aml_buffer); 533 return (AE_NO_MEMORY); 534 } 535 536 /* Lock namespace for acpi_ns_lookup, we may be creating a new node */ 537 538 status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); 539 if (ACPI_FAILURE(status)) { 540 goto error_exit; 541 } 542 543 /* The lookup either returns an existing node or creates a new one */ 544 545 status = 546 acpi_ns_lookup(NULL, path, ACPI_TYPE_METHOD, ACPI_IMODE_LOAD_PASS1, 547 ACPI_NS_DONT_OPEN_SCOPE | ACPI_NS_ERROR_IF_FOUND, 548 NULL, &node); 549 550 (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); 551 552 if (ACPI_FAILURE(status)) { /* ns_lookup */ 553 if (status != AE_ALREADY_EXISTS) { 554 goto error_exit; 555 } 556 557 /* Node existed previously, make sure it is a method node */ 558 559 if (node->type != ACPI_TYPE_METHOD) { 560 status = AE_TYPE; 561 goto error_exit; 562 } 563 } 564 565 /* Copy the method AML to the local buffer */ 566 567 memcpy(aml_buffer, aml_start, aml_length); 568 569 /* Initialize the method object with the new method's information */ 570 571 method_obj->method.aml_start = aml_buffer; 572 method_obj->method.aml_length = aml_length; 573 574 method_obj->method.param_count = (u8) 575 (method_flags & AML_METHOD_ARG_COUNT); 576 577 if (method_flags & AML_METHOD_SERIALIZED) { 578 method_obj->method.info_flags = ACPI_METHOD_SERIALIZED; 579 580 method_obj->method.sync_level = (u8) 581 ((method_flags & AML_METHOD_SYNC_LEVEL) >> 4); 582 } 583 584 /* 585 * Now that it is complete, we can attach the new method object to 586 * the method Node (detaches/deletes any existing object) 587 */ 588 status = acpi_ns_attach_object(node, method_obj, ACPI_TYPE_METHOD); 589 590 /* 591 * Flag indicates AML buffer is dynamic, must be deleted later. 592 * Must be set only after attach above. 593 */ 594 node->flags |= ANOBJ_ALLOCATED_BUFFER; 595 596 /* Remove local reference to the method object */ 597 598 acpi_ut_remove_reference(method_obj); 599 return (status); 600 601error_exit: 602 603 ACPI_FREE(aml_buffer); 604 ACPI_FREE(method_obj); 605 return (status); 606} 607ACPI_EXPORT_SYMBOL(acpi_install_method)