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