1 /****************************************************************************** 2 * 3 * Module Name: exutils - interpreter/scanner utilities 4 * 5 *****************************************************************************/ 6 7 /* 8 * Copyright (C) 2000 - 2022, 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 /* 45 * DEFINE_AML_GLOBALS is tested in amlcode.h 46 * to determine whether certain global names should be "defined" or only 47 * "declared" in the current compilation. This enhances maintainability 48 * by enabling a single header file to embody all knowledge of the names 49 * in question. 50 * 51 * Exactly one module of any executable should #define DEFINE_GLOBALS 52 * before #including the header files which use this convention. The 53 * names in question will be defined and initialized in that module, 54 * and declared as extern in all other modules which #include those 55 * header files. 56 */ 57 58 #define DEFINE_AML_GLOBALS 59 60 #include "acpi.h" 61 #include "accommon.h" 62 #include "acinterp.h" 63 #include "amlcode.h" 64 65 #define _COMPONENT ACPI_EXECUTER 66 ACPI_MODULE_NAME ("exutils") 67 68 /* Local prototypes */ 69 70 static UINT32 71 AcpiExDigitsNeeded ( 72 UINT64 Value, 73 UINT32 Base); 74 75 76 /******************************************************************************* 77 * 78 * FUNCTION: AcpiExEnterInterpreter 79 * 80 * PARAMETERS: None 81 * 82 * RETURN: None 83 * 84 * DESCRIPTION: Enter the interpreter execution region. Failure to enter 85 * the interpreter region is a fatal system error. Used in 86 * conjunction with ExitInterpreter. 87 * 88 ******************************************************************************/ 89 90 void 91 AcpiExEnterInterpreter ( 92 void) 93 { 94 ACPI_STATUS Status; 95 96 97 ACPI_FUNCTION_TRACE (ExEnterInterpreter); 98 99 100 Status = AcpiUtAcquireMutex (ACPI_MTX_INTERPRETER); 101 if (ACPI_FAILURE (Status)) 102 { 103 ACPI_ERROR ((AE_INFO, "Could not acquire AML Interpreter mutex")); 104 } 105 Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE); 106 if (ACPI_FAILURE (Status)) 107 { 108 ACPI_ERROR ((AE_INFO, "Could not acquire AML Namespace mutex")); 109 } 110 111 return_VOID; 112 } 113 114 115 /******************************************************************************* 116 * 117 * FUNCTION: AcpiExExitInterpreter 118 * 119 * PARAMETERS: None 120 * 121 * RETURN: None 122 * 123 * DESCRIPTION: Exit the interpreter execution region. This is the top level 124 * routine used to exit the interpreter when all processing has 125 * been completed, or when the method blocks. 126 * 127 * Cases where the interpreter is unlocked internally: 128 * 1) Method will be blocked on a Sleep() AML opcode 129 * 2) Method will be blocked on an Acquire() AML opcode 130 * 3) Method will be blocked on a Wait() AML opcode 131 * 4) Method will be blocked to acquire the global lock 132 * 5) Method will be blocked waiting to execute a serialized control 133 * method that is currently executing 134 * 6) About to invoke a user-installed opregion handler 135 * 136 ******************************************************************************/ 137 138 void 139 AcpiExExitInterpreter ( 140 void) 141 { 142 ACPI_STATUS Status; 143 144 145 ACPI_FUNCTION_TRACE (ExExitInterpreter); 146 147 148 Status = AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE); 149 if (ACPI_FAILURE (Status)) 150 { 151 ACPI_ERROR ((AE_INFO, "Could not release AML Namespace mutex")); 152 } 153 Status = AcpiUtReleaseMutex (ACPI_MTX_INTERPRETER); 154 if (ACPI_FAILURE (Status)) 155 { 156 ACPI_ERROR ((AE_INFO, "Could not release AML Interpreter mutex")); 157 } 158 159 return_VOID; 160 } 161 162 163 /******************************************************************************* 164 * 165 * FUNCTION: AcpiExTruncateFor32bitTable 166 * 167 * PARAMETERS: ObjDesc - Object to be truncated 168 * 169 * RETURN: TRUE if a truncation was performed, FALSE otherwise. 170 * 171 * DESCRIPTION: Truncate an ACPI Integer to 32 bits if the execution mode is 172 * 32-bit, as determined by the revision of the DSDT. 173 * 174 ******************************************************************************/ 175 176 BOOLEAN 177 AcpiExTruncateFor32bitTable ( 178 ACPI_OPERAND_OBJECT *ObjDesc) 179 { 180 181 ACPI_FUNCTION_ENTRY (); 182 183 184 /* 185 * Object must be a valid number and we must be executing 186 * a control method. Object could be NS node for AML_INT_NAMEPATH_OP. 187 */ 188 if ((!ObjDesc) || 189 (ACPI_GET_DESCRIPTOR_TYPE (ObjDesc) != ACPI_DESC_TYPE_OPERAND) || 190 (ObjDesc->Common.Type != ACPI_TYPE_INTEGER)) 191 { 192 return (FALSE); 193 } 194 195 if ((AcpiGbl_IntegerByteWidth == 4) && 196 (ObjDesc->Integer.Value > (UINT64) ACPI_UINT32_MAX)) 197 { 198 /* 199 * We are executing in a 32-bit ACPI table. Truncate 200 * the value to 32 bits by zeroing out the upper 32-bit field 201 */ 202 ObjDesc->Integer.Value &= (UINT64) ACPI_UINT32_MAX; 203 return (TRUE); 204 } 205 206 return (FALSE); 207 } 208 209 210 /******************************************************************************* 211 * 212 * FUNCTION: AcpiExAcquireGlobalLock 213 * 214 * PARAMETERS: FieldFlags - Flags with Lock rule: 215 * AlwaysLock or NeverLock 216 * 217 * RETURN: None 218 * 219 * DESCRIPTION: Obtain the ACPI hardware Global Lock, only if the field 220 * flags specify that it is to be obtained before field access. 221 * 222 ******************************************************************************/ 223 224 void 225 AcpiExAcquireGlobalLock ( 226 UINT32 FieldFlags) 227 { 228 ACPI_STATUS Status; 229 230 231 ACPI_FUNCTION_TRACE (ExAcquireGlobalLock); 232 233 234 /* Only use the lock if the AlwaysLock bit is set */ 235 236 if (!(FieldFlags & AML_FIELD_LOCK_RULE_MASK)) 237 { 238 return_VOID; 239 } 240 241 /* Attempt to get the global lock, wait forever */ 242 243 Status = AcpiExAcquireMutexObject (ACPI_WAIT_FOREVER, 244 AcpiGbl_GlobalLockMutex, AcpiOsGetThreadId ()); 245 246 if (ACPI_FAILURE (Status)) 247 { 248 ACPI_EXCEPTION ((AE_INFO, Status, 249 "Could not acquire Global Lock")); 250 } 251 252 return_VOID; 253 } 254 255 256 /******************************************************************************* 257 * 258 * FUNCTION: AcpiExReleaseGlobalLock 259 * 260 * PARAMETERS: FieldFlags - Flags with Lock rule: 261 * AlwaysLock or NeverLock 262 * 263 * RETURN: None 264 * 265 * DESCRIPTION: Release the ACPI hardware Global Lock 266 * 267 ******************************************************************************/ 268 269 void 270 AcpiExReleaseGlobalLock ( 271 UINT32 FieldFlags) 272 { 273 ACPI_STATUS Status; 274 275 276 ACPI_FUNCTION_TRACE (ExReleaseGlobalLock); 277 278 279 /* Only use the lock if the AlwaysLock bit is set */ 280 281 if (!(FieldFlags & AML_FIELD_LOCK_RULE_MASK)) 282 { 283 return_VOID; 284 } 285 286 /* Release the global lock */ 287 288 Status = AcpiExReleaseMutexObject (AcpiGbl_GlobalLockMutex); 289 if (ACPI_FAILURE (Status)) 290 { 291 /* Report the error, but there isn't much else we can do */ 292 293 ACPI_EXCEPTION ((AE_INFO, Status, 294 "Could not release Global Lock")); 295 } 296 297 return_VOID; 298 } 299 300 301 /******************************************************************************* 302 * 303 * FUNCTION: AcpiExDigitsNeeded 304 * 305 * PARAMETERS: Value - Value to be represented 306 * Base - Base of representation 307 * 308 * RETURN: The number of digits. 309 * 310 * DESCRIPTION: Calculate the number of digits needed to represent the Value 311 * in the given Base (Radix) 312 * 313 ******************************************************************************/ 314 315 static UINT32 316 AcpiExDigitsNeeded ( 317 UINT64 Value, 318 UINT32 Base) 319 { 320 UINT32 NumDigits; 321 UINT64 CurrentValue; 322 323 324 ACPI_FUNCTION_TRACE (ExDigitsNeeded); 325 326 327 /* UINT64 is unsigned, so we don't worry about a '-' prefix */ 328 329 if (Value == 0) 330 { 331 return_UINT32 (1); 332 } 333 334 CurrentValue = Value; 335 NumDigits = 0; 336 337 /* Count the digits in the requested base */ 338 339 while (CurrentValue) 340 { 341 (void) AcpiUtShortDivide (CurrentValue, Base, &CurrentValue, NULL); 342 NumDigits++; 343 } 344 345 return_UINT32 (NumDigits); 346 } 347 348 349 /******************************************************************************* 350 * 351 * FUNCTION: AcpiExEisaIdToString 352 * 353 * PARAMETERS: OutString - Where to put the converted string (8 bytes) 354 * CompressedId - EISAID to be converted 355 * 356 * RETURN: None 357 * 358 * DESCRIPTION: Convert a numeric EISAID to string representation. Return 359 * buffer must be large enough to hold the string. The string 360 * returned is always exactly of length ACPI_EISAID_STRING_SIZE 361 * (includes null terminator). The EISAID is always 32 bits. 362 * 363 ******************************************************************************/ 364 365 void 366 AcpiExEisaIdToString ( 367 char *OutString, 368 UINT64 CompressedId) 369 { 370 UINT32 SwappedId; 371 372 373 ACPI_FUNCTION_ENTRY (); 374 375 376 /* The EISAID should be a 32-bit integer */ 377 378 if (CompressedId > ACPI_UINT32_MAX) 379 { 380 ACPI_WARNING ((AE_INFO, 381 "Expected EISAID is larger than 32 bits: " 382 "0x%8.8X%8.8X, truncating", 383 ACPI_FORMAT_UINT64 (CompressedId))); 384 } 385 386 /* Swap ID to big-endian to get contiguous bits */ 387 388 SwappedId = AcpiUtDwordByteSwap ((UINT32) CompressedId); 389 390 /* First 3 bytes are uppercase letters. Next 4 bytes are hexadecimal */ 391 392 OutString[0] = (char) (0x40 + (((unsigned long) SwappedId >> 26) & 0x1F)); 393 OutString[1] = (char) (0x40 + ((SwappedId >> 21) & 0x1F)); 394 OutString[2] = (char) (0x40 + ((SwappedId >> 16) & 0x1F)); 395 OutString[3] = AcpiUtHexToAsciiChar ((UINT64) SwappedId, 12); 396 OutString[4] = AcpiUtHexToAsciiChar ((UINT64) SwappedId, 8); 397 OutString[5] = AcpiUtHexToAsciiChar ((UINT64) SwappedId, 4); 398 OutString[6] = AcpiUtHexToAsciiChar ((UINT64) SwappedId, 0); 399 OutString[7] = 0; 400 } 401 402 403 /******************************************************************************* 404 * 405 * FUNCTION: AcpiExIntegerToString 406 * 407 * PARAMETERS: OutString - Where to put the converted string. At least 408 * 21 bytes are needed to hold the largest 409 * possible 64-bit integer. 410 * Value - Value to be converted 411 * 412 * RETURN: Converted string in OutString 413 * 414 * DESCRIPTION: Convert a 64-bit integer to decimal string representation. 415 * Assumes string buffer is large enough to hold the string. The 416 * largest string is (ACPI_MAX64_DECIMAL_DIGITS + 1). 417 * 418 ******************************************************************************/ 419 420 void 421 AcpiExIntegerToString ( 422 char *OutString, 423 UINT64 Value) 424 { 425 UINT32 Count; 426 UINT32 DigitsNeeded; 427 UINT32 Remainder; 428 429 430 ACPI_FUNCTION_ENTRY (); 431 432 433 DigitsNeeded = AcpiExDigitsNeeded (Value, 10); 434 OutString[DigitsNeeded] = 0; 435 436 for (Count = DigitsNeeded; Count > 0; Count--) 437 { 438 (void) AcpiUtShortDivide (Value, 10, &Value, &Remainder); 439 OutString[Count-1] = (char) ('0' + Remainder);\ 440 } 441 } 442 443 444 /******************************************************************************* 445 * 446 * FUNCTION: AcpiExPciClsToString 447 * 448 * PARAMETERS: OutString - Where to put the converted string (7 bytes) 449 * ClassCode - PCI class code to be converted (3 bytes) 450 * 451 * RETURN: Converted string in OutString 452 * 453 * DESCRIPTION: Convert 3-bytes PCI class code to string representation. 454 * Return buffer must be large enough to hold the string. The 455 * string returned is always exactly of length 456 * ACPI_PCICLS_STRING_SIZE (includes null terminator). 457 * 458 ******************************************************************************/ 459 460 void 461 AcpiExPciClsToString ( 462 char *OutString, 463 UINT8 ClassCode[3]) 464 { 465 466 ACPI_FUNCTION_ENTRY (); 467 468 469 /* All 3 bytes are hexadecimal */ 470 471 OutString[0] = AcpiUtHexToAsciiChar ((UINT64) ClassCode[0], 4); 472 OutString[1] = AcpiUtHexToAsciiChar ((UINT64) ClassCode[0], 0); 473 OutString[2] = AcpiUtHexToAsciiChar ((UINT64) ClassCode[1], 4); 474 OutString[3] = AcpiUtHexToAsciiChar ((UINT64) ClassCode[1], 0); 475 OutString[4] = AcpiUtHexToAsciiChar ((UINT64) ClassCode[2], 4); 476 OutString[5] = AcpiUtHexToAsciiChar ((UINT64) ClassCode[2], 0); 477 OutString[6] = 0; 478 } 479 480 481 /******************************************************************************* 482 * 483 * FUNCTION: AcpiIsValidSpaceId 484 * 485 * PARAMETERS: SpaceId - ID to be validated 486 * 487 * RETURN: TRUE if SpaceId is a valid/supported ID. 488 * 489 * DESCRIPTION: Validate an operation region SpaceID. 490 * 491 ******************************************************************************/ 492 493 BOOLEAN 494 AcpiIsValidSpaceId ( 495 UINT8 SpaceId) 496 { 497 498 if ((SpaceId >= ACPI_NUM_PREDEFINED_REGIONS) && 499 (SpaceId < ACPI_USER_REGION_BEGIN) && 500 (SpaceId != ACPI_ADR_SPACE_DATA_TABLE) && 501 (SpaceId != ACPI_ADR_SPACE_FIXED_HARDWARE)) 502 { 503 return (FALSE); 504 } 505 506 return (TRUE); 507 } 508