1 /******************************************************************************
   2  *
   3  * Module Name: exmutex - ASL Mutex Acquire/Release functions
   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 __EXMUTEX_C__
  45 
  46 #include "acpi.h"
  47 #include "accommon.h"
  48 #include "acinterp.h"
  49 #include "acevents.h"
  50 
  51 #define _COMPONENT          ACPI_EXECUTER
  52         ACPI_MODULE_NAME    ("exmutex")
  53 
  54 /* Local prototypes */
  55 
  56 static void
  57 AcpiExLinkMutex (
  58     ACPI_OPERAND_OBJECT     *ObjDesc,
  59     ACPI_THREAD_STATE       *Thread);
  60 
  61 
  62 /*******************************************************************************
  63  *
  64  * FUNCTION:    AcpiExUnlinkMutex
  65  *
  66  * PARAMETERS:  ObjDesc             - The mutex to be unlinked
  67  *
  68  * RETURN:      None
  69  *
  70  * DESCRIPTION: Remove a mutex from the "AcquiredMutex" list
  71  *
  72  ******************************************************************************/
  73 
  74 void
  75 AcpiExUnlinkMutex (
  76     ACPI_OPERAND_OBJECT     *ObjDesc)
  77 {
  78     ACPI_THREAD_STATE       *Thread = ObjDesc->Mutex.OwnerThread;
  79 
  80 
  81     if (!Thread)
  82     {
  83         return;
  84     }
  85 
  86     /* Doubly linked list */
  87 
  88     if (ObjDesc->Mutex.Next)
  89     {
  90         (ObjDesc->Mutex.Next)->Mutex.Prev = ObjDesc->Mutex.Prev;
  91     }
  92 
  93     if (ObjDesc->Mutex.Prev)
  94     {
  95         (ObjDesc->Mutex.Prev)->Mutex.Next = ObjDesc->Mutex.Next;
  96 
  97         /*
  98          * Migrate the previous sync level associated with this mutex to
  99          * the previous mutex on the list so that it may be preserved.
 100          * This handles the case where several mutexes have been acquired
 101          * at the same level, but are not released in opposite order.
 102          */
 103         (ObjDesc->Mutex.Prev)->Mutex.OriginalSyncLevel =
 104             ObjDesc->Mutex.OriginalSyncLevel;
 105     }
 106     else
 107     {
 108         Thread->AcquiredMutexList = ObjDesc->Mutex.Next;
 109     }
 110 }
 111 
 112 
 113 /*******************************************************************************
 114  *
 115  * FUNCTION:    AcpiExLinkMutex
 116  *
 117  * PARAMETERS:  ObjDesc             - The mutex to be linked
 118  *              Thread              - Current executing thread object
 119  *
 120  * RETURN:      None
 121  *
 122  * DESCRIPTION: Add a mutex to the "AcquiredMutex" list for this walk
 123  *
 124  ******************************************************************************/
 125 
 126 static void
 127 AcpiExLinkMutex (
 128     ACPI_OPERAND_OBJECT     *ObjDesc,
 129     ACPI_THREAD_STATE       *Thread)
 130 {
 131     ACPI_OPERAND_OBJECT     *ListHead;
 132 
 133 
 134     ListHead = Thread->AcquiredMutexList;
 135 
 136     /* This object will be the first object in the list */
 137 
 138     ObjDesc->Mutex.Prev = NULL;
 139     ObjDesc->Mutex.Next = ListHead;
 140 
 141     /* Update old first object to point back to this object */
 142 
 143     if (ListHead)
 144     {
 145         ListHead->Mutex.Prev = ObjDesc;
 146     }
 147 
 148     /* Update list head */
 149 
 150     Thread->AcquiredMutexList = ObjDesc;
 151 }
 152 
 153 
 154 /*******************************************************************************
 155  *
 156  * FUNCTION:    AcpiExAcquireMutexObject
 157  *
 158  * PARAMETERS:  Timeout             - Timeout in milliseconds
 159  *              ObjDesc             - Mutex object
 160  *              ThreadId            - Current thread state
 161  *
 162  * RETURN:      Status
 163  *
 164  * DESCRIPTION: Acquire an AML mutex, low-level interface. Provides a common
 165  *              path that supports multiple acquires by the same thread.
 166  *
 167  * MUTEX:       Interpreter must be locked
 168  *
 169  * NOTE: This interface is called from three places:
 170  * 1) From AcpiExAcquireMutex, via an AML Acquire() operator
 171  * 2) From AcpiExAcquireGlobalLock when an AML Field access requires the
 172  *    global lock
 173  * 3) From the external interface, AcpiAcquireGlobalLock
 174  *
 175  ******************************************************************************/
 176 
 177 ACPI_STATUS
 178 AcpiExAcquireMutexObject (
 179     UINT16                  Timeout,
 180     ACPI_OPERAND_OBJECT     *ObjDesc,
 181     ACPI_THREAD_ID          ThreadId)
 182 {
 183     ACPI_STATUS             Status;
 184 
 185 
 186     ACPI_FUNCTION_TRACE_PTR (ExAcquireMutexObject, ObjDesc);
 187 
 188 
 189     if (!ObjDesc)
 190     {
 191         return_ACPI_STATUS (AE_BAD_PARAMETER);
 192     }
 193 
 194     /* Support for multiple acquires by the owning thread */
 195 
 196     if (ObjDesc->Mutex.ThreadId == ThreadId)
 197     {
 198         /*
 199          * The mutex is already owned by this thread, just increment the
 200          * acquisition depth
 201          */
 202         ObjDesc->Mutex.AcquisitionDepth++;
 203         return_ACPI_STATUS (AE_OK);
 204     }
 205 
 206     /* Acquire the mutex, wait if necessary. Special case for Global Lock */
 207 
 208     if (ObjDesc == AcpiGbl_GlobalLockMutex)
 209     {
 210         Status = AcpiEvAcquireGlobalLock (Timeout);
 211     }
 212     else
 213     {
 214         Status = AcpiExSystemWaitMutex (ObjDesc->Mutex.OsMutex,
 215                     Timeout);
 216     }
 217 
 218     if (ACPI_FAILURE (Status))
 219     {
 220         /* Includes failure from a timeout on TimeDesc */
 221 
 222         return_ACPI_STATUS (Status);
 223     }
 224 
 225     /* Acquired the mutex: update mutex object */
 226 
 227     ObjDesc->Mutex.ThreadId = ThreadId;
 228     ObjDesc->Mutex.AcquisitionDepth = 1;
 229     ObjDesc->Mutex.OriginalSyncLevel = 0;
 230     ObjDesc->Mutex.OwnerThread = NULL;      /* Used only for AML Acquire() */
 231 
 232     return_ACPI_STATUS (AE_OK);
 233 }
 234 
 235 
 236 /*******************************************************************************
 237  *
 238  * FUNCTION:    AcpiExAcquireMutex
 239  *
 240  * PARAMETERS:  TimeDesc            - Timeout integer
 241  *              ObjDesc             - Mutex object
 242  *              WalkState           - Current method execution state
 243  *
 244  * RETURN:      Status
 245  *
 246  * DESCRIPTION: Acquire an AML mutex
 247  *
 248  ******************************************************************************/
 249 
 250 ACPI_STATUS
 251 AcpiExAcquireMutex (
 252     ACPI_OPERAND_OBJECT     *TimeDesc,
 253     ACPI_OPERAND_OBJECT     *ObjDesc,
 254     ACPI_WALK_STATE         *WalkState)
 255 {
 256     ACPI_STATUS             Status;
 257 
 258 
 259     ACPI_FUNCTION_TRACE_PTR (ExAcquireMutex, ObjDesc);
 260 
 261 
 262     if (!ObjDesc)
 263     {
 264         return_ACPI_STATUS (AE_BAD_PARAMETER);
 265     }
 266 
 267     /* Must have a valid thread state struct */
 268 
 269     if (!WalkState->Thread)
 270     {
 271         ACPI_ERROR ((AE_INFO,
 272             "Cannot acquire Mutex [%4.4s], null thread info",
 273             AcpiUtGetNodeName (ObjDesc->Mutex.Node)));
 274         return_ACPI_STATUS (AE_AML_INTERNAL);
 275     }
 276 
 277     /*
 278      * Current sync level must be less than or equal to the sync level of the
 279      * mutex. This mechanism provides some deadlock prevention
 280      */
 281     if (WalkState->Thread->CurrentSyncLevel > ObjDesc->Mutex.SyncLevel)
 282     {
 283         ACPI_ERROR ((AE_INFO,
 284             "Cannot acquire Mutex [%4.4s], current SyncLevel is too large (%u)",
 285             AcpiUtGetNodeName (ObjDesc->Mutex.Node),
 286             WalkState->Thread->CurrentSyncLevel));
 287         return_ACPI_STATUS (AE_AML_MUTEX_ORDER);
 288     }
 289 
 290     Status = AcpiExAcquireMutexObject ((UINT16) TimeDesc->Integer.Value,
 291                 ObjDesc, WalkState->Thread->ThreadId);
 292     if (ACPI_SUCCESS (Status) && ObjDesc->Mutex.AcquisitionDepth == 1)
 293     {
 294         /* Save Thread object, original/current sync levels */
 295 
 296         ObjDesc->Mutex.OwnerThread = WalkState->Thread;
 297         ObjDesc->Mutex.OriginalSyncLevel = WalkState->Thread->CurrentSyncLevel;
 298         WalkState->Thread->CurrentSyncLevel = ObjDesc->Mutex.SyncLevel;
 299 
 300         /* Link the mutex to the current thread for force-unlock at method exit */
 301 
 302         AcpiExLinkMutex (ObjDesc, WalkState->Thread);
 303     }
 304 
 305     return_ACPI_STATUS (Status);
 306 }
 307 
 308 
 309 /*******************************************************************************
 310  *
 311  * FUNCTION:    AcpiExReleaseMutexObject
 312  *
 313  * PARAMETERS:  ObjDesc             - The object descriptor for this op
 314  *
 315  * RETURN:      Status
 316  *
 317  * DESCRIPTION: Release a previously acquired Mutex, low level interface.
 318  *              Provides a common path that supports multiple releases (after
 319  *              previous multiple acquires) by the same thread.
 320  *
 321  * MUTEX:       Interpreter must be locked
 322  *
 323  * NOTE: This interface is called from three places:
 324  * 1) From AcpiExReleaseMutex, via an AML Acquire() operator
 325  * 2) From AcpiExReleaseGlobalLock when an AML Field access requires the
 326  *    global lock
 327  * 3) From the external interface, AcpiReleaseGlobalLock
 328  *
 329  ******************************************************************************/
 330 
 331 ACPI_STATUS
 332 AcpiExReleaseMutexObject (
 333     ACPI_OPERAND_OBJECT     *ObjDesc)
 334 {
 335     ACPI_STATUS             Status = AE_OK;
 336 
 337 
 338     ACPI_FUNCTION_TRACE (ExReleaseMutexObject);
 339 
 340 
 341     if (ObjDesc->Mutex.AcquisitionDepth == 0)
 342     {
 343         return_ACPI_STATUS (AE_NOT_ACQUIRED);
 344     }
 345 
 346     /* Match multiple Acquires with multiple Releases */
 347 
 348     ObjDesc->Mutex.AcquisitionDepth--;
 349     if (ObjDesc->Mutex.AcquisitionDepth != 0)
 350     {
 351         /* Just decrement the depth and return */
 352 
 353         return_ACPI_STATUS (AE_OK);
 354     }
 355 
 356     if (ObjDesc->Mutex.OwnerThread)
 357     {
 358         /* Unlink the mutex from the owner's list */
 359 
 360         AcpiExUnlinkMutex (ObjDesc);
 361         ObjDesc->Mutex.OwnerThread = NULL;
 362     }
 363 
 364     /* Release the mutex, special case for Global Lock */
 365 
 366     if (ObjDesc == AcpiGbl_GlobalLockMutex)
 367     {
 368         Status = AcpiEvReleaseGlobalLock ();
 369     }
 370     else
 371     {
 372         AcpiOsReleaseMutex (ObjDesc->Mutex.OsMutex);
 373     }
 374 
 375     /* Clear mutex info */
 376 
 377     ObjDesc->Mutex.ThreadId = 0;
 378     return_ACPI_STATUS (Status);
 379 }
 380 
 381 
 382 /*******************************************************************************
 383  *
 384  * FUNCTION:    AcpiExReleaseMutex
 385  *
 386  * PARAMETERS:  ObjDesc             - The object descriptor for this op
 387  *              WalkState           - Current method execution state
 388  *
 389  * RETURN:      Status
 390  *
 391  * DESCRIPTION: Release a previously acquired Mutex.
 392  *
 393  ******************************************************************************/
 394 
 395 ACPI_STATUS
 396 AcpiExReleaseMutex (
 397     ACPI_OPERAND_OBJECT     *ObjDesc,
 398     ACPI_WALK_STATE         *WalkState)
 399 {
 400     ACPI_STATUS             Status = AE_OK;
 401     UINT8                   PreviousSyncLevel;
 402     ACPI_THREAD_STATE       *OwnerThread;
 403 
 404 
 405     ACPI_FUNCTION_TRACE (ExReleaseMutex);
 406 
 407 
 408     if (!ObjDesc)
 409     {
 410         return_ACPI_STATUS (AE_BAD_PARAMETER);
 411     }
 412 
 413     OwnerThread = ObjDesc->Mutex.OwnerThread;
 414 
 415     /* The mutex must have been previously acquired in order to release it */
 416 
 417     if (!OwnerThread)
 418     {
 419         ACPI_ERROR ((AE_INFO,
 420             "Cannot release Mutex [%4.4s], not acquired",
 421             AcpiUtGetNodeName (ObjDesc->Mutex.Node)));
 422         return_ACPI_STATUS (AE_AML_MUTEX_NOT_ACQUIRED);
 423     }
 424 
 425     /* Must have a valid thread ID */
 426 
 427     if (!WalkState->Thread)
 428     {
 429         ACPI_ERROR ((AE_INFO,
 430             "Cannot release Mutex [%4.4s], null thread info",
 431             AcpiUtGetNodeName (ObjDesc->Mutex.Node)));
 432         return_ACPI_STATUS (AE_AML_INTERNAL);
 433     }
 434 
 435     /*
 436      * The Mutex is owned, but this thread must be the owner.
 437      * Special case for Global Lock, any thread can release
 438      */
 439     if ((OwnerThread->ThreadId != WalkState->Thread->ThreadId) &&
 440         (ObjDesc != AcpiGbl_GlobalLockMutex))
 441     {
 442         ACPI_ERROR ((AE_INFO,
 443             "Thread %u cannot release Mutex [%4.4s] acquired by thread %u",
 444             (UINT32) WalkState->Thread->ThreadId,
 445             AcpiUtGetNodeName (ObjDesc->Mutex.Node),
 446             (UINT32) OwnerThread->ThreadId));
 447         return_ACPI_STATUS (AE_AML_NOT_OWNER);
 448     }
 449 
 450     /*
 451      * The sync level of the mutex must be equal to the current sync level. In
 452      * other words, the current level means that at least one mutex at that
 453      * level is currently being held. Attempting to release a mutex of a
 454      * different level can only mean that the mutex ordering rule is being
 455      * violated. This behavior is clarified in ACPI 4.0 specification.
 456      */
 457     if (ObjDesc->Mutex.SyncLevel != OwnerThread->CurrentSyncLevel)
 458     {
 459         ACPI_ERROR ((AE_INFO,
 460             "Cannot release Mutex [%4.4s], SyncLevel mismatch: mutex %u current %u",
 461             AcpiUtGetNodeName (ObjDesc->Mutex.Node),
 462             ObjDesc->Mutex.SyncLevel, WalkState->Thread->CurrentSyncLevel));
 463         return_ACPI_STATUS (AE_AML_MUTEX_ORDER);
 464     }
 465 
 466     /*
 467      * Get the previous SyncLevel from the head of the acquired mutex list.
 468      * This handles the case where several mutexes at the same level have been
 469      * acquired, but are not released in reverse order.
 470      */
 471     PreviousSyncLevel =
 472         OwnerThread->AcquiredMutexList->Mutex.OriginalSyncLevel;
 473 
 474     Status = AcpiExReleaseMutexObject (ObjDesc);
 475     if (ACPI_FAILURE (Status))
 476     {
 477         return_ACPI_STATUS (Status);
 478     }
 479 
 480     if (ObjDesc->Mutex.AcquisitionDepth == 0)
 481     {
 482         /* Restore the previous SyncLevel */
 483 
 484         OwnerThread->CurrentSyncLevel = PreviousSyncLevel;
 485     }
 486 
 487     return_ACPI_STATUS (Status);
 488 }
 489 
 490 
 491 /*******************************************************************************
 492  *
 493  * FUNCTION:    AcpiExReleaseAllMutexes
 494  *
 495  * PARAMETERS:  Thread              - Current executing thread object
 496  *
 497  * RETURN:      Status
 498  *
 499  * DESCRIPTION: Release all mutexes held by this thread
 500  *
 501  * NOTE: This function is called as the thread is exiting the interpreter.
 502  * Mutexes are not released when an individual control method is exited, but
 503  * only when the parent thread actually exits the interpreter. This allows one
 504  * method to acquire a mutex, and a different method to release it, as long as
 505  * this is performed underneath a single parent control method.
 506  *
 507  ******************************************************************************/
 508 
 509 void
 510 AcpiExReleaseAllMutexes (
 511     ACPI_THREAD_STATE       *Thread)
 512 {
 513     ACPI_OPERAND_OBJECT     *Next = Thread->AcquiredMutexList;
 514     ACPI_OPERAND_OBJECT     *ObjDesc;
 515 
 516 
 517     ACPI_FUNCTION_NAME (ExReleaseAllMutexes);
 518 
 519 
 520     /* Traverse the list of owned mutexes, releasing each one */
 521 
 522     while (Next)
 523     {
 524         ObjDesc = Next;
 525         Next = ObjDesc->Mutex.Next;
 526 
 527         ObjDesc->Mutex.Prev = NULL;
 528         ObjDesc->Mutex.Next = NULL;
 529         ObjDesc->Mutex.AcquisitionDepth = 0;
 530 
 531         ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
 532             "Force-releasing held mutex: %p\n", ObjDesc));
 533 
 534         /* Release the mutex, special case for Global Lock */
 535 
 536         if (ObjDesc == AcpiGbl_GlobalLockMutex)
 537         {
 538             /* Ignore errors */
 539 
 540             (void) AcpiEvReleaseGlobalLock ();
 541         }
 542         else
 543         {
 544             AcpiOsReleaseMutex (ObjDesc->Mutex.OsMutex);
 545         }
 546 
 547         /* Mark mutex unowned */
 548 
 549         ObjDesc->Mutex.OwnerThread = NULL;
 550         ObjDesc->Mutex.ThreadId = 0;
 551 
 552         /* Update Thread SyncLevel (Last mutex is the important one) */
 553 
 554         Thread->CurrentSyncLevel = ObjDesc->Mutex.OriginalSyncLevel;
 555     }
 556 }