608 lines · c
1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.02/******************************************************************************3 *4 * Module Name: nsxfname - Public interfaces to the ACPI subsystem5 * ACPI Namespace oriented interfaces6 *7 * Copyright (C) 2000 - 2023, Intel Corp.8 *9 *****************************************************************************/10 11#define EXPORT_ACPI_INTERFACES12 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_NAMESPACE20ACPI_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_handle30 *31 * PARAMETERS: parent - Object to search under (search scope).32 * pathname - Pointer to an asciiz string containing the33 * name34 * ret_handle - Where the return handle is returned35 *36 * RETURN: Status37 *38 * DESCRIPTION: This routine will search for a caller specified name in the39 * name space. The caller can restrict the search region by40 * specifying a non NULL parent. The parent value is itself a41 * namespace handle.42 *43 ******************************************************************************/44 45acpi_status46acpi_get_handle(acpi_handle parent,47 const char *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 pathname73 * 2) Parent + Relative pathname74 *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_name111 *112 * PARAMETERS: handle - Handle to be converted to a pathname113 * name_type - Full pathname or single segment114 * buffer - Buffer for returned path115 *116 * RETURN: Pointer to a string containing the fully qualified Name.117 *118 * DESCRIPTION: This routine returns the fully qualified name associated with119 * the Handle parameter. This and the acpi_pathname_to_handle are120 * complementary functions.121 *122 ******************************************************************************/123acpi_status124acpi_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 Node142 */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_id172 *173 * PARAMETERS: dest - Pointer to the destination PNP_DEVICE_ID174 * source - Pointer to the source PNP_DEVICE_ID175 * string_area - Pointer to where to copy the dest string176 *177 * RETURN: Pointer to the next string area178 *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_info200 *201 * PARAMETERS: handle - Object Handle202 * return_buffer - Where the info is returned203 *204 * RETURN: Status205 *206 * DESCRIPTION: Returns information about an object as gleaned from the207 * namespace node and possibly by running several standard208 * 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 device216 * discovery namespace traversal. Therefore, no complex methods can be217 * executed, especially those that access operation regions. Therefore, do218 * 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_status226acpi_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 may282 * not be present for this device. The Info->Valid bitfield is used283 * 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 the326 * return buffer327 */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 may342 * not be present for this device. The Info->Valid bitfield is used343 * 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-length391 * 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_method464 *465 * PARAMETERS: buffer - An ACPI table containing one control method466 *467 * RETURN: Status468 *469 * DESCRIPTION: Install a control method into the namespace. If the method470 * name already exists in the namespace, it is overwritten. The471 * input buffer must contain a valid DSDT or SSDT containing a472 * 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 new523 * 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 to586 * 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)608