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 62static char * 63WindowsFormatException ( 64 LONG WinStatus); 65 66/* Globals */ 67 68#define LOCAL_BUFFER_SIZE 64 69 70static char KeyBuffer[LOCAL_BUFFER_SIZE]; 71static char ErrorBuffer[LOCAL_BUFFER_SIZE]; 72 73/* 74 * List of table signatures reported by EnumSystemFirmwareTables () 75 */ 76UINT32 *Gbl_AvailableTableSignatures; 77UINT32 Gbl_TableCount = 0; 78UINT32 Gbl_SsdtInstance = 0; 79 80BOOLEAN Gbl_TableListInitialized = FALSE; 81 82static ACPI_STATUS 83OslTableInitialize ( 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 100static char * 101WindowsFormatException ( 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 129ACPI_STATUS 130AcpiOsGetTableByAddress ( 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 164ACPI_STATUS 165AcpiOsGetTableByIndex ( 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 *****************************************************************************/ 239static ACPI_STATUS 240OslTableInitialize ( 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 312static ACPI_STATUS 313WindowsGetTableFromRegistry ( 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 489Cleanup: 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 519ACPI_STATUS 520AcpiOsGetTableByName( 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 593void * 594AcpiOsMapMemory ( 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 617void 618AcpiOsUnmapMemory ( 619 void *Where, 620 ACPI_SIZE Length) 621{ 622 623 return; 624} 625#endif 626