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