0001
0002
0003
0004
0005
0006
0007
0008 #include <acpi/acpi.h>
0009 #include "accommon.h"
0010 #include "acresrc.h"
0011
0012 #define _COMPONENT ACPI_UTILITIES
0013 ACPI_MODULE_NAME("utresrc")
0014
0015
0016
0017
0018
0019 const u8 acpi_gbl_resource_aml_sizes[] = {
0020
0021
0022 0,
0023 0,
0024 0,
0025 0,
0026 ACPI_AML_SIZE_SMALL(struct aml_resource_irq),
0027 ACPI_AML_SIZE_SMALL(struct aml_resource_dma),
0028 ACPI_AML_SIZE_SMALL(struct aml_resource_start_dependent),
0029 ACPI_AML_SIZE_SMALL(struct aml_resource_end_dependent),
0030 ACPI_AML_SIZE_SMALL(struct aml_resource_io),
0031 ACPI_AML_SIZE_SMALL(struct aml_resource_fixed_io),
0032 ACPI_AML_SIZE_SMALL(struct aml_resource_fixed_dma),
0033 0,
0034 0,
0035 0,
0036 ACPI_AML_SIZE_SMALL(struct aml_resource_vendor_small),
0037 ACPI_AML_SIZE_SMALL(struct aml_resource_end_tag),
0038
0039
0040
0041 0,
0042 ACPI_AML_SIZE_LARGE(struct aml_resource_memory24),
0043 ACPI_AML_SIZE_LARGE(struct aml_resource_generic_register),
0044 0,
0045 ACPI_AML_SIZE_LARGE(struct aml_resource_vendor_large),
0046 ACPI_AML_SIZE_LARGE(struct aml_resource_memory32),
0047 ACPI_AML_SIZE_LARGE(struct aml_resource_fixed_memory32),
0048 ACPI_AML_SIZE_LARGE(struct aml_resource_address32),
0049 ACPI_AML_SIZE_LARGE(struct aml_resource_address16),
0050 ACPI_AML_SIZE_LARGE(struct aml_resource_extended_irq),
0051 ACPI_AML_SIZE_LARGE(struct aml_resource_address64),
0052 ACPI_AML_SIZE_LARGE(struct aml_resource_extended_address64),
0053 ACPI_AML_SIZE_LARGE(struct aml_resource_gpio),
0054 ACPI_AML_SIZE_LARGE(struct aml_resource_pin_function),
0055 ACPI_AML_SIZE_LARGE(struct aml_resource_common_serialbus),
0056 ACPI_AML_SIZE_LARGE(struct aml_resource_pin_config),
0057 ACPI_AML_SIZE_LARGE(struct aml_resource_pin_group),
0058 ACPI_AML_SIZE_LARGE(struct aml_resource_pin_group_function),
0059 ACPI_AML_SIZE_LARGE(struct aml_resource_pin_group_config),
0060 };
0061
0062 const u8 acpi_gbl_resource_aml_serial_bus_sizes[] = {
0063 0,
0064 ACPI_AML_SIZE_LARGE(struct aml_resource_i2c_serialbus),
0065 ACPI_AML_SIZE_LARGE(struct aml_resource_spi_serialbus),
0066 ACPI_AML_SIZE_LARGE(struct aml_resource_uart_serialbus),
0067 ACPI_AML_SIZE_LARGE(struct aml_resource_csi2_serialbus),
0068 };
0069
0070
0071
0072
0073
0074
0075
0076 static const u8 acpi_gbl_resource_types[] = {
0077
0078
0079 0,
0080 0,
0081 0,
0082 0,
0083 ACPI_SMALL_VARIABLE_LENGTH,
0084 ACPI_FIXED_LENGTH,
0085 ACPI_SMALL_VARIABLE_LENGTH,
0086 ACPI_FIXED_LENGTH,
0087 ACPI_FIXED_LENGTH,
0088 ACPI_FIXED_LENGTH,
0089 ACPI_FIXED_LENGTH,
0090 0,
0091 0,
0092 0,
0093 ACPI_VARIABLE_LENGTH,
0094 ACPI_FIXED_LENGTH,
0095
0096
0097
0098 0,
0099 ACPI_FIXED_LENGTH,
0100 ACPI_FIXED_LENGTH,
0101 0,
0102 ACPI_VARIABLE_LENGTH,
0103 ACPI_FIXED_LENGTH,
0104 ACPI_FIXED_LENGTH,
0105 ACPI_VARIABLE_LENGTH,
0106 ACPI_VARIABLE_LENGTH,
0107 ACPI_VARIABLE_LENGTH,
0108 ACPI_VARIABLE_LENGTH,
0109 ACPI_FIXED_LENGTH,
0110 ACPI_VARIABLE_LENGTH,
0111 ACPI_VARIABLE_LENGTH,
0112 ACPI_VARIABLE_LENGTH,
0113 ACPI_VARIABLE_LENGTH,
0114 ACPI_VARIABLE_LENGTH,
0115 ACPI_VARIABLE_LENGTH,
0116 ACPI_VARIABLE_LENGTH,
0117 };
0118
0119
0120
0121
0122
0123
0124
0125
0126
0127
0128
0129
0130
0131
0132
0133
0134
0135
0136
0137 acpi_status
0138 acpi_ut_walk_aml_resources(struct acpi_walk_state *walk_state,
0139 u8 *aml,
0140 acpi_size aml_length,
0141 acpi_walk_aml_callback user_function, void **context)
0142 {
0143 acpi_status status;
0144 u8 *end_aml;
0145 u8 resource_index;
0146 u32 length;
0147 u32 offset = 0;
0148 u8 end_tag[2] = { 0x79, 0x00 };
0149
0150 ACPI_FUNCTION_TRACE(ut_walk_aml_resources);
0151
0152
0153
0154 if (aml_length < sizeof(struct aml_resource_end_tag)) {
0155 return_ACPI_STATUS(AE_AML_NO_RESOURCE_END_TAG);
0156 }
0157
0158
0159
0160 end_aml = aml + aml_length;
0161
0162
0163
0164 while (aml < end_aml) {
0165
0166
0167
0168 status =
0169 acpi_ut_validate_resource(walk_state, aml, &resource_index);
0170 if (ACPI_FAILURE(status)) {
0171
0172
0173
0174
0175 return_ACPI_STATUS(status);
0176 }
0177
0178
0179
0180 length = acpi_ut_get_descriptor_length(aml);
0181
0182
0183
0184 if (user_function) {
0185 status =
0186 user_function(aml, length, offset, resource_index,
0187 context);
0188 if (ACPI_FAILURE(status)) {
0189 return_ACPI_STATUS(status);
0190 }
0191 }
0192
0193
0194
0195 if (acpi_ut_get_resource_type(aml) ==
0196 ACPI_RESOURCE_NAME_END_TAG) {
0197
0198
0199
0200
0201 if ((aml + 1) >= end_aml) {
0202 return_ACPI_STATUS(AE_AML_NO_RESOURCE_END_TAG);
0203 }
0204
0205
0206
0207
0208
0209
0210
0211
0212
0213
0214 if (!user_function) {
0215 *context = aml;
0216 }
0217
0218
0219
0220 return_ACPI_STATUS(AE_OK);
0221 }
0222
0223 aml += length;
0224 offset += length;
0225 }
0226
0227
0228
0229 if (user_function) {
0230
0231
0232
0233 (void)acpi_ut_validate_resource(walk_state, end_tag,
0234 &resource_index);
0235 status =
0236 user_function(end_tag, 2, offset, resource_index, context);
0237 if (ACPI_FAILURE(status)) {
0238 return_ACPI_STATUS(status);
0239 }
0240 }
0241
0242 return_ACPI_STATUS(AE_AML_NO_RESOURCE_END_TAG);
0243 }
0244
0245
0246
0247
0248
0249
0250
0251
0252
0253
0254
0255
0256
0257
0258
0259
0260
0261
0262 acpi_status
0263 acpi_ut_validate_resource(struct acpi_walk_state *walk_state,
0264 void *aml, u8 *return_index)
0265 {
0266 union aml_resource *aml_resource;
0267 u8 resource_type;
0268 u8 resource_index;
0269 acpi_rs_length resource_length;
0270 acpi_rs_length minimum_resource_length;
0271
0272 ACPI_FUNCTION_ENTRY();
0273
0274
0275
0276
0277 resource_type = ACPI_GET8(aml);
0278
0279
0280
0281
0282
0283 if (resource_type & ACPI_RESOURCE_NAME_LARGE) {
0284
0285
0286
0287 if (resource_type > ACPI_RESOURCE_NAME_LARGE_MAX) {
0288 goto invalid_resource;
0289 }
0290
0291
0292
0293
0294
0295 resource_index = (u8) (resource_type - 0x70);
0296 } else {
0297
0298
0299
0300
0301 resource_index = (u8)
0302 ((resource_type & ACPI_RESOURCE_NAME_SMALL_MASK) >> 3);
0303 }
0304
0305
0306
0307
0308
0309 if (!acpi_gbl_resource_types[resource_index]) {
0310 goto invalid_resource;
0311 }
0312
0313
0314
0315
0316
0317 resource_length = acpi_ut_get_resource_length(aml);
0318 minimum_resource_length = acpi_gbl_resource_aml_sizes[resource_index];
0319
0320
0321
0322 switch (acpi_gbl_resource_types[resource_index]) {
0323 case ACPI_FIXED_LENGTH:
0324
0325
0326
0327 if (resource_length != minimum_resource_length) {
0328 goto bad_resource_length;
0329 }
0330 break;
0331
0332 case ACPI_VARIABLE_LENGTH:
0333
0334
0335
0336 if (resource_length < minimum_resource_length) {
0337 goto bad_resource_length;
0338 }
0339 break;
0340
0341 case ACPI_SMALL_VARIABLE_LENGTH:
0342
0343
0344
0345 if ((resource_length > minimum_resource_length) ||
0346 (resource_length < (minimum_resource_length - 1))) {
0347 goto bad_resource_length;
0348 }
0349 break;
0350
0351 default:
0352
0353
0354
0355 goto invalid_resource;
0356 }
0357
0358 aml_resource = ACPI_CAST_PTR(union aml_resource, aml);
0359 if (resource_type == ACPI_RESOURCE_NAME_SERIAL_BUS) {
0360
0361
0362
0363 if ((aml_resource->common_serial_bus.type == 0) ||
0364 (aml_resource->common_serial_bus.type >
0365 AML_RESOURCE_MAX_SERIALBUSTYPE)) {
0366 if (walk_state) {
0367 ACPI_ERROR((AE_INFO,
0368 "Invalid/unsupported SerialBus resource descriptor: BusType 0x%2.2X",
0369 aml_resource->common_serial_bus.
0370 type));
0371 }
0372 return (AE_AML_INVALID_RESOURCE_TYPE);
0373 }
0374 }
0375
0376
0377
0378 if (return_index) {
0379 *return_index = resource_index;
0380 }
0381
0382 return (AE_OK);
0383
0384 invalid_resource:
0385
0386 if (walk_state) {
0387 ACPI_ERROR((AE_INFO,
0388 "Invalid/unsupported resource descriptor: Type 0x%2.2X",
0389 resource_type));
0390 }
0391 return (AE_AML_INVALID_RESOURCE_TYPE);
0392
0393 bad_resource_length:
0394
0395 if (walk_state) {
0396 ACPI_ERROR((AE_INFO,
0397 "Invalid resource descriptor length: Type "
0398 "0x%2.2X, Length 0x%4.4X, MinLength 0x%4.4X",
0399 resource_type, resource_length,
0400 minimum_resource_length));
0401 }
0402 return (AE_AML_BAD_RESOURCE_LENGTH);
0403 }
0404
0405
0406
0407
0408
0409
0410
0411
0412
0413
0414
0415
0416
0417
0418
0419 u8 acpi_ut_get_resource_type(void *aml)
0420 {
0421 ACPI_FUNCTION_ENTRY();
0422
0423
0424
0425
0426
0427 if (ACPI_GET8(aml) & ACPI_RESOURCE_NAME_LARGE) {
0428
0429
0430
0431 return (ACPI_GET8(aml));
0432 } else {
0433
0434
0435 return ((u8) (ACPI_GET8(aml) & ACPI_RESOURCE_NAME_SMALL_MASK));
0436 }
0437 }
0438
0439
0440
0441
0442
0443
0444
0445
0446
0447
0448
0449
0450
0451
0452
0453 u16 acpi_ut_get_resource_length(void *aml)
0454 {
0455 acpi_rs_length resource_length;
0456
0457 ACPI_FUNCTION_ENTRY();
0458
0459
0460
0461
0462
0463 if (ACPI_GET8(aml) & ACPI_RESOURCE_NAME_LARGE) {
0464
0465
0466
0467 ACPI_MOVE_16_TO_16(&resource_length, ACPI_ADD_PTR(u8, aml, 1));
0468
0469 } else {
0470
0471
0472 resource_length = (u16) (ACPI_GET8(aml) &
0473 ACPI_RESOURCE_NAME_SMALL_LENGTH_MASK);
0474 }
0475
0476 return (resource_length);
0477 }
0478
0479
0480
0481
0482
0483
0484
0485
0486
0487
0488
0489
0490
0491 u8 acpi_ut_get_resource_header_length(void *aml)
0492 {
0493 ACPI_FUNCTION_ENTRY();
0494
0495
0496
0497 if (ACPI_GET8(aml) & ACPI_RESOURCE_NAME_LARGE) {
0498 return (sizeof(struct aml_resource_large_header));
0499 } else {
0500 return (sizeof(struct aml_resource_small_header));
0501 }
0502 }
0503
0504
0505
0506
0507
0508
0509
0510
0511
0512
0513
0514
0515
0516
0517
0518 u32 acpi_ut_get_descriptor_length(void *aml)
0519 {
0520 ACPI_FUNCTION_ENTRY();
0521
0522
0523
0524
0525
0526 return (acpi_ut_get_resource_length(aml) +
0527 acpi_ut_get_resource_header_length(aml));
0528 }
0529
0530
0531
0532
0533
0534
0535
0536
0537
0538
0539
0540
0541
0542
0543
0544 acpi_status
0545 acpi_ut_get_resource_end_tag(union acpi_operand_object *obj_desc, u8 **end_tag)
0546 {
0547 acpi_status status;
0548
0549 ACPI_FUNCTION_TRACE(ut_get_resource_end_tag);
0550
0551
0552
0553 if (!obj_desc->buffer.length) {
0554 *end_tag = obj_desc->buffer.pointer;
0555 return_ACPI_STATUS(AE_OK);
0556 }
0557
0558
0559
0560 status = acpi_ut_walk_aml_resources(NULL, obj_desc->buffer.pointer,
0561 obj_desc->buffer.length, NULL,
0562 (void **)end_tag);
0563
0564 return_ACPI_STATUS(status);
0565 }