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 316 /* +1 to include null terminator */ 317 318 user_prt->length += 319 (u32)strlen(user_prt->source) + 1; 320 break; 321 322 case ACPI_TYPE_STRING: 323 324 strcpy(user_prt->source, 325 obj_desc->string.pointer); 326 327 /* 328 * Add to the Length field the length of the string 329 * (add 1 for terminator) 330 */ 331 user_prt->length += obj_desc->string.length + 1; 332 break; 333 334 case ACPI_TYPE_INTEGER: 335 /* 336 * If this is a number, then the Source Name is NULL, since 337 * the entire buffer was zeroed out, we can leave this alone. 338 * 339 * Add to the Length field the length of the u32 NULL 340 */ 341 user_prt->length += sizeof(u32); 342 break; 343 344 default: 345 346 ACPI_ERROR((AE_INFO, 347 "(PRT[%u].Source) Need Ref/String/Integer, found %s", 348 index, 349 acpi_ut_get_object_type_name 350 (obj_desc))); 351 return_ACPI_STATUS(AE_BAD_DATA); 352 } 353 } 354 355 /* Now align the current length */ 356 357 user_prt->length = 358 (u32) ACPI_ROUND_UP_TO_64BIT(user_prt->length); 359 360 /* 4) Fourth subobject: Dereference the PRT.source_index */ 361 362 obj_desc = sub_object_list[3]; 363 if (!obj_desc || obj_desc->common.type != ACPI_TYPE_INTEGER) { 364 ACPI_ERROR((AE_INFO, 365 "(PRT[%u].SourceIndex) Need Integer, found %s", 366 index, 367 acpi_ut_get_object_type_name(obj_desc))); 368 return_ACPI_STATUS(AE_BAD_DATA); 369 } 370 371 user_prt->source_index = (u32) obj_desc->integer.value; 372 373 /* Point to the next union acpi_operand_object in the top level package */ 374 375 top_object_list++; 376 } 377 378 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "OutputBuffer %p Length %X\n", 379 output_buffer->pointer, (u32) output_buffer->length)); 380 return_ACPI_STATUS(AE_OK); 381 } 382 383 /******************************************************************************* 384 * 385 * FUNCTION: acpi_rs_create_aml_resources 386 * 387 * PARAMETERS: resource_list - Pointer to the resource list buffer 388 * output_buffer - Where the AML buffer is returned 389 * 390 * RETURN: Status AE_OK if okay, else a valid acpi_status code. 391 * If the output_buffer is too small, the error will be 392 * AE_BUFFER_OVERFLOW and output_buffer->Length will point 393 * to the size buffer needed. 394 * 395 * DESCRIPTION: Converts a list of device resources to an AML bytestream 396 * to be used as input for the _SRS control method. 397 * 398 ******************************************************************************/ 399 400 acpi_status 401 acpi_rs_create_aml_resources(struct acpi_buffer *resource_list, 402 struct acpi_buffer *output_buffer) 403 { 404 acpi_status status; 405 acpi_size aml_size_needed = 0; 406 407 ACPI_FUNCTION_TRACE(rs_create_aml_resources); 408 409 /* Params already validated, no need to re-validate here */ 410 411 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "ResourceList Buffer = %p\n", 412 resource_list->pointer)); 413 414 /* Get the buffer size needed for the AML byte stream */ 415 416 status = 417 acpi_rs_get_aml_length(resource_list->pointer, 418 resource_list->length, &aml_size_needed); 419 420 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "AmlSizeNeeded=%X, %s\n", 421 (u32)aml_size_needed, acpi_format_exception(status))); 422 if (ACPI_FAILURE(status)) { 423 return_ACPI_STATUS(status); 424 } 425 426 /* Validate/Allocate/Clear caller buffer */ 427 428 status = acpi_ut_initialize_buffer(output_buffer, aml_size_needed); 429 if (ACPI_FAILURE(status)) { 430 return_ACPI_STATUS(status); 431 } 432 433 /* Do the conversion */ 434 435 status = acpi_rs_convert_resources_to_aml(resource_list->pointer, 436 aml_size_needed, 437 output_buffer->pointer); 438 if (ACPI_FAILURE(status)) { 439 return_ACPI_STATUS(status); 440 } 441 442 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "OutputBuffer %p Length %X\n", 443 output_buffer->pointer, (u32) output_buffer->length)); 444 return_ACPI_STATUS(AE_OK); 445 } 446