0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <acpi/acpi.h>
0011 #include "accommon.h"
0012 #include "acinterp.h"
0013 #include "acnamesp.h"
0014 #include "actables.h"
0015 #include "acdispat.h"
0016 #include "acevents.h"
0017 #include "amlcode.h"
0018
0019 #define _COMPONENT ACPI_EXECUTER
0020 ACPI_MODULE_NAME("exconfig")
0021
0022
0023 static acpi_status
0024 acpi_ex_add_table(u32 table_index, union acpi_operand_object **ddb_handle);
0025
0026 static acpi_status
0027 acpi_ex_region_read(union acpi_operand_object *obj_desc,
0028 u32 length, u8 *buffer);
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045 static acpi_status
0046 acpi_ex_add_table(u32 table_index, union acpi_operand_object **ddb_handle)
0047 {
0048 union acpi_operand_object *obj_desc;
0049
0050 ACPI_FUNCTION_TRACE(ex_add_table);
0051
0052
0053
0054 obj_desc = acpi_ut_create_internal_object(ACPI_TYPE_LOCAL_REFERENCE);
0055 if (!obj_desc) {
0056 return_ACPI_STATUS(AE_NO_MEMORY);
0057 }
0058
0059
0060
0061 obj_desc->common.flags |= AOPOBJ_DATA_VALID;
0062 obj_desc->reference.class = ACPI_REFCLASS_TABLE;
0063 obj_desc->reference.value = table_index;
0064 *ddb_handle = obj_desc;
0065 return_ACPI_STATUS(AE_OK);
0066 }
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079
0080
0081 acpi_status
0082 acpi_ex_load_table_op(struct acpi_walk_state *walk_state,
0083 union acpi_operand_object **return_desc)
0084 {
0085 acpi_status status;
0086 union acpi_operand_object **operand = &walk_state->operands[0];
0087 struct acpi_namespace_node *parent_node;
0088 struct acpi_namespace_node *start_node;
0089 struct acpi_namespace_node *parameter_node = NULL;
0090 union acpi_operand_object *return_obj;
0091 union acpi_operand_object *ddb_handle;
0092 u32 table_index;
0093
0094 ACPI_FUNCTION_TRACE(ex_load_table_op);
0095
0096
0097
0098 return_obj = acpi_ut_create_integer_object((u64)0);
0099 if (!return_obj) {
0100 return_ACPI_STATUS(AE_NO_MEMORY);
0101 }
0102
0103 *return_desc = return_obj;
0104
0105
0106
0107 acpi_ex_exit_interpreter();
0108 status = acpi_tb_find_table(operand[0]->string.pointer,
0109 operand[1]->string.pointer,
0110 operand[2]->string.pointer, &table_index);
0111 acpi_ex_enter_interpreter();
0112 if (ACPI_FAILURE(status)) {
0113 if (status != AE_NOT_FOUND) {
0114 return_ACPI_STATUS(status);
0115 }
0116
0117
0118
0119 return_ACPI_STATUS(AE_OK);
0120 }
0121
0122
0123
0124 start_node = walk_state->scope_info->scope.node;
0125 parent_node = acpi_gbl_root_node;
0126
0127
0128
0129 if (operand[3]->string.length > 0) {
0130
0131
0132
0133
0134 status = acpi_ns_get_node_unlocked(start_node,
0135 operand[3]->string.pointer,
0136 ACPI_NS_SEARCH_PARENT,
0137 &parent_node);
0138 if (ACPI_FAILURE(status)) {
0139 return_ACPI_STATUS(status);
0140 }
0141 }
0142
0143
0144
0145 if (operand[4]->string.length > 0) {
0146 if ((operand[4]->string.pointer[0] != AML_ROOT_PREFIX) &&
0147 (operand[4]->string.pointer[0] != AML_PARENT_PREFIX)) {
0148
0149
0150
0151
0152 start_node = parent_node;
0153 }
0154
0155
0156
0157 status = acpi_ns_get_node_unlocked(start_node,
0158 operand[4]->string.pointer,
0159 ACPI_NS_SEARCH_PARENT,
0160 ¶meter_node);
0161 if (ACPI_FAILURE(status)) {
0162 return_ACPI_STATUS(status);
0163 }
0164 }
0165
0166
0167
0168 ACPI_INFO(("Dynamic OEM Table Load:"));
0169 acpi_ex_exit_interpreter();
0170 status = acpi_tb_load_table(table_index, parent_node);
0171 acpi_ex_enter_interpreter();
0172 if (ACPI_FAILURE(status)) {
0173 return_ACPI_STATUS(status);
0174 }
0175
0176 status = acpi_ex_add_table(table_index, &ddb_handle);
0177 if (ACPI_FAILURE(status)) {
0178 return_ACPI_STATUS(status);
0179 }
0180
0181
0182
0183 acpi_ex_exit_interpreter();
0184 acpi_ns_initialize_objects();
0185 acpi_ex_enter_interpreter();
0186
0187
0188
0189 if (parameter_node) {
0190
0191
0192
0193 status = acpi_ex_store(operand[5],
0194 ACPI_CAST_PTR(union acpi_operand_object,
0195 parameter_node),
0196 walk_state);
0197 if (ACPI_FAILURE(status)) {
0198 (void)acpi_ex_unload_table(ddb_handle);
0199
0200 acpi_ut_remove_reference(ddb_handle);
0201 return_ACPI_STATUS(status);
0202 }
0203 }
0204
0205
0206
0207 acpi_ut_remove_reference(ddb_handle);
0208
0209
0210
0211 return_obj->integer.value = 0xFFFFFFFFFFFFFFFF;
0212 return_ACPI_STATUS(status);
0213 }
0214
0215
0216
0217
0218
0219
0220
0221
0222
0223
0224
0225
0226
0227
0228
0229
0230 static acpi_status
0231 acpi_ex_region_read(union acpi_operand_object *obj_desc, u32 length, u8 *buffer)
0232 {
0233 acpi_status status;
0234 u64 value;
0235 u32 region_offset = 0;
0236 u32 i;
0237
0238
0239
0240 for (i = 0; i < length; i++) {
0241 status =
0242 acpi_ev_address_space_dispatch(obj_desc, NULL, ACPI_READ,
0243 region_offset, 8, &value);
0244 if (ACPI_FAILURE(status)) {
0245 return (status);
0246 }
0247
0248 *buffer = (u8)value;
0249 buffer++;
0250 region_offset++;
0251 }
0252
0253 return (AE_OK);
0254 }
0255
0256
0257
0258
0259
0260
0261
0262
0263
0264
0265
0266
0267
0268
0269
0270
0271
0272
0273
0274
0275
0276
0277 acpi_status
0278 acpi_ex_load_op(union acpi_operand_object *obj_desc,
0279 union acpi_operand_object *target,
0280 struct acpi_walk_state *walk_state)
0281 {
0282 union acpi_operand_object *ddb_handle;
0283 struct acpi_table_header *table_header;
0284 struct acpi_table_header *table;
0285 u32 table_index;
0286 acpi_status status;
0287 u32 length;
0288
0289 ACPI_FUNCTION_TRACE(ex_load_op);
0290
0291 if (target->common.descriptor_type == ACPI_DESC_TYPE_NAMED) {
0292 target =
0293 acpi_ns_get_attached_object(ACPI_CAST_PTR
0294 (struct acpi_namespace_node,
0295 target));
0296 }
0297 if (target->common.type != ACPI_TYPE_INTEGER) {
0298 ACPI_EXCEPTION((AE_INFO, AE_TYPE,
0299 "Type not integer: %X\n", target->common.type));
0300 return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
0301 }
0302
0303 target->integer.value = 0;
0304
0305
0306
0307 switch (obj_desc->common.type) {
0308 case ACPI_TYPE_REGION:
0309
0310 ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
0311 "Load table from Region %p\n", obj_desc));
0312
0313
0314
0315 if (obj_desc->region.space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) {
0316 return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
0317 }
0318
0319
0320
0321
0322
0323 if (!(obj_desc->common.flags & AOPOBJ_DATA_VALID)) {
0324 status = acpi_ds_get_region_arguments(obj_desc);
0325 if (ACPI_FAILURE(status)) {
0326 return_ACPI_STATUS(status);
0327 }
0328 }
0329
0330
0331
0332 table_header = ACPI_ALLOCATE(sizeof(struct acpi_table_header));
0333 if (!table_header) {
0334 return_ACPI_STATUS(AE_NO_MEMORY);
0335 }
0336
0337 status =
0338 acpi_ex_region_read(obj_desc,
0339 sizeof(struct acpi_table_header),
0340 ACPI_CAST_PTR(u8, table_header));
0341 length = table_header->length;
0342 ACPI_FREE(table_header);
0343
0344 if (ACPI_FAILURE(status)) {
0345 return_ACPI_STATUS(status);
0346 }
0347
0348
0349
0350 if (length < sizeof(struct acpi_table_header)) {
0351 return_ACPI_STATUS(AE_INVALID_TABLE_LENGTH);
0352 }
0353
0354
0355
0356
0357
0358
0359
0360
0361
0362
0363
0364
0365
0366
0367
0368
0369
0370
0371
0372 table = ACPI_ALLOCATE(length);
0373 if (!table) {
0374 return_ACPI_STATUS(AE_NO_MEMORY);
0375 }
0376
0377
0378
0379 status = acpi_ex_region_read(obj_desc, length,
0380 ACPI_CAST_PTR(u8, table));
0381 if (ACPI_FAILURE(status)) {
0382 ACPI_FREE(table);
0383 return_ACPI_STATUS(status);
0384 }
0385 break;
0386
0387 case ACPI_TYPE_BUFFER:
0388
0389 ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
0390 "Load table from Buffer or Field %p\n",
0391 obj_desc));
0392
0393
0394
0395 if (obj_desc->buffer.length < sizeof(struct acpi_table_header)) {
0396 return_ACPI_STATUS(AE_INVALID_TABLE_LENGTH);
0397 }
0398
0399
0400
0401 table_header =
0402 ACPI_CAST_PTR(struct acpi_table_header,
0403 obj_desc->buffer.pointer);
0404 length = table_header->length;
0405
0406
0407
0408 if (length > obj_desc->buffer.length) {
0409 return_ACPI_STATUS(AE_AML_BUFFER_LIMIT);
0410 }
0411 if (length < sizeof(struct acpi_table_header)) {
0412 return_ACPI_STATUS(AE_INVALID_TABLE_LENGTH);
0413 }
0414
0415
0416
0417
0418
0419 table = ACPI_ALLOCATE(length);
0420 if (!table) {
0421 return_ACPI_STATUS(AE_NO_MEMORY);
0422 }
0423
0424 memcpy(table, table_header, length);
0425 break;
0426
0427 default:
0428
0429 return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
0430 }
0431
0432
0433
0434 ACPI_INFO(("Dynamic OEM Table Load:"));
0435 acpi_ex_exit_interpreter();
0436 status = acpi_tb_install_and_load_table(ACPI_PTR_TO_PHYSADDR(table),
0437 ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL,
0438 table, TRUE, &table_index);
0439 acpi_ex_enter_interpreter();
0440 if (ACPI_FAILURE(status)) {
0441
0442
0443
0444 ACPI_FREE(table);
0445 return_ACPI_STATUS(status);
0446 }
0447
0448
0449
0450
0451
0452
0453
0454
0455 status = acpi_ex_add_table(table_index, &ddb_handle);
0456 if (ACPI_FAILURE(status)) {
0457 return_ACPI_STATUS(status);
0458 }
0459
0460
0461
0462 acpi_ex_exit_interpreter();
0463 acpi_ns_initialize_objects();
0464 acpi_ex_enter_interpreter();
0465
0466
0467
0468 acpi_ut_remove_reference(ddb_handle);
0469
0470
0471
0472 target->integer.value = 0xFFFFFFFFFFFFFFFF;
0473 return_ACPI_STATUS(status);
0474 }
0475
0476
0477
0478
0479
0480
0481
0482
0483
0484
0485
0486
0487
0488 acpi_status acpi_ex_unload_table(union acpi_operand_object *ddb_handle)
0489 {
0490 acpi_status status = AE_OK;
0491 union acpi_operand_object *table_desc = ddb_handle;
0492 u32 table_index;
0493
0494 ACPI_FUNCTION_TRACE(ex_unload_table);
0495
0496
0497
0498
0499
0500
0501 ACPI_WARNING((AE_INFO, "Received request to unload an ACPI table"));
0502
0503
0504
0505
0506
0507
0508
0509
0510
0511 ACPI_EXCEPTION((AE_INFO, AE_NOT_IMPLEMENTED,
0512 "AML Unload operator is not supported"));
0513
0514
0515
0516
0517
0518
0519
0520
0521
0522
0523
0524 if ((!ddb_handle) ||
0525 (ACPI_GET_DESCRIPTOR_TYPE(ddb_handle) != ACPI_DESC_TYPE_OPERAND) ||
0526 (ddb_handle->common.type != ACPI_TYPE_LOCAL_REFERENCE) ||
0527 (!(ddb_handle->common.flags & AOPOBJ_DATA_VALID))) {
0528 return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
0529 }
0530
0531
0532
0533 table_index = table_desc->reference.value;
0534
0535
0536
0537
0538
0539 acpi_ex_exit_interpreter();
0540 status = acpi_tb_unload_table(table_index);
0541 acpi_ex_enter_interpreter();
0542
0543
0544
0545
0546
0547 if (ACPI_SUCCESS(status)) {
0548 ddb_handle->common.flags &= ~AOPOBJ_DATA_VALID;
0549 }
0550 return_ACPI_STATUS(status);
0551 }