2 * acpi_utils.c - ACPI Utility Functions ($Revision: 10 $)
4 * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
5 * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
7 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or (at
12 * your option) any later version.
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
23 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
27 #include <ntstrsafe.h>
32 /* Modified for ReactOS and latest ACPICA
33 * Copyright (C)2009 Samuel Serapion
36 #define _COMPONENT ACPI_BUS_COMPONENT
37 ACPI_MODULE_NAME ("acpi_utils")
40 acpi_util_eval_error(ACPI_HANDLE h
, ACPI_STRING p
, ACPI_STATUS s
)
42 #ifdef ACPI_DEBUG_OUTPUT
43 char prefix
[80] = {'\0'};
44 ACPI_BUFFER buffer
= {sizeof(prefix
), prefix
};
45 AcpiGetName(h
, ACPI_FULL_PATHNAME
, &buffer
);
46 ACPI_DEBUG_PRINT((ACPI_DB_INFO
, "Evaluate [%s.%s]: %s\n",
47 (char *) prefix
, p
, AcpiFormatException(s
)));
54 /* --------------------------------------------------------------------------
55 Object Evaluation Helpers
56 -------------------------------------------------------------------------- */
60 acpi_extract_package (
65 UINT32 size_required
= 0;
66 UINT32 tail_offset
= 0;
67 char *format_string
= NULL
;
68 UINT32 format_count
= 0;
73 if (!package
|| (package
->Type
!= ACPI_TYPE_PACKAGE
) || (package
->Package
.Count
< 1)) {
74 ACPI_DEBUG_PRINT((ACPI_DB_WARN
, "Invalid 'package' argument\n"));
75 return_ACPI_STATUS(AE_BAD_PARAMETER
);
78 if (!format
|| !format
->Pointer
|| (format
->Length
< 1)) {
79 ACPI_DEBUG_PRINT((ACPI_DB_WARN
, "Invalid 'format' argument\n"));
80 return_ACPI_STATUS(AE_BAD_PARAMETER
);
84 ACPI_DEBUG_PRINT((ACPI_DB_WARN
, "Invalid 'buffer' argument\n"));
85 return_ACPI_STATUS(AE_BAD_PARAMETER
);
88 format_count
= (format
->Length
/sizeof(char)) - 1;
89 if (format_count
> package
->Package
.Count
) {
90 ACPI_DEBUG_PRINT((ACPI_DB_WARN
, "Format specifies more objects [%d] than exist in package [%d].", format_count
, package
->package
.count
));
91 return_ACPI_STATUS(AE_BAD_DATA
);
94 format_string
= format
->Pointer
;
97 * Calculate size_required.
99 for (i
=0; i
<format_count
; i
++) {
101 ACPI_OBJECT
*element
= &(package
->Package
.Elements
[i
]);
104 return_ACPI_STATUS(AE_BAD_DATA
);
107 switch (element
->Type
) {
109 case ACPI_TYPE_INTEGER
:
110 switch (format_string
[i
]) {
112 size_required
+= sizeof(ACPI_INTEGER
);
113 tail_offset
+= sizeof(ACPI_INTEGER
);
116 size_required
+= sizeof(char*) + sizeof(ACPI_INTEGER
) + sizeof(char);
117 tail_offset
+= sizeof(char*);
120 ACPI_DEBUG_PRINT((ACPI_DB_WARN
, "Invalid package element [%d]: got number, expecting [%c].\n", i
, format_string
[i
]));
121 return_ACPI_STATUS(AE_BAD_DATA
);
126 case ACPI_TYPE_STRING
:
127 case ACPI_TYPE_BUFFER
:
128 switch (format_string
[i
]) {
130 size_required
+= sizeof(char*) + (element
->String
.Length
* sizeof(char)) + sizeof(char);
131 tail_offset
+= sizeof(char*);
134 size_required
+= sizeof(UINT8
*) + (element
->Buffer
.Length
* sizeof(UINT8
));
135 tail_offset
+= sizeof(UINT8
*);
138 ACPI_DEBUG_PRINT((ACPI_DB_WARN
, "Invalid package element [%d] got string/buffer, expecting [%c].\n", i
, format_string
[i
]));
139 return_ACPI_STATUS(AE_BAD_DATA
);
144 case ACPI_TYPE_PACKAGE
:
146 ACPI_DEBUG_PRINT((ACPI_DB_INFO
, "Found unsupported element at index=%d\n", i
));
147 /* TBD: handle nested packages... */
148 return_ACPI_STATUS(AE_SUPPORT
);
154 * Validate output buffer.
156 if (buffer
->Length
< size_required
) {
157 buffer
->Length
= size_required
;
158 return_ACPI_STATUS(AE_BUFFER_OVERFLOW
);
160 else if (buffer
->Length
!= size_required
|| !buffer
->Pointer
) {
161 return_ACPI_STATUS(AE_BAD_PARAMETER
);
164 head
= buffer
->Pointer
;
165 tail
= ((PUCHAR
)buffer
->Pointer
) + tail_offset
;
168 * Extract package data.
170 for (i
=0; i
<format_count
; i
++) {
172 UINT8
**pointer
= NULL
;
173 ACPI_OBJECT
*element
= &(package
->Package
.Elements
[i
]);
176 return_ACPI_STATUS(AE_BAD_DATA
);
179 switch (element
->Type
) {
181 case ACPI_TYPE_INTEGER
:
182 switch (format_string
[i
]) {
184 *((ACPI_INTEGER
*)head
) = element
->Integer
.Value
;
185 head
+= sizeof(ACPI_INTEGER
);
188 pointer
= (UINT8
**)head
;
190 *((ACPI_INTEGER
*)tail
) = element
->Integer
.Value
;
191 head
+= sizeof(ACPI_INTEGER
*);
192 tail
+= sizeof(ACPI_INTEGER
);
193 /* NULL terminate string */
195 tail
+= sizeof(char);
198 /* Should never get here */
203 case ACPI_TYPE_STRING
:
204 case ACPI_TYPE_BUFFER
:
205 switch (format_string
[i
]) {
207 pointer
= (UINT8
**)head
;
209 memcpy(tail
, element
->String
.Pointer
, element
->String
.Length
);
210 head
+= sizeof(char*);
211 tail
+= element
->String
.Length
* sizeof(char);
212 /* NULL terminate string */
214 tail
+= sizeof(char);
217 pointer
= (UINT8
**)head
;
219 memcpy(tail
, element
->Buffer
.Pointer
, element
->Buffer
.Length
);
220 head
+= sizeof(UINT8
*);
221 tail
+= element
->Buffer
.Length
* sizeof(UINT8
);
224 /* Should never get here */
229 case ACPI_TYPE_PACKAGE
:
230 /* TBD: handle nested packages... */
232 /* Should never get here */
237 return_ACPI_STATUS(AE_OK
);
242 acpi_evaluate_integer (
244 ACPI_STRING pathname
,
245 ACPI_OBJECT_LIST
*arguments
,
246 unsigned long long *data
)
248 ACPI_STATUS status
= AE_OK
;
250 ACPI_BUFFER buffer
= {sizeof(ACPI_OBJECT
), &element
};
252 ACPI_FUNCTION_TRACE("acpi_evaluate_integer");
255 return_ACPI_STATUS(AE_BAD_PARAMETER
);
257 status
= AcpiEvaluateObject(handle
, pathname
, arguments
, &buffer
);
258 if (ACPI_FAILURE(status
)) {
259 acpi_util_eval_error(handle
, pathname
, status
);
260 return_ACPI_STATUS(status
);
263 if (element
.Type
!= ACPI_TYPE_INTEGER
) {
264 acpi_util_eval_error(handle
, pathname
, AE_BAD_DATA
);
265 return_ACPI_STATUS(AE_BAD_DATA
);
268 *data
= element
.Integer
.Value
;
270 ACPI_DEBUG_PRINT((ACPI_DB_INFO
, "Return value [%lu]\n", *data
));
272 return_ACPI_STATUS(AE_OK
);
277 acpi_evaluate_reference (
279 ACPI_STRING pathname
,
280 ACPI_OBJECT_LIST
*arguments
,
281 struct acpi_handle_list
*list
)
283 ACPI_STATUS status
= AE_OK
;
284 ACPI_OBJECT
*package
= NULL
;
285 ACPI_OBJECT
*element
= NULL
;
286 ACPI_BUFFER buffer
= {ACPI_ALLOCATE_BUFFER
, NULL
};
289 ACPI_FUNCTION_TRACE("acpi_evaluate_reference");
292 return_ACPI_STATUS(AE_BAD_PARAMETER
);
295 /* Evaluate object. */
297 status
= AcpiEvaluateObject(handle
, pathname
, arguments
, &buffer
);
298 if (ACPI_FAILURE(status
))
301 package
= (ACPI_OBJECT
*) buffer
.Pointer
;
303 if ((buffer
.Length
== 0) || !package
) {
304 ACPI_DEBUG_PRINT((ACPI_DB_ERROR
,
305 "No return object (len %X ptr %p)\n",
306 buffer
.Length
, package
));
307 status
= AE_BAD_DATA
;
308 acpi_util_eval_error(handle
, pathname
, status
);
311 if (package
->Type
!= ACPI_TYPE_PACKAGE
) {
312 ACPI_DEBUG_PRINT((ACPI_DB_ERROR
,
313 "Expecting a [Package], found type %X\n",
315 status
= AE_BAD_DATA
;
316 acpi_util_eval_error(handle
, pathname
, status
);
319 if (!package
->Package
.Count
) {
320 ACPI_DEBUG_PRINT((ACPI_DB_ERROR
,
321 "[Package] has zero elements (%p)\n",
323 status
= AE_BAD_DATA
;
324 acpi_util_eval_error(handle
, pathname
, status
);
328 if (package
->Package
.Count
> ACPI_MAX_HANDLES
) {
331 list
->count
= package
->Package
.Count
;
333 /* Extract package data. */
335 for (i
= 0; i
< list
->count
; i
++) {
337 element
= &(package
->Package
.Elements
[i
]);
339 if (element
->Type
!= ACPI_TYPE_LOCAL_REFERENCE
) {
340 status
= AE_BAD_DATA
;
341 ACPI_DEBUG_PRINT((ACPI_DB_ERROR
,
342 "Expecting a [Reference] package element, found type %X\n",
344 acpi_util_eval_error(handle
, pathname
, status
);
348 if (!element
->Reference
.Handle
) {
349 ACPI_DEBUG_PRINT((ACPI_DB_ERROR
, "Invalid reference in"
350 " package %s\n", pathname
));
351 status
= AE_NULL_ENTRY
;
354 /* Get the ACPI_HANDLE. */
356 list
->handles
[i
] = element
->Reference
.Handle
;
357 ACPI_DEBUG_PRINT((ACPI_DB_INFO
, "Found reference [%p]\n",
362 if (ACPI_FAILURE(status
)) {
364 //ExFreePool(list->handles);
368 AcpiOsFree(buffer
.Pointer
);
370 return_ACPI_STATUS(status
);
374 acpi_create_registry_table(HANDLE ParentKeyHandle
, ACPI_TABLE_HEADER
*OutTable
, PCWSTR KeyName
)
376 OBJECT_ATTRIBUTES ObjectAttributes
;
377 UNICODE_STRING HardwareKeyName
, ValueName
;
378 ANSI_STRING HardwareKeyNameA
;
379 HANDLE KeyHandle
= NULL
, SubKeyHandle
= NULL
;
381 char OemId
[7] = { 0 }; /* exactly one byte more than ACPI_TABLE_HEADER->OemId */
382 char OemTableId
[9] = { 0 }; /* exactly one byte more than ACPI_TABLE_HEADER->OemTableId */
383 WCHAR OemRevision
[9] = { 0 }; /* enough to accept hex DWORD */
385 C_ASSERT(sizeof(OemId
) == RTL_FIELD_SIZE(ACPI_TABLE_HEADER
, OemId
) + 1);
386 C_ASSERT(sizeof(OemTableId
) == RTL_FIELD_SIZE(ACPI_TABLE_HEADER
, OemTableId
) + 1);
387 /* Copy OEM data from the table */
388 RtlCopyMemory(OemId
, OutTable
->OemId
, sizeof(OutTable
->OemId
));
389 RtlCopyMemory(OemTableId
, OutTable
->OemTableId
, sizeof(OutTable
->OemTableId
));
390 /* Create table subkey */
391 RtlInitUnicodeString(&HardwareKeyName
, KeyName
);
392 InitializeObjectAttributes(&ObjectAttributes
,
394 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
397 Status
= ZwCreateKey(&KeyHandle
,
404 if (!NT_SUCCESS(Status
))
406 DPRINT1("ZwCreateKey() for %ws failed (Status 0x%08lx)\n", KeyName
, Status
);
410 if (OutTable
->OemRevision
!= 0)
412 /* We have OEM info in table, so create other OEM subkeys */
413 RtlInitAnsiString(&HardwareKeyNameA
, OemId
);
414 Status
= RtlAnsiStringToUnicodeString(&HardwareKeyName
, &HardwareKeyNameA
, TRUE
);
415 if (!NT_SUCCESS(Status
))
417 DPRINT1("RtlAnsiStringToUnicodeString() for %s failed (Status 0x%08lx)\n", HardwareKeyNameA
, Status
);
421 InitializeObjectAttributes(&ObjectAttributes
,
423 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
426 Status
= ZwCreateKey(&SubKeyHandle
,
433 RtlFreeUnicodeString(&HardwareKeyName
);
435 if (!NT_SUCCESS(Status
))
437 DPRINT1("ZwCreateKey() for %s failed (Status 0x%08lx)\n", HardwareKeyNameA
, Status
);
440 KeyHandle
= SubKeyHandle
;
442 RtlInitAnsiString(&HardwareKeyNameA
, OemTableId
);
443 Status
= RtlAnsiStringToUnicodeString(&HardwareKeyName
, &HardwareKeyNameA
, TRUE
);
444 if (!NT_SUCCESS(Status
))
446 DPRINT1("RtlAnsiStringToUnicodeString() for %s failed (Status 0x%08lx)\n", HardwareKeyNameA
, Status
);
450 InitializeObjectAttributes(&ObjectAttributes
,
452 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
455 Status
= ZwCreateKey(&SubKeyHandle
,
462 RtlFreeUnicodeString(&HardwareKeyName
);
464 if (!NT_SUCCESS(Status
))
466 DPRINT1("ZwCreateKey() for %s failed (Status 0x%08lx)\n", HardwareKeyNameA
, Status
);
469 KeyHandle
= SubKeyHandle
;
471 Status
= RtlStringCbPrintfW(OemRevision
,
474 OutTable
->OemRevision
);
475 if (!NT_SUCCESS(Status
))
477 DPRINT1("RtlStringCbPrintfW() for 0x%08lx failed (Status 0x%08lx)\n", OutTable
->OemRevision
, Status
);
480 RtlInitUnicodeString(&HardwareKeyName
, OemRevision
);
482 InitializeObjectAttributes(&ObjectAttributes
,
484 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
487 Status
= ZwCreateKey(&SubKeyHandle
,
495 if (!NT_SUCCESS(Status
))
497 DPRINT1("ZwCreateKey() for %ws failed (Status 0x%08lx)\n", KeyName
, Status
);
500 KeyHandle
= SubKeyHandle
;
502 /* Table reg value name is always '00000000' */
503 RtlInitUnicodeString(&ValueName
,
505 Status
= ZwSetValueKey(KeyHandle
,
512 if (!NT_SUCCESS(Status
))
514 DPRINT1("ZwSetValueKey() failed (Status 0x%08lx)\n", Status
);
518 return STATUS_SUCCESS
;
522 acpi_create_volatile_registry_tables()
524 OBJECT_ATTRIBUTES ObjectAttributes
;
525 UNICODE_STRING HardwareKeyName
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\HARDWARE\\ACPI");
526 HANDLE KeyHandle
= NULL
;
528 ACPI_STATUS AcpiStatus
;
529 ACPI_TABLE_HEADER
*OutTable
;
530 ACPI_PHYSICAL_ADDRESS RsdpAddress
;
531 ACPI_TABLE_RSDP
*Rsdp
;
532 ACPI_PHYSICAL_ADDRESS Address
;
533 UINT32 TableEntrySize
;
535 /* Create Main Hardware ACPI key*/
536 InitializeObjectAttributes(&ObjectAttributes
,
538 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
541 Status
= ZwCreateKey(&KeyHandle
,
548 if (!NT_SUCCESS(Status
))
550 DPRINT1("ZwCreateKey() for ACPI failed (Status 0x%08lx)\n", Status
);
553 /* Read DSDT table */
554 AcpiStatus
= AcpiGetTable(ACPI_SIG_DSDT
, 0, &OutTable
);
555 if (ACPI_FAILURE(AcpiStatus
))
557 DPRINT1("AcpiGetTable() for DSDT failed (Status 0x%08lx)\n", AcpiStatus
);
558 Status
= STATUS_UNSUCCESSFUL
;
561 /* Dump DSDT table */
562 Status
= acpi_create_registry_table(KeyHandle
, OutTable
, L
"DSDT");
563 if (!NT_SUCCESS(Status
))
565 DPRINT1("acpi_dump_table_to_registry() for DSDT failed (Status 0x%08lx)\n", Status
);
568 /* Read FACS table */
569 AcpiStatus
= AcpiGetTable(ACPI_SIG_FACS
, 0, &OutTable
);
570 if (ACPI_FAILURE(AcpiStatus
))
572 DPRINT1("AcpiGetTable() for FACS failed (Status 0x%08lx)\n", AcpiStatus
);
573 Status
= STATUS_UNSUCCESSFUL
;
576 /* Dump FACS table */
577 Status
= acpi_create_registry_table(KeyHandle
, OutTable
, L
"FACS");
578 if (!NT_SUCCESS(Status
))
580 DPRINT1("acpi_dump_table_to_registry() for FACS failed (Status 0x%08lx)\n", Status
);
583 /* Read FACS table */
584 AcpiStatus
= AcpiGetTable(ACPI_SIG_FADT
, 0, &OutTable
);
585 if (ACPI_FAILURE(AcpiStatus
))
587 DPRINT1("AcpiGetTable() for FADT failed (Status 0x%08lx)\n", AcpiStatus
);
588 Status
= STATUS_UNSUCCESSFUL
;
591 /* Dump FADT table */
592 Status
= acpi_create_registry_table(KeyHandle
, OutTable
, L
"FADT");
593 if (!NT_SUCCESS(Status
))
595 DPRINT1("acpi_dump_table_to_registry() for FADT failed (Status 0x%08lx)\n", Status
);
598 /* This is a rough copy from ACPICA reading of RSDT/XSDT and added to avoid patching acpica */
599 RsdpAddress
= AcpiOsGetRootPointer();
600 /* Map the entire RSDP and extract the address of the RSDT or XSDT */
601 Rsdp
= AcpiOsMapMemory(RsdpAddress
, sizeof(ACPI_TABLE_RSDP
));
604 DPRINT1("AcpiOsMapMemory() failed\n");
605 Status
= STATUS_NO_MEMORY
;
608 /* Use XSDT if present and not overridden. Otherwise, use RSDT */
609 if ((Rsdp
->Revision
> 1) &&
610 Rsdp
->XsdtPhysicalAddress
&&
611 !AcpiGbl_DoNotUseXsdt
)
614 * RSDP contains an XSDT (64-bit physical addresses). We must use
615 * the XSDT if the revision is > 1 and the XSDT pointer is present,
616 * as per the ACPI specification.
618 Address
= (ACPI_PHYSICAL_ADDRESS
)Rsdp
->XsdtPhysicalAddress
;
619 TableEntrySize
= ACPI_XSDT_ENTRY_SIZE
;
623 /* Root table is an RSDT (32-bit physical addresses) */
624 Address
= (ACPI_PHYSICAL_ADDRESS
)Rsdp
->RsdtPhysicalAddress
;
625 TableEntrySize
= ACPI_RSDT_ENTRY_SIZE
;
628 * It is not possible to map more than one entry in some environments,
629 * so unmap the RSDP here before mapping other tables
631 AcpiOsUnmapMemory(Rsdp
, sizeof(ACPI_TABLE_RSDP
));
632 OutTable
= AcpiOsMapMemory(Address
, TableEntrySize
);
635 DPRINT1("AcpiOsMapMemory() failed\n");
636 Status
= STATUS_NO_MEMORY
;
639 /* Dump RSDT table */
640 Status
= acpi_create_registry_table(KeyHandle
, OutTable
, L
"RSDT");
641 AcpiOsUnmapMemory(OutTable
, TableEntrySize
);
642 if (!NT_SUCCESS(Status
))
644 DPRINT1("acpi_dump_table_to_registry() for RSDT failed (Status 0x%08lx)\n", Status
);