1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 2 /******************************************************************************* 3 * 4 * Module Name: rscreate - Create resource lists/tables 5 * 6 ******************************************************************************/ 7 8 #include <acpi/acpi.h> 9 #include "accommon.h" 10 #include "acresrc.h" 11 #include "acnamesp.h" 12 13 #define _COMPONENT ACPI_RESOURCES 14 ACPI_MODULE_NAME("rscreate") 15 16 /******************************************************************************* 17 * 18 * FUNCTION: acpi_buffer_to_resource 19 * 20 * PARAMETERS: aml_buffer - Pointer to the resource byte stream 21 * aml_buffer_length - Length of the aml_buffer 22 * resource_ptr - Where the converted resource is returned 23 * 24 * RETURN: Status 25 * 26 * DESCRIPTION: Convert a raw AML buffer to a resource list 27 * 28 ******************************************************************************/ 29 acpi_status 30 acpi_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 tag 43 * 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 83 ACPI_EXPORT_SYMBOL(acpi_buffer_to_resource) 84 85 /******************************************************************************* 86 * 87 * FUNCTION: acpi_rs_create_resource_list 88 * 89 * PARAMETERS: aml_buffer - Pointer to the resource byte stream 90 * output_buffer - Pointer to the user's buffer 91 * 92 * RETURN: Status: AE_OK if okay, else a valid acpi_status code 93 * If output_buffer is not large enough, output_buffer_length 94 * indicates how large output_buffer should be, else it 95 * indicates how may u8 elements of output_buffer are valid. 96 * 97 * DESCRIPTION: Takes the byte stream returned from a _CRS, _PRS control method 98 * execution and parses the stream to create a linked list 99 * of device resources. 100 * 101 ******************************************************************************/ 102 acpi_status 103 acpi_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 calculate 124 * the buffer size needed for the linked list 125 */ 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_table 160 * 161 * PARAMETERS: package_object - Pointer to a package containing one 162 * of more ACPI_OPERAND_OBJECTs 163 * output_buffer - Pointer to the user's buffer 164 * 165 * RETURN: Status AE_OK if okay, else a valid acpi_status code. 166 * If the output_buffer is too small, the error will be 167 * AE_BUFFER_OVERFLOW and output_buffer->Length will point 168 * to the size buffer needed. 169 * 170 * DESCRIPTION: Takes the union acpi_operand_object package and creates a 171 * linked list of PCI interrupt descriptions 172 * 173 * NOTE: It is the caller's responsibility to ensure that the start of the 174 * output buffer is aligned properly (if necessary). 175 * 176 ******************************************************************************/ 177 178 acpi_status 179 acpi_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 a 219 * 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 structure 231 * 232 * NOTE: On the first iteration, user_prt->Length will 233 * be zero because we cleared the return buffer earlier 234 */ 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 this 240 * point. The minus four is to subtract the size of the u8 241 * 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 IRQ 257 * 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_name 289 * The name may be unresolved (slack mode), so allow a null object 290 */ 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 string 332 * (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, since 340 * the entire buffer was zeroed out, we can leave this alone. 341 * 342 * Add to the Length field the length of the u32 NULL 343 */ 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_name 353 (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_resources 389 * 390 * PARAMETERS: resource_list - Pointer to the resource list buffer 391 * output_buffer - Where the AML buffer is returned 392 * 393 * RETURN: Status AE_OK if okay, else a valid acpi_status code. 394 * If the output_buffer is too small, the error will be 395 * AE_BUFFER_OVERFLOW and output_buffer->Length will point 396 * to the size buffer needed. 397 * 398 * DESCRIPTION: Converts a list of device resources to an AML bytestream 399 * to be used as input for the _SRS control method. 400 * 401 ******************************************************************************/ 402 403 acpi_status 404 acpi_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