oswintbl.c revision 1.1.1.11 1 /******************************************************************************
2 *
3 * Module Name: oswintbl - Windows OSL for obtaining ACPI tables
4 *
5 *****************************************************************************/
6
7 /*
8 * Copyright (C) 2000 - 2019, 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 MERCHANTIBILITY 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 * Tables supported in the Windows registry. Zero or more SSDTs are assumed to
75 * follow these tables.
76 */
77 static char *SupportedTables[] =
78 {
79 "DSDT",
80 "RSDT",
81 "FACS",
82 "FACP"
83 };
84
85 /* Number of table names for the table above. */
86
87 #define ACPI_OS_NUM_TABLE_ENTRIES 4
88
89
90 /******************************************************************************
91 *
92 * FUNCTION: WindowsFormatException
93 *
94 * PARAMETERS: WinStatus - Status from a Windows system call
95 *
96 * RETURN: Formatted (ascii) exception code. Front-end to Windows
97 * FormatMessage interface.
98 *
99 * DESCRIPTION: Decode a windows exception
100 *
101 *****************************************************************************/
102
103 static char *
104 WindowsFormatException (
105 LONG WinStatus)
106 {
107
108 ErrorBuffer[0] = 0;
109 FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, NULL, WinStatus, 0,
110 ErrorBuffer, LOCAL_BUFFER_SIZE, NULL);
111
112 return (ErrorBuffer);
113 }
114
115
116 /******************************************************************************
117 *
118 * FUNCTION: AcpiOsGetTableByAddress
119 *
120 * PARAMETERS: Address - Physical address of the ACPI table
121 * Table - Where a pointer to the table is returned
122 *
123 * RETURN: Status; Table buffer is returned if AE_OK.
124 * AE_NOT_FOUND: A valid table was not found at the address
125 *
126 * DESCRIPTION: Get an ACPI table via a physical memory address.
127 *
128 * NOTE: Cannot be implemented without a Windows device driver.
129 *
130 *****************************************************************************/
131
132 ACPI_STATUS
133 AcpiOsGetTableByAddress (
134 ACPI_PHYSICAL_ADDRESS Address,
135 ACPI_TABLE_HEADER **Table)
136 {
137
138 fprintf (stderr, "Get table by address is not supported on Windows\n");
139 return (AE_SUPPORT);
140 }
141
142
143 /******************************************************************************
144 *
145 * FUNCTION: AcpiOsGetTableByIndex
146 *
147 * PARAMETERS: Index - Which table to get
148 * Table - Where a pointer to the table is returned
149 * Instance - Where a pointer to the table instance no. is
150 * returned
151 * Address - Where the table physical address is returned
152 *
153 * RETURN: Status; Table buffer and physical address returned if AE_OK.
154 * AE_LIMIT: Index is beyond valid limit
155 *
156 * DESCRIPTION: Get an ACPI table via an index value (0 through n). Returns
157 * AE_LIMIT when an invalid index is reached. Index is not
158 * necessarily an index into the RSDT/XSDT.
159 * Table is obtained from the Windows registry.
160 *
161 * NOTE: Cannot get the physical address from the windows registry;
162 * zero is returned instead.
163 *
164 *****************************************************************************/
165
166 ACPI_STATUS
167 AcpiOsGetTableByIndex (
168 UINT32 Index,
169 ACPI_TABLE_HEADER **Table,
170 UINT32 *Instance,
171 ACPI_PHYSICAL_ADDRESS *Address)
172 {
173 ACPI_STATUS Status;
174 char *Signature;
175
176
177 if (Index < ACPI_OS_NUM_TABLE_ENTRIES)
178 {
179 Signature = SupportedTables[Index];
180 Index = 0;
181 }
182 else
183 {
184 Signature = ACPI_SIG_SSDT;
185 Index -= ACPI_OS_NUM_TABLE_ENTRIES;
186 }
187
188 Status = AcpiOsGetTableByName (Signature, Index, Table, Address);
189
190 if (ACPI_SUCCESS (Status))
191 {
192 *Instance = Index;
193 }
194 else if (Status == AE_NOT_FOUND &&
195 ACPI_COMPARE_NAMESEG (Signature, ACPI_SIG_SSDT))
196 {
197 /* Treat SSDTs that are not found as invalid index. */
198 Status = (AE_LIMIT);
199 }
200
201 return (Status);
202 }
203
204
205 /******************************************************************************
206 *
207 * FUNCTION: AcpiOsGetTableByName
208 *
209 * PARAMETERS: Signature - ACPI Signature for desired table. Must be
210 * a null terminated 4-character string.
211 * Instance - For SSDTs (0...n). Use 0 otherwise.
212 * Table - Where a pointer to the table is returned
213 * Address - Where the table physical address is returned
214 *
215 * RETURN: Status; Table buffer and physical address returned if AE_OK.
216 * AE_LIMIT: Instance is beyond valid limit
217 * AE_NOT_FOUND: A table with the signature was not found
218 *
219 * DESCRIPTION: Get an ACPI table via a table signature (4 ASCII characters).
220 * Returns AE_LIMIT when an invalid instance is reached.
221 * Table is obtained from the Windows registry.
222 *
223 * NOTE: Assumes the input signature is uppercase.
224 * Cannot get the physical address from the windows registry;
225 * zero is returned instead.
226 *
227 *****************************************************************************/
228
229 ACPI_STATUS
230 AcpiOsGetTableByName (
231 char *Signature,
232 UINT32 Instance,
233 ACPI_TABLE_HEADER **Table,
234 ACPI_PHYSICAL_ADDRESS *Address)
235 {
236 HKEY Handle = NULL;
237 LONG WinStatus;
238 ULONG Type;
239 ULONG NameSize;
240 ULONG DataSize;
241 HKEY SubKey;
242 ULONG i;
243 ACPI_TABLE_HEADER *ReturnTable;
244 ACPI_STATUS Status = AE_OK;
245
246
247 /* Multiple instances are only supported for SSDT tables. */
248
249 if (Instance > 0 && !ACPI_COMPARE_NAMESEG (Signature, ACPI_SIG_SSDT))
250 {
251 return (AE_LIMIT);
252 }
253
254 /* Get a handle to the table key */
255
256 while (1)
257 {
258 strcpy (KeyBuffer, "HARDWARE\\ACPI\\");
259 if (AcpiUtSafeStrcat (KeyBuffer, sizeof (KeyBuffer), Signature))
260 {
261 return (AE_BUFFER_OVERFLOW);
262 }
263
264 /*
265 * Windows stores SSDT at SSDT, SSD1, ..., SSD9, SSDA, ..., SSDS, SSDT,
266 * SSDU, ..., SSDY. If the first (0th) and the 29th tables have the same
267 * OEM ID, Table ID and Revision, then the 29th entry will overwrite the
268 * first entry... Let's hope that we do not have that many entries.
269 */
270 if (Instance > 0 && ACPI_COMPARE_NAMESEG (Signature, ACPI_SIG_SSDT))
271 {
272 if (Instance < 10)
273 {
274 KeyBuffer[strlen (KeyBuffer) - 1] = '0' + (char) Instance;
275 }
276 else if (Instance < 29)
277 {
278 KeyBuffer[strlen (KeyBuffer) - 1] = 'A' + (char) (Instance - 10);
279 }
280 else
281 {
282 return (AE_LIMIT);
283 }
284 }
285
286 WinStatus = RegOpenKeyEx (HKEY_LOCAL_MACHINE, KeyBuffer,
287 0L, KEY_READ, &Handle);
288
289 if (WinStatus != ERROR_SUCCESS)
290 {
291 /*
292 * Somewhere along the way, MS changed the registry entry for
293 * the FADT from
294 * HARDWARE/ACPI/FACP to
295 * HARDWARE/ACPI/FADT.
296 *
297 * This code allows for both.
298 */
299 if (ACPI_COMPARE_NAMESEG (Signature, "FACP"))
300 {
301 Signature = "FADT";
302 }
303 else if (ACPI_COMPARE_NAMESEG (Signature, "XSDT"))
304 {
305 Signature = "RSDT";
306 }
307 else if (ACPI_COMPARE_NAMESEG (Signature, ACPI_SIG_SSDT))
308 {
309 /* SSDT may not be present on older Windows versions, but it is
310 * also possible that the index is not found. */
311 return (AE_NOT_FOUND);
312 }
313 else
314 {
315 fprintf (stderr,
316 "Could not find %s in registry at %s: %s (WinStatus=0x%X)\n",
317 Signature, KeyBuffer, WindowsFormatException (WinStatus), WinStatus);
318 return (AE_NOT_FOUND);
319 }
320 }
321 else
322 {
323 break;
324 }
325 }
326
327 /* Actual data for the table is down a couple levels */
328
329 for (i = 0; ;)
330 {
331 WinStatus = RegEnumKey (Handle, i, KeyBuffer, sizeof (KeyBuffer));
332 i++;
333 if (WinStatus == ERROR_NO_MORE_ITEMS)
334 {
335 break;
336 }
337
338 WinStatus = RegOpenKey (Handle, KeyBuffer, &SubKey);
339 if (WinStatus != ERROR_SUCCESS)
340 {
341 fprintf (stderr, "Could not open %s entry: %s\n",
342 Signature, WindowsFormatException (WinStatus));
343 Status = AE_ERROR;
344 goto Cleanup;
345 }
346
347 RegCloseKey (Handle);
348 Handle = SubKey;
349 i = 0;
350 }
351
352 /* Find the (binary) table entry */
353
354 for (i = 0; ; i++)
355 {
356 NameSize = sizeof (KeyBuffer);
357 WinStatus = RegEnumValue (Handle, i, KeyBuffer, &NameSize, NULL,
358 &Type, NULL, 0);
359 if (WinStatus != ERROR_SUCCESS)
360 {
361 fprintf (stderr, "Could not get %s registry entry: %s\n",
362 Signature, WindowsFormatException (WinStatus));
363 Status = AE_ERROR;
364 goto Cleanup;
365 }
366
367 if (Type == REG_BINARY)
368 {
369 break;
370 }
371 }
372
373 /* Get the size of the table */
374
375 WinStatus = RegQueryValueEx (Handle, KeyBuffer, NULL, NULL,
376 NULL, &DataSize);
377 if (WinStatus != ERROR_SUCCESS)
378 {
379 fprintf (stderr, "Could not read the %s table size: %s\n",
380 Signature, WindowsFormatException (WinStatus));
381 Status = AE_ERROR;
382 goto Cleanup;
383 }
384
385 /* Allocate a new buffer for the table */
386
387 ReturnTable = malloc (DataSize);
388 if (!ReturnTable)
389 {
390 Status = AE_NO_MEMORY;
391 goto Cleanup;
392 }
393
394 /* Get the actual table from the registry */
395
396 WinStatus = RegQueryValueEx (Handle, KeyBuffer, NULL, NULL,
397 (UCHAR *) ReturnTable, &DataSize);
398 if (WinStatus != ERROR_SUCCESS)
399 {
400 fprintf (stderr, "Could not read %s data: %s\n",
401 Signature, WindowsFormatException (WinStatus));
402 free (ReturnTable);
403 Status = AE_ERROR;
404 goto Cleanup;
405 }
406
407 *Table = ReturnTable;
408 *Address = 0;
409
410 Cleanup:
411 RegCloseKey (Handle);
412 return (Status);
413 }
414
415
416 /* These are here for acpidump only, so we don't need to link oswinxf */
417
418 #ifdef ACPI_DUMP_APP
419 /******************************************************************************
420 *
421 * FUNCTION: AcpiOsMapMemory
422 *
423 * PARAMETERS: Where - Physical address of memory to be mapped
424 * Length - How much memory to map
425 *
426 * RETURN: Pointer to mapped memory. Null on error.
427 *
428 * DESCRIPTION: Map physical memory into caller's address space
429 *
430 *****************************************************************************/
431
432 void *
433 AcpiOsMapMemory (
434 ACPI_PHYSICAL_ADDRESS Where,
435 ACPI_SIZE Length)
436 {
437
438 return (ACPI_TO_POINTER ((ACPI_SIZE) Where));
439 }
440
441
442 /******************************************************************************
443 *
444 * FUNCTION: AcpiOsUnmapMemory
445 *
446 * PARAMETERS: Where - Logical address of memory to be unmapped
447 * Length - How much memory to unmap
448 *
449 * RETURN: None.
450 *
451 * DESCRIPTION: Delete a previously created mapping. Where and Length must
452 * correspond to a previous mapping exactly.
453 *
454 *****************************************************************************/
455
456 void
457 AcpiOsUnmapMemory (
458 void *Where,
459 ACPI_SIZE Length)
460 {
461
462 return;
463 }
464 #endif
465