1 
   2 /******************************************************************************
   3  *
   4  * Module Name: exutils - interpreter/scanner utilities
   5  *
   6  *****************************************************************************/
   7 
   8 /*
   9  * Copyright (C) 2000 - 2011, Intel Corp.
  10  * All rights reserved.
  11  *
  12  * Redistribution and use in source and binary forms, with or without
  13  * modification, are permitted provided that the following conditions
  14  * are met:
  15  * 1. Redistributions of source code must retain the above copyright
  16  *    notice, this list of conditions, and the following disclaimer,
  17  *    without modification.
  18  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
  19  *    substantially similar to the "NO WARRANTY" disclaimer below
  20  *    ("Disclaimer") and any redistribution must be conditioned upon
  21  *    including a substantially similar Disclaimer requirement for further
  22  *    binary redistribution.
  23  * 3. Neither the names of the above-listed copyright holders nor the names
  24  *    of any contributors may be used to endorse or promote products derived
  25  *    from this software without specific prior written permission.
  26  *
  27  * Alternatively, this software may be distributed under the terms of the
  28  * GNU General Public License ("GPL") version 2 as published by the Free
  29  * Software Foundation.
  30  *
  31  * NO WARRANTY
  32  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  33  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  34  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
  35  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  36  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  37  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  38  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  39  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  40  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
  41  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  42  * POSSIBILITY OF SUCH DAMAGES.
  43  */
  44 
  45 #define __EXUTILS_C__
  46 
  47 /*
  48  * DEFINE_AML_GLOBALS is tested in amlcode.h
  49  * to determine whether certain global names should be "defined" or only
  50  * "declared" in the current compilation.  This enhances maintainability
  51  * by enabling a single header file to embody all knowledge of the names
  52  * in question.
  53  *
  54  * Exactly one module of any executable should #define DEFINE_GLOBALS
  55  * before #including the header files which use this convention.  The
  56  * names in question will be defined and initialized in that module,
  57  * and declared as extern in all other modules which #include those
  58  * header files.
  59  */
  60 
  61 #define DEFINE_AML_GLOBALS
  62 
  63 #include "acpi.h"
  64 #include "accommon.h"
  65 #include "acinterp.h"
  66 #include "amlcode.h"
  67 
  68 #define _COMPONENT          ACPI_EXECUTER
  69         ACPI_MODULE_NAME    ("exutils")
  70 
  71 /* Local prototypes */
  72 
  73 static UINT32
  74 AcpiExDigitsNeeded (
  75     UINT64                  Value,
  76     UINT32                  Base);
  77 
  78 
  79 #ifndef ACPI_NO_METHOD_EXECUTION
  80 /*******************************************************************************
  81  *
  82  * FUNCTION:    AcpiExEnterInterpreter
  83  *
  84  * PARAMETERS:  None
  85  *
  86  * RETURN:      None
  87  *
  88  * DESCRIPTION: Enter the interpreter execution region. Failure to enter
  89  *              the interpreter region is a fatal system error. Used in
  90  *              conjunction with ExitInterpreter.
  91  *
  92  ******************************************************************************/
  93 
  94 void
  95 AcpiExEnterInterpreter (
  96     void)
  97 {
  98     ACPI_STATUS             Status;
  99 
 100 
 101     ACPI_FUNCTION_TRACE (ExEnterInterpreter);
 102 
 103 
 104     Status = AcpiUtAcquireMutex (ACPI_MTX_INTERPRETER);
 105     if (ACPI_FAILURE (Status))
 106     {
 107         ACPI_ERROR ((AE_INFO, "Could not acquire AML Interpreter mutex"));
 108     }
 109 
 110     return_VOID;
 111 }
 112 
 113 
 114 /*******************************************************************************
 115  *
 116  * FUNCTION:    AcpiExReacquireInterpreter
 117  *
 118  * PARAMETERS:  None
 119  *
 120  * RETURN:      None
 121  *
 122  * DESCRIPTION: Reacquire the interpreter execution region from within the
 123  *              interpreter code. Failure to enter the interpreter region is a
 124  *              fatal system error. Used in  conjuction with
 125  *              RelinquishInterpreter
 126  *
 127  ******************************************************************************/
 128 
 129 void
 130 AcpiExReacquireInterpreter (
 131     void)
 132 {
 133     ACPI_FUNCTION_TRACE (ExReacquireInterpreter);
 134 
 135 
 136     /*
 137      * If the global serialized flag is set, do not release the interpreter,
 138      * since it was not actually released by AcpiExRelinquishInterpreter.
 139      * This forces the interpreter to be single threaded.
 140      */
 141     if (!AcpiGbl_AllMethodsSerialized)
 142     {
 143         AcpiExEnterInterpreter ();
 144     }
 145 
 146     return_VOID;
 147 }
 148 
 149 
 150 /*******************************************************************************
 151  *
 152  * FUNCTION:    AcpiExExitInterpreter
 153  *
 154  * PARAMETERS:  None
 155  *
 156  * RETURN:      None
 157  *
 158  * DESCRIPTION: Exit the interpreter execution region. This is the top level
 159  *              routine used to exit the interpreter when all processing has
 160  *              been completed.
 161  *
 162  ******************************************************************************/
 163 
 164 void
 165 AcpiExExitInterpreter (
 166     void)
 167 {
 168     ACPI_STATUS             Status;
 169 
 170 
 171     ACPI_FUNCTION_TRACE (ExExitInterpreter);
 172 
 173 
 174     Status = AcpiUtReleaseMutex (ACPI_MTX_INTERPRETER);
 175     if (ACPI_FAILURE (Status))
 176     {
 177         ACPI_ERROR ((AE_INFO, "Could not release AML Interpreter mutex"));
 178     }
 179 
 180     return_VOID;
 181 }
 182 
 183 
 184 /*******************************************************************************
 185  *
 186  * FUNCTION:    AcpiExRelinquishInterpreter
 187  *
 188  * PARAMETERS:  None
 189  *
 190  * RETURN:      None
 191  *
 192  * DESCRIPTION: Exit the interpreter execution region, from within the
 193  *              interpreter - before attempting an operation that will possibly
 194  *              block the running thread.
 195  *
 196  * Cases where the interpreter is unlocked internally
 197  *      1) Method to be blocked on a Sleep() AML opcode
 198  *      2) Method to be blocked on an Acquire() AML opcode
 199  *      3) Method to be blocked on a Wait() AML opcode
 200  *      4) Method to be blocked to acquire the global lock
 201  *      5) Method to be blocked waiting to execute a serialized control method
 202  *          that is currently executing
 203  *      6) About to invoke a user-installed opregion handler
 204  *
 205  ******************************************************************************/
 206 
 207 void
 208 AcpiExRelinquishInterpreter (
 209     void)
 210 {
 211     ACPI_FUNCTION_TRACE (ExRelinquishInterpreter);
 212 
 213 
 214     /*
 215      * If the global serialized flag is set, do not release the interpreter.
 216      * This forces the interpreter to be single threaded.
 217      */
 218     if (!AcpiGbl_AllMethodsSerialized)
 219     {
 220         AcpiExExitInterpreter ();
 221     }
 222 
 223     return_VOID;
 224 }
 225 
 226 
 227 /*******************************************************************************
 228  *
 229  * FUNCTION:    AcpiExTruncateFor32bitTable
 230  *
 231  * PARAMETERS:  ObjDesc         - Object to be truncated
 232  *
 233  * RETURN:      none
 234  *
 235  * DESCRIPTION: Truncate an ACPI Integer to 32 bits if the execution mode is
 236  *              32-bit, as determined by the revision of the DSDT.
 237  *
 238  ******************************************************************************/
 239 
 240 void
 241 AcpiExTruncateFor32bitTable (
 242     ACPI_OPERAND_OBJECT     *ObjDesc)
 243 {
 244 
 245     ACPI_FUNCTION_ENTRY ();
 246 
 247 
 248     /*
 249      * Object must be a valid number and we must be executing
 250      * a control method. NS node could be there for AML_INT_NAMEPATH_OP.
 251      */
 252     if ((!ObjDesc) ||
 253         (ACPI_GET_DESCRIPTOR_TYPE (ObjDesc) != ACPI_DESC_TYPE_OPERAND) ||
 254         (ObjDesc->Common.Type != ACPI_TYPE_INTEGER))
 255     {
 256         return;
 257     }
 258 
 259     if (AcpiGbl_IntegerByteWidth == 4)
 260     {
 261         /*
 262          * We are running a method that exists 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     }
 267 }
 268 
 269 
 270 /*******************************************************************************
 271  *
 272  * FUNCTION:    AcpiExAcquireGlobalLock
 273  *
 274  * PARAMETERS:  FieldFlags            - Flags with Lock rule:
 275  *                                      AlwaysLock or NeverLock
 276  *
 277  * RETURN:      None
 278  *
 279  * DESCRIPTION: Obtain the ACPI hardware Global Lock, only if the field
 280  *              flags specifiy that it is to be obtained before field access.
 281  *
 282  ******************************************************************************/
 283 
 284 void
 285 AcpiExAcquireGlobalLock (
 286     UINT32                  FieldFlags)
 287 {
 288     ACPI_STATUS             Status;
 289 
 290 
 291     ACPI_FUNCTION_TRACE (ExAcquireGlobalLock);
 292 
 293 
 294     /* Only use the lock if the AlwaysLock bit is set */
 295 
 296     if (!(FieldFlags & AML_FIELD_LOCK_RULE_MASK))
 297     {
 298         return_VOID;
 299     }
 300 
 301     /* Attempt to get the global lock, wait forever */
 302 
 303     Status = AcpiExAcquireMutexObject (ACPI_WAIT_FOREVER,
 304                 AcpiGbl_GlobalLockMutex, AcpiOsGetThreadId ());
 305 
 306     if (ACPI_FAILURE (Status))
 307     {
 308         ACPI_EXCEPTION ((AE_INFO, Status,
 309             "Could not acquire Global Lock"));
 310     }
 311 
 312     return_VOID;
 313 }
 314 
 315 
 316 /*******************************************************************************
 317  *
 318  * FUNCTION:    AcpiExReleaseGlobalLock
 319  *
 320  * PARAMETERS:  FieldFlags            - Flags with Lock rule:
 321  *                                      AlwaysLock or NeverLock
 322  *
 323  * RETURN:      None
 324  *
 325  * DESCRIPTION: Release the ACPI hardware Global Lock
 326  *
 327  ******************************************************************************/
 328 
 329 void
 330 AcpiExReleaseGlobalLock (
 331     UINT32                  FieldFlags)
 332 {
 333     ACPI_STATUS             Status;
 334 
 335 
 336     ACPI_FUNCTION_TRACE (ExReleaseGlobalLock);
 337 
 338 
 339     /* Only use the lock if the AlwaysLock bit is set */
 340 
 341     if (!(FieldFlags & AML_FIELD_LOCK_RULE_MASK))
 342     {
 343         return_VOID;
 344     }
 345 
 346     /* Release the global lock */
 347 
 348     Status = AcpiExReleaseMutexObject (AcpiGbl_GlobalLockMutex);
 349     if (ACPI_FAILURE (Status))
 350     {
 351         /* Report the error, but there isn't much else we can do */
 352 
 353         ACPI_EXCEPTION ((AE_INFO, Status,
 354             "Could not release Global Lock"));
 355     }
 356 
 357     return_VOID;
 358 }
 359 
 360 
 361 /*******************************************************************************
 362  *
 363  * FUNCTION:    AcpiExDigitsNeeded
 364  *
 365  * PARAMETERS:  Value           - Value to be represented
 366  *              Base            - Base of representation
 367  *
 368  * RETURN:      The number of digits.
 369  *
 370  * DESCRIPTION: Calculate the number of digits needed to represent the Value
 371  *              in the given Base (Radix)
 372  *
 373  ******************************************************************************/
 374 
 375 static UINT32
 376 AcpiExDigitsNeeded (
 377     UINT64                  Value,
 378     UINT32                  Base)
 379 {
 380     UINT32                  NumDigits;
 381     UINT64                  CurrentValue;
 382 
 383 
 384     ACPI_FUNCTION_TRACE (ExDigitsNeeded);
 385 
 386 
 387     /* UINT64 is unsigned, so we don't worry about a '-' prefix */
 388 
 389     if (Value == 0)
 390     {
 391         return_UINT32 (1);
 392     }
 393 
 394     CurrentValue = Value;
 395     NumDigits = 0;
 396 
 397     /* Count the digits in the requested base */
 398 
 399     while (CurrentValue)
 400     {
 401         (void) AcpiUtShortDivide (CurrentValue, Base, &CurrentValue, NULL);
 402         NumDigits++;
 403     }
 404 
 405     return_UINT32 (NumDigits);
 406 }
 407 
 408 
 409 /*******************************************************************************
 410  *
 411  * FUNCTION:    AcpiExEisaIdToString
 412  *
 413  * PARAMETERS:  CompressedId    - EISAID to be converted
 414  *              OutString       - Where to put the converted string (8 bytes)
 415  *
 416  * RETURN:      None
 417  *
 418  * DESCRIPTION: Convert a numeric EISAID to string representation. Return
 419  *              buffer must be large enough to hold the string. The string
 420  *              returned is always exactly of length ACPI_EISAID_STRING_SIZE
 421  *              (includes null terminator). The EISAID is always 32 bits.
 422  *
 423  ******************************************************************************/
 424 
 425 void
 426 AcpiExEisaIdToString (
 427     char                    *OutString,
 428     UINT64                  CompressedId)
 429 {
 430     UINT32                  SwappedId;
 431 
 432 
 433     ACPI_FUNCTION_ENTRY ();
 434 
 435 
 436     /* The EISAID should be a 32-bit integer */
 437 
 438     if (CompressedId > ACPI_UINT32_MAX)
 439     {
 440         ACPI_WARNING ((AE_INFO,
 441             "Expected EISAID is larger than 32 bits: 0x%8.8X%8.8X, truncating",
 442             ACPI_FORMAT_UINT64 (CompressedId)));
 443     }
 444 
 445     /* Swap ID to big-endian to get contiguous bits */
 446 
 447     SwappedId = AcpiUtDwordByteSwap ((UINT32) CompressedId);
 448 
 449     /* First 3 bytes are uppercase letters. Next 4 bytes are hexadecimal */
 450 
 451     OutString[0] = (char) (0x40 + (((unsigned long) SwappedId >> 26) & 0x1F));
 452     OutString[1] = (char) (0x40 + ((SwappedId >> 21) & 0x1F));
 453     OutString[2] = (char) (0x40 + ((SwappedId >> 16) & 0x1F));
 454     OutString[3] = AcpiUtHexToAsciiChar ((UINT64) SwappedId, 12);
 455     OutString[4] = AcpiUtHexToAsciiChar ((UINT64) SwappedId, 8);
 456     OutString[5] = AcpiUtHexToAsciiChar ((UINT64) SwappedId, 4);
 457     OutString[6] = AcpiUtHexToAsciiChar ((UINT64) SwappedId, 0);
 458     OutString[7] = 0;
 459 }
 460 
 461 
 462 /*******************************************************************************
 463  *
 464  * FUNCTION:    AcpiExIntegerToString
 465  *
 466  * PARAMETERS:  OutString       - Where to put the converted string. At least
 467  *                                21 bytes are needed to hold the largest
 468  *                                possible 64-bit integer.
 469  *              Value           - Value to be converted
 470  *
 471  * RETURN:      None, string
 472  *
 473  * DESCRIPTION: Convert a 64-bit integer to decimal string representation.
 474  *              Assumes string buffer is large enough to hold the string. The
 475  *              largest string is (ACPI_MAX64_DECIMAL_DIGITS + 1).
 476  *
 477  ******************************************************************************/
 478 
 479 void
 480 AcpiExIntegerToString (
 481     char                    *OutString,
 482     UINT64                  Value)
 483 {
 484     UINT32                  Count;
 485     UINT32                  DigitsNeeded;
 486     UINT32                  Remainder;
 487 
 488 
 489     ACPI_FUNCTION_ENTRY ();
 490 
 491 
 492     DigitsNeeded = AcpiExDigitsNeeded (Value, 10);
 493     OutString[DigitsNeeded] = 0;
 494 
 495     for (Count = DigitsNeeded; Count > 0; Count--)
 496     {
 497         (void) AcpiUtShortDivide (Value, 10, &Value, &Remainder);
 498         OutString[Count-1] = (char) ('0' + Remainder);\
 499     }
 500 }
 501 
 502 #endif