1 /******************************************************************************
2 *
3 * Module Name: oswintbl - Windows OSL for obtaining ACPI tables
4 *
5 *****************************************************************************/
6
7 /*
8 * Copyright (C) 2000 - 2023, Intel Corp.
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions, and the following disclaimer,
16 * without modification.
17 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18 * substantially similar to the "NO WARRANTY" disclaimer below
19 * ("Disclaimer") and any redistribution must be conditioned upon
20 * including a substantially similar Disclaimer requirement for further
21 * binary redistribution.
22 * 3. Neither the names of the above-listed copyright holders nor the names
23 * of any contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * Alternatively, this software may be distributed under the terms of the
27 * GNU General Public License ("GPL") version 2 as published by the Free
28 * Software Foundation.
29 *
30 * NO WARRANTY
31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
34 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41 * POSSIBILITY OF SUCH DAMAGES.
42 */
43
44 #include "acpi.h"
45 #include "accommon.h"
46 #include "acutils.h"
47 #include <stdio.h>
48
49 #ifdef WIN32
50 #pragma warning(disable:4115) /* warning C4115: (caused by rpcasync.h) */
51 #include <windows.h>
52
53 #elif WIN64
54 #include <windowsx.h>
55 #endif
56
57 #define _COMPONENT ACPI_OS_SERVICES
58 ACPI_MODULE_NAME ("oswintbl")
59
60 /* Local prototypes */
61
62 static char *
63 WindowsFormatException (
64 LONG WinStatus);
65
66 /* Globals */
67
68 #define LOCAL_BUFFER_SIZE 64
69
70 static char KeyBuffer[LOCAL_BUFFER_SIZE];
71 static char ErrorBuffer[LOCAL_BUFFER_SIZE];
72
73 /*
74 * List of table signatures reported by EnumSystemFirmwareTables ()
75 */
76 UINT32 *Gbl_AvailableTableSignatures;
77 UINT32 Gbl_TableCount = 0;
78 UINT32 Gbl_SsdtInstance = 0;
79
80 BOOLEAN Gbl_TableListInitialized = FALSE;
81
82 static ACPI_STATUS
83 OslTableInitialize (
84 void);
85
86
87 /******************************************************************************
88 *
89 * FUNCTION: WindowsFormatException
90 *
91 * PARAMETERS: WinStatus - Status from a Windows system call
92 *
93 * RETURN: Formatted (ascii) exception code. Front-end to Windows
94 * FormatMessage interface.
95 *
96 * DESCRIPTION: Decode a windows exception
97 *
98 *****************************************************************************/
99
100 static char *
WindowsFormatException(LONG WinStatus)101 WindowsFormatException (
102 LONG WinStatus)
103 {
104
105 ErrorBuffer[0] = 0;
106 FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, NULL, WinStatus, 0,
107 ErrorBuffer, LOCAL_BUFFER_SIZE, NULL);
108
109 return (ErrorBuffer);
110 }
111
112
113 /******************************************************************************
114 *
115 * FUNCTION: AcpiOsGetTableByAddress
116 *
117 * PARAMETERS: Address - Physical address of the ACPI table
118 * Table - Where a pointer to the table is returned
119 *
120 * RETURN: Status; Table buffer is returned if AE_OK.
121 * AE_NOT_FOUND: A valid table was not found at the address
122 *
123 * DESCRIPTION: Get an ACPI table via a physical memory address.
124 *
125 * NOTE: Cannot be implemented without a Windows device driver.
126 *
127 *****************************************************************************/
128
129 ACPI_STATUS
AcpiOsGetTableByAddress(ACPI_PHYSICAL_ADDRESS Address,ACPI_TABLE_HEADER ** Table)130 AcpiOsGetTableByAddress (
131 ACPI_PHYSICAL_ADDRESS Address,
132 ACPI_TABLE_HEADER **Table)
133 {
134
135 fprintf (stderr, "Get table by address is not supported on Windows\n");
136 return (AE_SUPPORT);
137 }
138
139
140 /******************************************************************************
141 *
142 * FUNCTION: AcpiOsGetTableByIndex
143 *
144 * PARAMETERS: Index - Which table to get
145 * Table - Where a pointer to the table is returned
146 * Instance - Where a pointer to the table instance no. is
147 * returned
148 * Address - Where the table physical address is returned
149 *
150 * RETURN: Status; Table buffer and physical address returned if AE_OK.
151 * AE_LIMIT: Index is beyond valid limit
152 *
153 * DESCRIPTION: Get an ACPI table via an index value (0 through n). Returns
154 * AE_LIMIT when an invalid index is reached. Index is not
155 * necessarily an index into the RSDT/XSDT.
156 * SSDT tables are obtained from the Windows registry. All other
157 * tables are obtained through GetSystemFirmwareTable ().
158 *
159 * NOTE: Cannot get the physical address from the windows registry;
160 * zero is returned instead.
161 *
162 *****************************************************************************/
163
164 ACPI_STATUS
AcpiOsGetTableByIndex(UINT32 Index,ACPI_TABLE_HEADER ** Table,UINT32 * Instance,ACPI_PHYSICAL_ADDRESS * Address)165 AcpiOsGetTableByIndex (
166 UINT32 Index,
167 ACPI_TABLE_HEADER **Table,
168 UINT32 *Instance,
169 ACPI_PHYSICAL_ADDRESS *Address)
170 {
171 ACPI_STATUS Status;
172 char *Signature;
173 UINT32 CurrentInstance;
174
175
176 /* Enumerate all ACPI table signatures on first invocation of this function */
177
178 Status = OslTableInitialize ();
179 if (ACPI_FAILURE (Status))
180 {
181 return (Status);
182 }
183
184 /* Validate Index */
185
186 if (Index < Gbl_TableCount)
187 {
188 Signature = malloc (ACPI_NAMESEG_SIZE + 1);
189 if (!Signature)
190 {
191 return (AE_NO_MEMORY);
192 }
193
194 Signature = memmove (Signature, &Gbl_AvailableTableSignatures[Index], ACPI_NAMESEG_SIZE);
195 }
196 else
197 {
198 return (AE_LIMIT);
199 }
200
201 if (ACPI_COMPARE_NAMESEG (Signature, ACPI_SIG_SSDT))
202 {
203 CurrentInstance = Gbl_SsdtInstance;
204 Gbl_SsdtInstance++;
205 }
206 else
207 {
208 CurrentInstance = 0;
209 }
210
211 Status = AcpiOsGetTableByName (Signature, CurrentInstance, Table, Address);
212 if (ACPI_SUCCESS (Status))
213 {
214 *Instance = CurrentInstance;
215 }
216 else if (Status == AE_NOT_FOUND &&
217 ACPI_COMPARE_NAMESEG (Signature, ACPI_SIG_SSDT))
218 {
219 /* Treat SSDTs that are not found as invalid index. */
220 Status = AE_LIMIT;
221 }
222
223 free (Signature);
224 return (Status);
225 }
226
227 /******************************************************************************
228 *
229 * FUNCTION: OslTableInitialize
230 *
231 * PARAMETERS: None
232 *
233 * RETURN: Status
234 *
235 * DESCRIPTION: Initialize ACPI table data. Enumerate all ACPI table signatures
236 * and save them to a global list.
237 *
238 *****************************************************************************/
239 static ACPI_STATUS
OslTableInitialize(void)240 OslTableInitialize (
241 void)
242 {
243 UINT32 ResultSize;
244 UINT32 DataSize;
245
246 if (Gbl_TableListInitialized)
247 {
248 return (AE_OK);
249 }
250
251 /*
252 * ACPI table signatures are always 4 characters. Therefore, the data size
253 * buffer should be a multiple of 4
254 */
255 DataSize = EnumSystemFirmwareTables ('ACPI', NULL, 0);
256 if (DataSize % ACPI_NAMESEG_SIZE)
257 {
258 return (AE_ERROR);
259 }
260
261 /*
262 * EnumSystemFirmwareTables () does not report the DSDT or XSDT. Work around this
263 * by adding these entries manually.
264 */
265 Gbl_TableCount = 2 + DataSize / ACPI_NAMESEG_SIZE;
266 Gbl_AvailableTableSignatures = malloc (Gbl_TableCount * ACPI_NAMESEG_SIZE);
267 if (!Gbl_AvailableTableSignatures)
268 {
269 return (AE_NO_MEMORY);
270 }
271
272 ResultSize = EnumSystemFirmwareTables ('ACPI', Gbl_AvailableTableSignatures, DataSize);
273 if (ResultSize > DataSize)
274 {
275 return (AE_ERROR);
276 }
277
278 /* Insert the DSDT and XSDT tables signatures */
279
280 Gbl_AvailableTableSignatures [Gbl_TableCount - 1] = 'TDSD';
281 Gbl_AvailableTableSignatures [Gbl_TableCount - 2] = 'TDSX';
282
283 Gbl_TableListInitialized = TRUE;
284 return (AE_OK);
285 }
286
287
288 /******************************************************************************
289 *
290 * FUNCTION: WindowsGetTableFromRegistry
291 *
292 * PARAMETERS: Signature - ACPI Signature for desired table. Must be
293 * a null terminated 4-character string.
294 * Instance - For SSDTs (0...n). Use 0 otherwise.
295 * Table - Where a pointer to the table is returned
296 * Address - Where the table physical address is returned
297 *
298 * RETURN: Status; Table buffer and physical address returned if AE_OK.
299 * AE_LIMIT: Instance is beyond valid limit
300 * AE_NOT_FOUND: A table with the signature was not found
301 *
302 * DESCRIPTION: Get an ACPI table via a table signature (4 ASCII characters).
303 * Returns AE_LIMIT when an invalid instance is reached.
304 * Table is obtained from the Windows registry.
305 *
306 * NOTE: Assumes the input signature is uppercase.
307 * Cannot get the physical address from the windows registry;
308 * zero is returned instead.
309 *
310 *****************************************************************************/
311
312 static ACPI_STATUS
WindowsGetTableFromRegistry(char * Signature,UINT32 Instance,ACPI_TABLE_HEADER ** Table,ACPI_PHYSICAL_ADDRESS * Address)313 WindowsGetTableFromRegistry (
314 char *Signature,
315 UINT32 Instance,
316 ACPI_TABLE_HEADER **Table,
317 ACPI_PHYSICAL_ADDRESS *Address)
318 {
319 HKEY Handle = NULL;
320 LONG WinStatus;
321 ULONG Type;
322 ULONG NameSize;
323 ULONG DataSize;
324 HKEY SubKey;
325 ULONG i;
326 ACPI_TABLE_HEADER *ReturnTable;
327 ACPI_STATUS Status = AE_OK;
328
329
330 /* Get a handle to the table key */
331
332 while (1)
333 {
334 strcpy(KeyBuffer, "HARDWARE\\ACPI\\");
335 if (AcpiUtSafeStrcat(KeyBuffer, sizeof(KeyBuffer), Signature))
336 {
337 return (AE_BUFFER_OVERFLOW);
338 }
339
340 /*
341 * Windows stores SSDT at SSDT, SSD1, ..., SSD9, SSDA, ..., SSDS, SSDT,
342 * SSDU, ..., SSDY. If the first (0th) and the 29th tables have the same
343 * OEM ID, Table ID and Revision, then the 29th entry will overwrite the
344 * first entry... Let's hope that we do not have that many entries.
345 */
346 if (Instance > 0 && ACPI_COMPARE_NAMESEG(Signature, ACPI_SIG_SSDT))
347 {
348 if (Instance < 10)
349 {
350 KeyBuffer[strlen(KeyBuffer) - 1] = '0' + (char)Instance;
351 }
352 else if (Instance < 29)
353 {
354 KeyBuffer[strlen(KeyBuffer) - 1] = 'A' + (char)(Instance - 10);
355 }
356 else
357 {
358 return (AE_LIMIT);
359 }
360 }
361
362 WinStatus = RegOpenKeyEx(HKEY_LOCAL_MACHINE, KeyBuffer,
363 0L, KEY_READ, &Handle);
364
365 if (WinStatus != ERROR_SUCCESS)
366 {
367 /*
368 * Somewhere along the way, MS changed the registry entry for
369 * the FADT from
370 * HARDWARE/ACPI/FACP to
371 * HARDWARE/ACPI/FADT.
372 *
373 * This code allows for both.
374 */
375 if (ACPI_COMPARE_NAMESEG(Signature, "FACP"))
376 {
377 Signature = "FADT";
378 }
379 else if (ACPI_COMPARE_NAMESEG(Signature, "XSDT"))
380 {
381 Signature = "RSDT";
382 }
383 else if (ACPI_COMPARE_NAMESEG(Signature, ACPI_SIG_SSDT))
384 {
385 /*
386 * SSDT may not be present on older Windows versions, but it is
387 * also possible that the index is not found.
388 */
389 return (AE_NOT_FOUND);
390 }
391 else
392 {
393 fprintf(stderr,
394 "Could not find %s in registry at %s: %s (WinStatus=0x%X)\n",
395 Signature, KeyBuffer, WindowsFormatException(WinStatus), WinStatus);
396 return (AE_NOT_FOUND);
397 }
398 }
399 else
400 {
401 break;
402 }
403 }
404
405 /* Actual data for the table is down a couple levels */
406
407 for (i = 0; ;)
408 {
409 WinStatus = RegEnumKey(Handle, i, KeyBuffer, sizeof(KeyBuffer));
410 i++;
411 if (WinStatus == ERROR_NO_MORE_ITEMS)
412 {
413 break;
414 }
415
416 WinStatus = RegOpenKey(Handle, KeyBuffer, &SubKey);
417 if (WinStatus != ERROR_SUCCESS)
418 {
419 fprintf(stderr, "Could not open %s entry: %s\n",
420 Signature, WindowsFormatException(WinStatus));
421 Status = AE_ERROR;
422 goto Cleanup;
423 }
424
425 RegCloseKey(Handle);
426 Handle = SubKey;
427 i = 0;
428 }
429
430 /* Find the (binary) table entry */
431
432 for (i = 0; ; i++)
433 {
434 NameSize = sizeof(KeyBuffer);
435 WinStatus = RegEnumValue(Handle, i, KeyBuffer, &NameSize, NULL,
436 &Type, NULL, 0);
437 if (WinStatus != ERROR_SUCCESS)
438 {
439 fprintf(stderr, "Could not get %s registry entry: %s\n",
440 Signature, WindowsFormatException(WinStatus));
441 Status = AE_ERROR;
442 goto Cleanup;
443 }
444
445 if (Type == REG_BINARY)
446 {
447 break;
448 }
449 }
450
451 /* Get the size of the table */
452
453 WinStatus = RegQueryValueEx(Handle, KeyBuffer, NULL, NULL,
454 NULL, &DataSize);
455 if (WinStatus != ERROR_SUCCESS)
456 {
457 fprintf(stderr, "Could not read the %s table size: %s\n",
458 Signature, WindowsFormatException(WinStatus));
459 Status = AE_ERROR;
460 goto Cleanup;
461 }
462
463 /* Allocate a new buffer for the table */
464
465 ReturnTable = malloc(DataSize);
466 if (!ReturnTable)
467 {
468 Status = AE_NO_MEMORY;
469 goto Cleanup;
470 }
471
472 /* Get the actual table from the registry */
473
474 WinStatus = RegQueryValueEx(Handle, KeyBuffer, NULL, NULL,
475 (UCHAR *)ReturnTable, &DataSize);
476
477 if (WinStatus != ERROR_SUCCESS)
478 {
479 fprintf(stderr, "Could not read %s data: %s\n",
480 Signature, WindowsFormatException(WinStatus));
481 free(ReturnTable);
482 Status = AE_ERROR;
483 goto Cleanup;
484 }
485
486 *Table = ReturnTable;
487 *Address = 0;
488
489 Cleanup:
490 RegCloseKey(Handle);
491 return (Status);
492 }
493
494
495 /******************************************************************************
496 *
497 * FUNCTION: AcpiOsGetTableByName
498 *
499 * PARAMETERS: Signature - ACPI Signature for desired table. Must be
500 * a null terminated 4-character string.
501 * Instance - For SSDTs (0...n). Use 0 otherwise.
502 * Table - Where a pointer to the table is returned
503 * Address - Where the table physical address is returned
504 *
505 * RETURN: Status; Table buffer and physical address returned if AE_OK.
506 * AE_LIMIT: Instance is beyond valid limit
507 * AE_NOT_FOUND: A table with the signature was not found
508 *
509 * DESCRIPTION: Get an ACPI table via a table signature (4 ASCII characters).
510 * Returns AE_LIMIT when an invalid instance is reached.
511 * Table is obtained from the Windows registry.
512 *
513 * NOTE: Assumes the input signature is uppercase.
514 * Cannot get the physical address from the windows registry;
515 * zero is returned instead.
516 *
517 *****************************************************************************/
518
519 ACPI_STATUS
AcpiOsGetTableByName(char * Signature,UINT32 Instance,ACPI_TABLE_HEADER ** Table,ACPI_PHYSICAL_ADDRESS * Address)520 AcpiOsGetTableByName(
521 char *Signature,
522 UINT32 Instance,
523 ACPI_TABLE_HEADER **Table,
524 ACPI_PHYSICAL_ADDRESS *Address)
525 {
526 LONG Result;
527 ACPI_STATUS Status = AE_OK;
528 UINT32 DataSize;
529 ACPI_TABLE_HEADER *ReturnTable;
530 UINT32 UIntSignature = 0;
531
532
533 /* Multiple instances are only supported for SSDT tables. */
534
535 if (Instance > 0 && !ACPI_COMPARE_NAMESEG (Signature, ACPI_SIG_SSDT))
536 {
537 return (AE_LIMIT);
538 }
539
540 if (ACPI_COMPARE_NAMESEG (Signature, ACPI_SIG_SSDT))
541 {
542 Status = WindowsGetTableFromRegistry ("SSDT", Instance, Table, Address);
543 return (Status);
544 }
545
546 /* GetSystemFirmwareTable requires the table signature to be UINT32 */
547
548 UIntSignature = *ACPI_CAST_PTR (UINT32, Signature);
549 DataSize = GetSystemFirmwareTable('ACPI', UIntSignature, NULL, 0);
550 if (!DataSize)
551 {
552 fprintf(stderr, "The table signature %s does not exist.", Signature);
553 return (AE_ERROR);
554 }
555
556 ReturnTable = malloc(DataSize);
557 if (!ReturnTable)
558 {
559 return (AE_NO_MEMORY);
560 }
561
562 Result = GetSystemFirmwareTable('ACPI', UIntSignature, ReturnTable, DataSize);
563 if (Result > (LONG) DataSize)
564 {
565 /* Clean up */
566
567 fprintf (stderr, "Could not read %s data\n", Signature);
568 free (ReturnTable);
569 return (AE_ERROR);
570 }
571
572 *Table = ReturnTable;
573 return (Status);
574 }
575
576
577 /* These are here for acpidump only, so we don't need to link oswinxf */
578
579 #ifdef ACPI_DUMP_APP
580 /******************************************************************************
581 *
582 * FUNCTION: AcpiOsMapMemory
583 *
584 * PARAMETERS: Where - Physical address of memory to be mapped
585 * Length - How much memory to map
586 *
587 * RETURN: Pointer to mapped memory. Null on error.
588 *
589 * DESCRIPTION: Map physical memory into caller's address space
590 *
591 *****************************************************************************/
592
593 void *
AcpiOsMapMemory(ACPI_PHYSICAL_ADDRESS Where,ACPI_SIZE Length)594 AcpiOsMapMemory (
595 ACPI_PHYSICAL_ADDRESS Where,
596 ACPI_SIZE Length)
597 {
598
599 return (ACPI_TO_POINTER ((ACPI_SIZE) Where));
600 }
601
602
603 /******************************************************************************
604 *
605 * FUNCTION: AcpiOsUnmapMemory
606 *
607 * PARAMETERS: Where - Logical address of memory to be unmapped
608 * Length - How much memory to unmap
609 *
610 * RETURN: None.
611 *
612 * DESCRIPTION: Delete a previously created mapping. Where and Length must
613 * correspond to a previous mapping exactly.
614 *
615 *****************************************************************************/
616
617 void
AcpiOsUnmapMemory(void * Where,ACPI_SIZE Length)618 AcpiOsUnmapMemory (
619 void *Where,
620 ACPI_SIZE Length)
621 {
622
623 return;
624 }
625 #endif
626