449 lines · c
1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.02/*******************************************************************************3 *4 * Module Name: rscreate - Create resource lists/tables5 *6 ******************************************************************************/7 8#include <acpi/acpi.h>9#include "accommon.h"10#include "acresrc.h"11#include "acnamesp.h"12 13#define _COMPONENT ACPI_RESOURCES14ACPI_MODULE_NAME("rscreate")15 16/*******************************************************************************17 *18 * FUNCTION: acpi_buffer_to_resource19 *20 * PARAMETERS: aml_buffer - Pointer to the resource byte stream21 * aml_buffer_length - Length of the aml_buffer22 * resource_ptr - Where the converted resource is returned23 *24 * RETURN: Status25 *26 * DESCRIPTION: Convert a raw AML buffer to a resource list27 *28 ******************************************************************************/29acpi_status30acpi_buffer_to_resource(u8 *aml_buffer,31 u16 aml_buffer_length,32 struct acpi_resource **resource_ptr)33{34 acpi_status status;35 acpi_size list_size_needed;36 void *resource;37 void *current_resource_ptr;38 39 ACPI_FUNCTION_TRACE(acpi_buffer_to_resource);40 41 /*42 * Note: we allow AE_AML_NO_RESOURCE_END_TAG, since an end tag43 * is not required here.44 */45 46 /* Get the required length for the converted resource */47 48 status =49 acpi_rs_get_list_length(aml_buffer, aml_buffer_length,50 &list_size_needed);51 if (status == AE_AML_NO_RESOURCE_END_TAG) {52 status = AE_OK;53 }54 if (ACPI_FAILURE(status)) {55 return_ACPI_STATUS(status);56 }57 58 /* Allocate a buffer for the converted resource */59 60 resource = ACPI_ALLOCATE_ZEROED(list_size_needed);61 current_resource_ptr = resource;62 if (!resource) {63 return_ACPI_STATUS(AE_NO_MEMORY);64 }65 66 /* Perform the AML-to-Resource conversion */67 68 status = acpi_ut_walk_aml_resources(NULL, aml_buffer, aml_buffer_length,69 acpi_rs_convert_aml_to_resources,70 ¤t_resource_ptr);71 if (status == AE_AML_NO_RESOURCE_END_TAG) {72 status = AE_OK;73 }74 if (ACPI_FAILURE(status)) {75 ACPI_FREE(resource);76 } else {77 *resource_ptr = resource;78 }79 80 return_ACPI_STATUS(status);81}82 83ACPI_EXPORT_SYMBOL(acpi_buffer_to_resource)84 85/*******************************************************************************86 *87 * FUNCTION: acpi_rs_create_resource_list88 *89 * PARAMETERS: aml_buffer - Pointer to the resource byte stream90 * output_buffer - Pointer to the user's buffer91 *92 * RETURN: Status: AE_OK if okay, else a valid acpi_status code93 * If output_buffer is not large enough, output_buffer_length94 * indicates how large output_buffer should be, else it95 * indicates how may u8 elements of output_buffer are valid.96 *97 * DESCRIPTION: Takes the byte stream returned from a _CRS, _PRS control method98 * execution and parses the stream to create a linked list99 * of device resources.100 *101 ******************************************************************************/102acpi_status103acpi_rs_create_resource_list(union acpi_operand_object *aml_buffer,104 struct acpi_buffer *output_buffer)105{106 107 acpi_status status;108 u8 *aml_start;109 acpi_size list_size_needed = 0;110 u32 aml_buffer_length;111 void *resource;112 113 ACPI_FUNCTION_TRACE(rs_create_resource_list);114 115 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "AmlBuffer = %p\n", aml_buffer));116 117 /* Params already validated, so we don't re-validate here */118 119 aml_buffer_length = aml_buffer->buffer.length;120 aml_start = aml_buffer->buffer.pointer;121 122 /*123 * Pass the aml_buffer into a module that can calculate124 * the buffer size needed for the linked list125 */126 status = acpi_rs_get_list_length(aml_start, aml_buffer_length,127 &list_size_needed);128 129 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Status=%X ListSizeNeeded=%X\n",130 status, (u32) list_size_needed));131 if (ACPI_FAILURE(status)) {132 return_ACPI_STATUS(status);133 }134 135 /* Validate/Allocate/Clear caller buffer */136 137 status = acpi_ut_initialize_buffer(output_buffer, list_size_needed);138 if (ACPI_FAILURE(status)) {139 return_ACPI_STATUS(status);140 }141 142 /* Do the conversion */143 144 resource = output_buffer->pointer;145 status = acpi_ut_walk_aml_resources(NULL, aml_start, aml_buffer_length,146 acpi_rs_convert_aml_to_resources,147 &resource);148 if (ACPI_FAILURE(status)) {149 return_ACPI_STATUS(status);150 }151 152 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "OutputBuffer %p Length %X\n",153 output_buffer->pointer, (u32) output_buffer->length));154 return_ACPI_STATUS(AE_OK);155}156 157/*******************************************************************************158 *159 * FUNCTION: acpi_rs_create_pci_routing_table160 *161 * PARAMETERS: package_object - Pointer to a package containing one162 * of more ACPI_OPERAND_OBJECTs163 * output_buffer - Pointer to the user's buffer164 *165 * RETURN: Status AE_OK if okay, else a valid acpi_status code.166 * If the output_buffer is too small, the error will be167 * AE_BUFFER_OVERFLOW and output_buffer->Length will point168 * to the size buffer needed.169 *170 * DESCRIPTION: Takes the union acpi_operand_object package and creates a171 * linked list of PCI interrupt descriptions172 *173 * NOTE: It is the caller's responsibility to ensure that the start of the174 * output buffer is aligned properly (if necessary).175 *176 ******************************************************************************/177 178acpi_status179acpi_rs_create_pci_routing_table(union acpi_operand_object *package_object,180 struct acpi_buffer *output_buffer)181{182 u8 *buffer;183 union acpi_operand_object **top_object_list;184 union acpi_operand_object **sub_object_list;185 union acpi_operand_object *obj_desc;186 acpi_size buffer_size_needed = 0;187 u32 number_of_elements;188 u32 index;189 struct acpi_pci_routing_table *user_prt;190 struct acpi_namespace_node *node;191 acpi_status status;192 struct acpi_buffer path_buffer;193 194 ACPI_FUNCTION_TRACE(rs_create_pci_routing_table);195 196 /* Params already validated, so we don't re-validate here */197 198 /* Get the required buffer length */199 200 status =201 acpi_rs_get_pci_routing_table_length(package_object,202 &buffer_size_needed);203 if (ACPI_FAILURE(status)) {204 return_ACPI_STATUS(status);205 }206 207 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "BufferSizeNeeded = %X\n",208 (u32) buffer_size_needed));209 210 /* Validate/Allocate/Clear caller buffer */211 212 status = acpi_ut_initialize_buffer(output_buffer, buffer_size_needed);213 if (ACPI_FAILURE(status)) {214 return_ACPI_STATUS(status);215 }216 217 /*218 * Loop through the ACPI_INTERNAL_OBJECTS - Each object should be a219 * package that in turn contains an u64 Address, a u8 Pin,220 * a Name, and a u8 source_index.221 */222 top_object_list = package_object->package.elements;223 number_of_elements = package_object->package.count;224 buffer = output_buffer->pointer;225 user_prt = ACPI_CAST_PTR(struct acpi_pci_routing_table, buffer);226 227 for (index = 0; index < number_of_elements; index++) {228 229 /*230 * Point user_prt past this current structure231 *232 * NOTE: On the first iteration, user_prt->Length will233 * be zero because we cleared the return buffer earlier234 */235 buffer += user_prt->length;236 user_prt = ACPI_CAST_PTR(struct acpi_pci_routing_table, buffer);237 238 /*239 * Fill in the Length field with the information we have at this240 * point. The minus four is to subtract the size of the u8241 * Source[4] member because it is added below.242 */243 user_prt->length = (sizeof(struct acpi_pci_routing_table) - 4);244 245 /* Each subpackage must be of length 4 */246 247 if ((*top_object_list)->package.count != 4) {248 ACPI_ERROR((AE_INFO,249 "(PRT[%u]) Need package of length 4, found length %u",250 index, (*top_object_list)->package.count));251 return_ACPI_STATUS(AE_AML_PACKAGE_LIMIT);252 }253 254 /*255 * Dereference the subpackage.256 * The sub_object_list will now point to an array of the four IRQ257 * elements: [Address, Pin, Source, source_index]258 */259 sub_object_list = (*top_object_list)->package.elements;260 261 /* 1) First subobject: Dereference the PRT.Address */262 263 obj_desc = sub_object_list[0];264 if (!obj_desc || obj_desc->common.type != ACPI_TYPE_INTEGER) {265 ACPI_ERROR((AE_INFO,266 "(PRT[%u].Address) Need Integer, found %s",267 index,268 acpi_ut_get_object_type_name(obj_desc)));269 return_ACPI_STATUS(AE_BAD_DATA);270 }271 272 user_prt->address = obj_desc->integer.value;273 274 /* 2) Second subobject: Dereference the PRT.Pin */275 276 obj_desc = sub_object_list[1];277 if (!obj_desc || obj_desc->common.type != ACPI_TYPE_INTEGER) {278 ACPI_ERROR((AE_INFO,279 "(PRT[%u].Pin) Need Integer, found %s",280 index,281 acpi_ut_get_object_type_name(obj_desc)));282 return_ACPI_STATUS(AE_BAD_DATA);283 }284 285 user_prt->pin = (u32) obj_desc->integer.value;286 287 /*288 * 3) Third subobject: Dereference the PRT.source_name289 * The name may be unresolved (slack mode), so allow a null object290 */291 obj_desc = sub_object_list[2];292 if (obj_desc) {293 switch (obj_desc->common.type) {294 case ACPI_TYPE_LOCAL_REFERENCE:295 296 if (obj_desc->reference.class !=297 ACPI_REFCLASS_NAME) {298 ACPI_ERROR((AE_INFO,299 "(PRT[%u].Source) Need name, found Reference Class 0x%X",300 index,301 obj_desc->reference.class));302 return_ACPI_STATUS(AE_BAD_DATA);303 }304 305 node = obj_desc->reference.node;306 307 /* Use *remaining* length of the buffer as max for pathname */308 309 path_buffer.length = output_buffer->length -310 (u32) ((u8 *) user_prt->source -311 (u8 *) output_buffer->pointer);312 path_buffer.pointer = user_prt->source;313 314 status = acpi_ns_handle_to_pathname((acpi_handle)node, &path_buffer, FALSE);315 if (ACPI_FAILURE(status)) {316 return_ACPI_STATUS(status);317 }318 319 /* +1 to include null terminator */320 321 user_prt->length +=322 (u32)strlen(user_prt->source) + 1;323 break;324 325 case ACPI_TYPE_STRING:326 327 strcpy(user_prt->source,328 obj_desc->string.pointer);329 330 /*331 * Add to the Length field the length of the string332 * (add 1 for terminator)333 */334 user_prt->length += obj_desc->string.length + 1;335 break;336 337 case ACPI_TYPE_INTEGER:338 /*339 * If this is a number, then the Source Name is NULL, since340 * the entire buffer was zeroed out, we can leave this alone.341 *342 * Add to the Length field the length of the u32 NULL343 */344 user_prt->length += sizeof(u32);345 break;346 347 default:348 349 ACPI_ERROR((AE_INFO,350 "(PRT[%u].Source) Need Ref/String/Integer, found %s",351 index,352 acpi_ut_get_object_type_name353 (obj_desc)));354 return_ACPI_STATUS(AE_BAD_DATA);355 }356 }357 358 /* Now align the current length */359 360 user_prt->length =361 (u32) ACPI_ROUND_UP_TO_64BIT(user_prt->length);362 363 /* 4) Fourth subobject: Dereference the PRT.source_index */364 365 obj_desc = sub_object_list[3];366 if (!obj_desc || obj_desc->common.type != ACPI_TYPE_INTEGER) {367 ACPI_ERROR((AE_INFO,368 "(PRT[%u].SourceIndex) Need Integer, found %s",369 index,370 acpi_ut_get_object_type_name(obj_desc)));371 return_ACPI_STATUS(AE_BAD_DATA);372 }373 374 user_prt->source_index = (u32) obj_desc->integer.value;375 376 /* Point to the next union acpi_operand_object in the top level package */377 378 top_object_list++;379 }380 381 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "OutputBuffer %p Length %X\n",382 output_buffer->pointer, (u32) output_buffer->length));383 return_ACPI_STATUS(AE_OK);384}385 386/*******************************************************************************387 *388 * FUNCTION: acpi_rs_create_aml_resources389 *390 * PARAMETERS: resource_list - Pointer to the resource list buffer391 * output_buffer - Where the AML buffer is returned392 *393 * RETURN: Status AE_OK if okay, else a valid acpi_status code.394 * If the output_buffer is too small, the error will be395 * AE_BUFFER_OVERFLOW and output_buffer->Length will point396 * to the size buffer needed.397 *398 * DESCRIPTION: Converts a list of device resources to an AML bytestream399 * to be used as input for the _SRS control method.400 *401 ******************************************************************************/402 403acpi_status404acpi_rs_create_aml_resources(struct acpi_buffer *resource_list,405 struct acpi_buffer *output_buffer)406{407 acpi_status status;408 acpi_size aml_size_needed = 0;409 410 ACPI_FUNCTION_TRACE(rs_create_aml_resources);411 412 /* Params already validated, no need to re-validate here */413 414 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "ResourceList Buffer = %p\n",415 resource_list->pointer));416 417 /* Get the buffer size needed for the AML byte stream */418 419 status =420 acpi_rs_get_aml_length(resource_list->pointer,421 resource_list->length, &aml_size_needed);422 423 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "AmlSizeNeeded=%X, %s\n",424 (u32)aml_size_needed, acpi_format_exception(status)));425 if (ACPI_FAILURE(status)) {426 return_ACPI_STATUS(status);427 }428 429 /* Validate/Allocate/Clear caller buffer */430 431 status = acpi_ut_initialize_buffer(output_buffer, aml_size_needed);432 if (ACPI_FAILURE(status)) {433 return_ACPI_STATUS(status);434 }435 436 /* Do the conversion */437 438 status = acpi_rs_convert_resources_to_aml(resource_list->pointer,439 aml_size_needed,440 output_buffer->pointer);441 if (ACPI_FAILURE(status)) {442 return_ACPI_STATUS(status);443 }444 445 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "OutputBuffer %p Length %X\n",446 output_buffer->pointer, (u32) output_buffer->length));447 return_ACPI_STATUS(AE_OK);448}449