Sync ACPICA with Intel's version 20170119.
[dragonfly.git] / sys / contrib / dev / acpica / source / os_specific / service_layers / oswintbl.c
1 /******************************************************************************
2  *
3  * Module Name: oswintbl - Windows OSL for obtaining ACPI tables
4  *
5  *****************************************************************************/
6
7 /*
8  * Copyright (C) 2000 - 2017, 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 && ACPI_COMPARE_NAME (Signature, ACPI_SIG_SSDT))
195     {
196         /* Treat SSDTs that are not found as invalid index. */
197         Status = (AE_LIMIT);
198     }
199
200     return (Status);
201 }
202
203
204 /******************************************************************************
205  *
206  * FUNCTION:    AcpiOsGetTableByName
207  *
208  * PARAMETERS:  Signature       - ACPI Signature for desired table. Must be
209  *                                a null terminated 4-character string.
210  *              Instance        - For SSDTs (0...n). Use 0 otherwise.
211  *              Table           - Where a pointer to the table is returned
212  *              Address         - Where the table physical address is returned
213  *
214  * RETURN:      Status; Table buffer and physical address returned if AE_OK.
215  *              AE_LIMIT: Instance is beyond valid limit
216  *              AE_NOT_FOUND: A table with the signature was not found
217  *
218  * DESCRIPTION: Get an ACPI table via a table signature (4 ASCII characters).
219  *              Returns AE_LIMIT when an invalid instance is reached.
220  *              Table is obtained from the Windows registry.
221  *
222  * NOTE:        Assumes the input signature is uppercase.
223  *              Cannot get the physical address from the windows registry;
224  *              zero is returned instead.
225  *
226  *****************************************************************************/
227
228 ACPI_STATUS
229 AcpiOsGetTableByName (
230     char                    *Signature,
231     UINT32                  Instance,
232     ACPI_TABLE_HEADER       **Table,
233     ACPI_PHYSICAL_ADDRESS   *Address)
234 {
235     HKEY                    Handle = NULL;
236     LONG                    WinStatus;
237     ULONG                   Type;
238     ULONG                   NameSize;
239     ULONG                   DataSize;
240     HKEY                    SubKey;
241     ULONG                   i;
242     ACPI_TABLE_HEADER       *ReturnTable;
243     ACPI_STATUS             Status = AE_OK;
244
245
246     /* Multiple instances are only supported for SSDT tables. */
247
248     if (Instance > 0 && !ACPI_COMPARE_NAME (Signature, ACPI_SIG_SSDT))
249     {
250         return (AE_LIMIT);
251     }
252
253     /* Get a handle to the table key */
254
255     while (1)
256     {
257         strcpy (KeyBuffer, "HARDWARE\\ACPI\\");
258         if (AcpiUtSafeStrcat (KeyBuffer, sizeof (KeyBuffer), Signature))
259         {
260             return (AE_BUFFER_OVERFLOW);
261         }
262
263         /*
264          * Windows stores SSDT at SSDT, SSD1, ..., SSD9, SSDA, ..., SSDS, SSDT,
265          * SSDU, ..., SSDY. If the first (0th) and the 29th tables have the same
266          * OEM ID, Table ID and Revision, then the 29th entry will overwrite the
267          * first entry... Let's hope that we do not have that many entries.
268          */
269         if (Instance > 0 && ACPI_COMPARE_NAME (Signature, ACPI_SIG_SSDT))
270         {
271             if (Instance < 10)
272             {
273                 KeyBuffer[strlen (KeyBuffer) - 1] = '0' + (char) Instance;
274             }
275             else if (Instance < 29)
276             {
277                 KeyBuffer[strlen (KeyBuffer) - 1] = 'A' + (char) (Instance - 10);
278             }
279             else
280             {
281                 return (AE_LIMIT);
282             }
283         }
284
285         WinStatus = RegOpenKeyEx (HKEY_LOCAL_MACHINE, KeyBuffer,
286             0L, KEY_READ, &Handle);
287
288         if (WinStatus != ERROR_SUCCESS)
289         {
290             /*
291              * Somewhere along the way, MS changed the registry entry for
292              * the FADT from
293              * HARDWARE/ACPI/FACP  to
294              * HARDWARE/ACPI/FADT.
295              *
296              * This code allows for both.
297              */
298             if (ACPI_COMPARE_NAME (Signature, "FACP"))
299             {
300                 Signature = "FADT";
301             }
302             else if (ACPI_COMPARE_NAME (Signature, "XSDT"))
303             {
304                 Signature = "RSDT";
305             }
306             else if (ACPI_COMPARE_NAME (Signature, ACPI_SIG_SSDT))
307             {
308                 /* SSDT may not be present on older Windows versions, but it is
309                  * also possible that the index is not found. */
310                 return (AE_NOT_FOUND);
311             }
312             else
313             {
314                 fprintf (stderr,
315                     "Could not find %s in registry at %s: %s (WinStatus=0x%X)\n",
316                     Signature, KeyBuffer, WindowsFormatException (WinStatus), WinStatus);
317                 return (AE_NOT_FOUND);
318             }
319         }
320         else
321         {
322             break;
323         }
324     }
325
326     /* Actual data for the table is down a couple levels */
327
328     for (i = 0; ;)
329     {
330         WinStatus = RegEnumKey (Handle, i, KeyBuffer, sizeof (KeyBuffer));
331         i++;
332         if (WinStatus == ERROR_NO_MORE_ITEMS)
333         {
334             break;
335         }
336
337         WinStatus = RegOpenKey (Handle, KeyBuffer, &SubKey);
338         if (WinStatus != ERROR_SUCCESS)
339         {
340             fprintf (stderr, "Could not open %s entry: %s\n",
341                 Signature, WindowsFormatException (WinStatus));
342             Status = AE_ERROR;
343             goto Cleanup;
344         }
345
346         RegCloseKey (Handle);
347         Handle = SubKey;
348         i = 0;
349     }
350
351     /* Find the (binary) table entry */
352
353     for (i = 0; ; i++)
354     {
355         NameSize = sizeof (KeyBuffer);
356         WinStatus = RegEnumValue (Handle, i, KeyBuffer, &NameSize, NULL,
357             &Type, NULL, 0);
358         if (WinStatus != ERROR_SUCCESS)
359         {
360             fprintf (stderr, "Could not get %s registry entry: %s\n",
361                 Signature, WindowsFormatException (WinStatus));
362             Status = AE_ERROR;
363             goto Cleanup;
364         }
365
366         if (Type == REG_BINARY)
367         {
368             break;
369         }
370     }
371
372     /* Get the size of the table */
373
374     WinStatus = RegQueryValueEx (Handle, KeyBuffer, NULL, NULL,
375         NULL, &DataSize);
376     if (WinStatus != ERROR_SUCCESS)
377     {
378         fprintf (stderr, "Could not read the %s table size: %s\n",
379             Signature, WindowsFormatException (WinStatus));
380         Status = AE_ERROR;
381         goto Cleanup;
382     }
383
384     /* Allocate a new buffer for the table */
385
386     ReturnTable = malloc (DataSize);
387     if (!ReturnTable)
388     {
389         Status = AE_NO_MEMORY;
390         goto Cleanup;
391     }
392
393     /* Get the actual table from the registry */
394
395     WinStatus = RegQueryValueEx (Handle, KeyBuffer, NULL, NULL,
396         (UCHAR *) ReturnTable, &DataSize);
397     if (WinStatus != ERROR_SUCCESS)
398     {
399         fprintf (stderr, "Could not read %s data: %s\n",
400             Signature, WindowsFormatException (WinStatus));
401         free (ReturnTable);
402         Status = AE_ERROR;
403         goto Cleanup;
404     }
405
406     *Table = ReturnTable;
407     *Address = 0;
408
409 Cleanup:
410     RegCloseKey (Handle);
411     return (Status);
412 }
413
414
415 /* These are here for acpidump only, so we don't need to link oswinxf */
416
417 #ifdef ACPI_DUMP_APP
418 /******************************************************************************
419  *
420  * FUNCTION:    AcpiOsMapMemory
421  *
422  * PARAMETERS:  Where               - Physical address of memory to be mapped
423  *              Length              - How much memory to map
424  *
425  * RETURN:      Pointer to mapped memory. Null on error.
426  *
427  * DESCRIPTION: Map physical memory into caller's address space
428  *
429  *****************************************************************************/
430
431 void *
432 AcpiOsMapMemory (
433     ACPI_PHYSICAL_ADDRESS   Where,
434     ACPI_SIZE               Length)
435 {
436
437     return (ACPI_TO_POINTER ((ACPI_SIZE) Where));
438 }
439
440
441 /******************************************************************************
442  *
443  * FUNCTION:    AcpiOsUnmapMemory
444  *
445  * PARAMETERS:  Where               - Logical address of memory to be unmapped
446  *              Length              - How much memory to unmap
447  *
448  * RETURN:      None.
449  *
450  * DESCRIPTION: Delete a previously created mapping. Where and Length must
451  *              correspond to a previous mapping exactly.
452  *
453  *****************************************************************************/
454
455 void
456 AcpiOsUnmapMemory (
457     void                    *Where,
458     ACPI_SIZE               Length)
459 {
460
461     return;
462 }
463 #endif