Path: blob/main/sys/contrib/dev/acpica/components/executer/exmutex.c
48521 views
/******************************************************************************1*2* Module Name: exmutex - ASL Mutex Acquire/Release functions3*4*****************************************************************************/56/******************************************************************************7*8* 1. Copyright Notice9*10* Some or all of this work - Copyright (c) 1999 - 2025, Intel Corp.11* All rights reserved.12*13* 2. License14*15* 2.1. This is your license from Intel Corp. under its intellectual property16* rights. You may have additional license terms from the party that provided17* you this software, covering your right to use that party's intellectual18* property rights.19*20* 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a21* copy of the source code appearing in this file ("Covered Code") an22* irrevocable, perpetual, worldwide license under Intel's copyrights in the23* base code distributed originally by Intel ("Original Intel Code") to copy,24* make derivatives, distribute, use and display any portion of the Covered25* Code in any form, with the right to sublicense such rights; and26*27* 2.3. Intel grants Licensee a non-exclusive and non-transferable patent28* license (with the right to sublicense), under only those claims of Intel29* patents that are infringed by the Original Intel Code, to make, use, sell,30* offer to sell, and import the Covered Code and derivative works thereof31* solely to the minimum extent necessary to exercise the above copyright32* license, and in no event shall the patent license extend to any additions33* to or modifications of the Original Intel Code. No other license or right34* is granted directly or by implication, estoppel or otherwise;35*36* The above copyright and patent license is granted only if the following37* conditions are met:38*39* 3. Conditions40*41* 3.1. Redistribution of Source with Rights to Further Distribute Source.42* Redistribution of source code of any substantial portion of the Covered43* Code or modification with rights to further distribute source must include44* the above Copyright Notice, the above License, this list of Conditions,45* and the following Disclaimer and Export Compliance provision. In addition,46* Licensee must cause all Covered Code to which Licensee contributes to47* contain a file documenting the changes Licensee made to create that Covered48* Code and the date of any change. Licensee must include in that file the49* documentation of any changes made by any predecessor Licensee. Licensee50* must include a prominent statement that the modification is derived,51* directly or indirectly, from Original Intel Code.52*53* 3.2. Redistribution of Source with no Rights to Further Distribute Source.54* Redistribution of source code of any substantial portion of the Covered55* Code or modification without rights to further distribute source must56* include the following Disclaimer and Export Compliance provision in the57* documentation and/or other materials provided with distribution. In58* addition, Licensee may not authorize further sublicense of source of any59* portion of the Covered Code, and must include terms to the effect that the60* license from Licensee to its licensee is limited to the intellectual61* property embodied in the software Licensee provides to its licensee, and62* not to intellectual property embodied in modifications its licensee may63* make.64*65* 3.3. Redistribution of Executable. Redistribution in executable form of any66* substantial portion of the Covered Code or modification must reproduce the67* above Copyright Notice, and the following Disclaimer and Export Compliance68* provision in the documentation and/or other materials provided with the69* distribution.70*71* 3.4. Intel retains all right, title, and interest in and to the Original72* Intel Code.73*74* 3.5. Neither the name Intel nor any other trademark owned or controlled by75* Intel shall be used in advertising or otherwise to promote the sale, use or76* other dealings in products derived from or relating to the Covered Code77* without prior written authorization from Intel.78*79* 4. Disclaimer and Export Compliance80*81* 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED82* HERE. ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE83* IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT, ASSISTANCE,84* INSTALLATION, TRAINING OR OTHER SERVICES. INTEL WILL NOT PROVIDE ANY85* UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY DISCLAIMS ANY86* IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A87* PARTICULAR PURPOSE.88*89* 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES90* OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR91* COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT,92* SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY93* CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL94* HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS95* SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY96* LIMITED REMEDY.97*98* 4.3. Licensee shall not export, either directly or indirectly, any of this99* software or system incorporating such software without first obtaining any100* required license or other approval from the U. S. Department of Commerce or101* any other agency or department of the United States Government. In the102* event Licensee exports any such software from the United States or103* re-exports any such software from a foreign destination, Licensee shall104* ensure that the distribution and export/re-export of the software is in105* compliance with all laws, regulations, orders, or other restrictions of the106* U.S. Export Administration Regulations. Licensee agrees that neither it nor107* any of its subsidiaries will export/re-export any technical data, process,108* software, or service, directly or indirectly, to any country for which the109* United States government or any agency thereof requires an export license,110* other governmental approval, or letter of assurance, without first obtaining111* such license, approval or letter.112*113*****************************************************************************114*115* Alternatively, you may choose to be licensed under the terms of the116* following license:117*118* Redistribution and use in source and binary forms, with or without119* modification, are permitted provided that the following conditions120* are met:121* 1. Redistributions of source code must retain the above copyright122* notice, this list of conditions, and the following disclaimer,123* without modification.124* 2. Redistributions in binary form must reproduce at minimum a disclaimer125* substantially similar to the "NO WARRANTY" disclaimer below126* ("Disclaimer") and any redistribution must be conditioned upon127* including a substantially similar Disclaimer requirement for further128* binary redistribution.129* 3. Neither the names of the above-listed copyright holders nor the names130* of any contributors may be used to endorse or promote products derived131* from this software without specific prior written permission.132*133* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS134* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT135* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR136* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT137* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,138* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT139* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,140* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY141* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT142* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE143* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.144*145* Alternatively, you may choose to be licensed under the terms of the146* GNU General Public License ("GPL") version 2 as published by the Free147* Software Foundation.148*149*****************************************************************************/150151#include <contrib/dev/acpica/include/acpi.h>152#include <contrib/dev/acpica/include/accommon.h>153#include <contrib/dev/acpica/include/acinterp.h>154#include <contrib/dev/acpica/include/acevents.h>155156#define _COMPONENT ACPI_EXECUTER157ACPI_MODULE_NAME ("exmutex")158159/* Local prototypes */160161static void162AcpiExLinkMutex (163ACPI_OPERAND_OBJECT *ObjDesc,164ACPI_THREAD_STATE *Thread);165166167/*******************************************************************************168*169* FUNCTION: AcpiExUnlinkMutex170*171* PARAMETERS: ObjDesc - The mutex to be unlinked172*173* RETURN: None174*175* DESCRIPTION: Remove a mutex from the "AcquiredMutex" list176*177******************************************************************************/178179void180AcpiExUnlinkMutex (181ACPI_OPERAND_OBJECT *ObjDesc)182{183ACPI_THREAD_STATE *Thread = ObjDesc->Mutex.OwnerThread;184185186if (!Thread)187{188return;189}190191/* Doubly linked list */192193if (ObjDesc->Mutex.Next)194{195(ObjDesc->Mutex.Next)->Mutex.Prev = ObjDesc->Mutex.Prev;196}197198if (ObjDesc->Mutex.Prev)199{200(ObjDesc->Mutex.Prev)->Mutex.Next = ObjDesc->Mutex.Next;201202/*203* Migrate the previous sync level associated with this mutex to204* the previous mutex on the list so that it may be preserved.205* This handles the case where several mutexes have been acquired206* at the same level, but are not released in opposite order.207*/208(ObjDesc->Mutex.Prev)->Mutex.OriginalSyncLevel =209ObjDesc->Mutex.OriginalSyncLevel;210}211else212{213Thread->AcquiredMutexList = ObjDesc->Mutex.Next;214}215}216217218/*******************************************************************************219*220* FUNCTION: AcpiExLinkMutex221*222* PARAMETERS: ObjDesc - The mutex to be linked223* Thread - Current executing thread object224*225* RETURN: None226*227* DESCRIPTION: Add a mutex to the "AcquiredMutex" list for this walk228*229******************************************************************************/230231static void232AcpiExLinkMutex (233ACPI_OPERAND_OBJECT *ObjDesc,234ACPI_THREAD_STATE *Thread)235{236ACPI_OPERAND_OBJECT *ListHead;237238239ListHead = Thread->AcquiredMutexList;240241/* This object will be the first object in the list */242243ObjDesc->Mutex.Prev = NULL;244ObjDesc->Mutex.Next = ListHead;245246/* Update old first object to point back to this object */247248if (ListHead)249{250ListHead->Mutex.Prev = ObjDesc;251}252253/* Update list head */254255Thread->AcquiredMutexList = ObjDesc;256}257258259/*******************************************************************************260*261* FUNCTION: AcpiExAcquireMutexObject262*263* PARAMETERS: Timeout - Timeout in milliseconds264* ObjDesc - Mutex object265* ThreadId - Current thread state266*267* RETURN: Status268*269* DESCRIPTION: Acquire an AML mutex, low-level interface. Provides a common270* path that supports multiple acquires by the same thread.271*272* MUTEX: Interpreter must be locked273*274* NOTE: This interface is called from three places:275* 1) From AcpiExAcquireMutex, via an AML Acquire() operator276* 2) From AcpiExAcquireGlobalLock when an AML Field access requires the277* global lock278* 3) From the external interface, AcpiAcquireGlobalLock279*280******************************************************************************/281282ACPI_STATUS283AcpiExAcquireMutexObject (284UINT16 Timeout,285ACPI_OPERAND_OBJECT *ObjDesc,286ACPI_THREAD_ID ThreadId)287{288ACPI_STATUS Status;289290291ACPI_FUNCTION_TRACE_PTR (ExAcquireMutexObject, ObjDesc);292293294if (!ObjDesc)295{296return_ACPI_STATUS (AE_BAD_PARAMETER);297}298299/* Support for multiple acquires by the owning thread */300301if (ObjDesc->Mutex.ThreadId == ThreadId)302{303/*304* The mutex is already owned by this thread, just increment the305* acquisition depth306*/307ObjDesc->Mutex.AcquisitionDepth++;308return_ACPI_STATUS (AE_OK);309}310311/* Acquire the mutex, wait if necessary. Special case for Global Lock */312313if (ObjDesc == AcpiGbl_GlobalLockMutex)314{315Status = AcpiEvAcquireGlobalLock (Timeout);316}317else318{319Status = AcpiExSystemWaitMutex (ObjDesc->Mutex.OsMutex, Timeout);320}321322if (ACPI_FAILURE (Status))323{324/* Includes failure from a timeout on TimeDesc */325326return_ACPI_STATUS (Status);327}328329/* Acquired the mutex: update mutex object */330331ObjDesc->Mutex.ThreadId = ThreadId;332ObjDesc->Mutex.AcquisitionDepth = 1;333ObjDesc->Mutex.OriginalSyncLevel = 0;334ObjDesc->Mutex.OwnerThread = NULL; /* Used only for AML Acquire() */335336return_ACPI_STATUS (AE_OK);337}338339340/*******************************************************************************341*342* FUNCTION: AcpiExAcquireMutex343*344* PARAMETERS: TimeDesc - Timeout integer345* ObjDesc - Mutex object346* WalkState - Current method execution state347*348* RETURN: Status349*350* DESCRIPTION: Acquire an AML mutex351*352******************************************************************************/353354ACPI_STATUS355AcpiExAcquireMutex (356ACPI_OPERAND_OBJECT *TimeDesc,357ACPI_OPERAND_OBJECT *ObjDesc,358ACPI_WALK_STATE *WalkState)359{360ACPI_STATUS Status;361362363ACPI_FUNCTION_TRACE_PTR (ExAcquireMutex, ObjDesc);364365366if (!ObjDesc)367{368return_ACPI_STATUS (AE_BAD_PARAMETER);369}370371/* Must have a valid thread state struct */372373if (!WalkState->Thread)374{375ACPI_ERROR ((AE_INFO,376"Cannot acquire Mutex [%4.4s], null thread info",377AcpiUtGetNodeName (ObjDesc->Mutex.Node)));378return_ACPI_STATUS (AE_AML_INTERNAL);379}380381/*382* Current sync level must be less than or equal to the sync level383* of the mutex. This mechanism provides some deadlock prevention.384*/385if (WalkState->Thread->CurrentSyncLevel > ObjDesc->Mutex.SyncLevel)386{387ACPI_ERROR ((AE_INFO,388"Cannot acquire Mutex [%4.4s], "389"current SyncLevel is too large (%u)",390AcpiUtGetNodeName (ObjDesc->Mutex.Node),391WalkState->Thread->CurrentSyncLevel));392return_ACPI_STATUS (AE_AML_MUTEX_ORDER);393}394395ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,396"Acquiring: Mutex SyncLevel %u, Thread SyncLevel %u, "397"Depth %u TID %p\n",398ObjDesc->Mutex.SyncLevel, WalkState->Thread->CurrentSyncLevel,399ObjDesc->Mutex.AcquisitionDepth, WalkState->Thread));400401Status = AcpiExAcquireMutexObject ((UINT16) TimeDesc->Integer.Value,402ObjDesc, WalkState->Thread->ThreadId);403404if (ACPI_SUCCESS (Status) && ObjDesc->Mutex.AcquisitionDepth == 1)405{406/* Save Thread object, original/current sync levels */407408ObjDesc->Mutex.OwnerThread = WalkState->Thread;409ObjDesc->Mutex.OriginalSyncLevel =410WalkState->Thread->CurrentSyncLevel;411WalkState->Thread->CurrentSyncLevel =412ObjDesc->Mutex.SyncLevel;413414/* Link the mutex to the current thread for force-unlock at method exit */415416AcpiExLinkMutex (ObjDesc, WalkState->Thread);417}418419ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,420"Acquired: Mutex SyncLevel %u, Thread SyncLevel %u, Depth %u\n",421ObjDesc->Mutex.SyncLevel, WalkState->Thread->CurrentSyncLevel,422ObjDesc->Mutex.AcquisitionDepth));423424return_ACPI_STATUS (Status);425}426427428/*******************************************************************************429*430* FUNCTION: AcpiExReleaseMutexObject431*432* PARAMETERS: ObjDesc - The object descriptor for this op433*434* RETURN: Status435*436* DESCRIPTION: Release a previously acquired Mutex, low level interface.437* Provides a common path that supports multiple releases (after438* previous multiple acquires) by the same thread.439*440* MUTEX: Interpreter must be locked441*442* NOTE: This interface is called from three places:443* 1) From AcpiExReleaseMutex, via an AML Acquire() operator444* 2) From AcpiExReleaseGlobalLock when an AML Field access requires the445* global lock446* 3) From the external interface, AcpiReleaseGlobalLock447*448******************************************************************************/449450ACPI_STATUS451AcpiExReleaseMutexObject (452ACPI_OPERAND_OBJECT *ObjDesc)453{454ACPI_STATUS Status = AE_OK;455456457ACPI_FUNCTION_TRACE (ExReleaseMutexObject);458459460if (ObjDesc->Mutex.AcquisitionDepth == 0)461{462return_ACPI_STATUS (AE_NOT_ACQUIRED);463}464465/* Match multiple Acquires with multiple Releases */466467ObjDesc->Mutex.AcquisitionDepth--;468if (ObjDesc->Mutex.AcquisitionDepth != 0)469{470/* Just decrement the depth and return */471472return_ACPI_STATUS (AE_OK);473}474475if (ObjDesc->Mutex.OwnerThread)476{477/* Unlink the mutex from the owner's list */478479AcpiExUnlinkMutex (ObjDesc);480ObjDesc->Mutex.OwnerThread = NULL;481}482483/* Release the mutex, special case for Global Lock */484485if (ObjDesc == AcpiGbl_GlobalLockMutex)486{487Status = AcpiEvReleaseGlobalLock ();488}489else490{491AcpiOsReleaseMutex (ObjDesc->Mutex.OsMutex);492}493494/* Clear mutex info */495496ObjDesc->Mutex.ThreadId = 0;497return_ACPI_STATUS (Status);498}499500501/*******************************************************************************502*503* FUNCTION: AcpiExReleaseMutex504*505* PARAMETERS: ObjDesc - The object descriptor for this op506* WalkState - Current method execution state507*508* RETURN: Status509*510* DESCRIPTION: Release a previously acquired Mutex.511*512******************************************************************************/513514ACPI_STATUS515AcpiExReleaseMutex (516ACPI_OPERAND_OBJECT *ObjDesc,517ACPI_WALK_STATE *WalkState)518{519UINT8 PreviousSyncLevel;520ACPI_THREAD_STATE *OwnerThread;521ACPI_STATUS Status = AE_OK;522523524ACPI_FUNCTION_TRACE (ExReleaseMutex);525526527if (!ObjDesc)528{529return_ACPI_STATUS (AE_BAD_PARAMETER);530}531532OwnerThread = ObjDesc->Mutex.OwnerThread;533534/* The mutex must have been previously acquired in order to release it */535536if (!OwnerThread)537{538ACPI_ERROR ((AE_INFO,539"Cannot release Mutex [%4.4s], not acquired",540AcpiUtGetNodeName (ObjDesc->Mutex.Node)));541return_ACPI_STATUS (AE_AML_MUTEX_NOT_ACQUIRED);542}543544/* Must have a valid thread ID */545546if (!WalkState->Thread)547{548ACPI_ERROR ((AE_INFO,549"Cannot release Mutex [%4.4s], null thread info",550AcpiUtGetNodeName (ObjDesc->Mutex.Node)));551return_ACPI_STATUS (AE_AML_INTERNAL);552}553554/*555* The Mutex is owned, but this thread must be the owner.556* Special case for Global Lock, any thread can release557*/558if ((OwnerThread->ThreadId != WalkState->Thread->ThreadId) &&559(ObjDesc != AcpiGbl_GlobalLockMutex))560{561ACPI_ERROR ((AE_INFO,562"Thread %u cannot release Mutex [%4.4s] acquired by thread %u",563(UINT32) WalkState->Thread->ThreadId,564AcpiUtGetNodeName (ObjDesc->Mutex.Node),565(UINT32) OwnerThread->ThreadId));566return_ACPI_STATUS (AE_AML_NOT_OWNER);567}568569/*570* The sync level of the mutex must be equal to the current sync level. In571* other words, the current level means that at least one mutex at that572* level is currently being held. Attempting to release a mutex of a573* different level can only mean that the mutex ordering rule is being574* violated. This behavior is clarified in ACPI 4.0 specification.575*/576if (ObjDesc->Mutex.SyncLevel != OwnerThread->CurrentSyncLevel)577{578ACPI_ERROR ((AE_INFO,579"Cannot release Mutex [%4.4s], SyncLevel mismatch: "580"mutex %u current %u",581AcpiUtGetNodeName (ObjDesc->Mutex.Node),582ObjDesc->Mutex.SyncLevel, WalkState->Thread->CurrentSyncLevel));583return_ACPI_STATUS (AE_AML_MUTEX_ORDER);584}585586/*587* Get the previous SyncLevel from the head of the acquired mutex list.588* This handles the case where several mutexes at the same level have been589* acquired, but are not released in reverse order.590*/591PreviousSyncLevel =592OwnerThread->AcquiredMutexList->Mutex.OriginalSyncLevel;593594ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,595"Releasing: Object SyncLevel %u, Thread SyncLevel %u, "596"Prev SyncLevel %u, Depth %u TID %p\n",597ObjDesc->Mutex.SyncLevel, WalkState->Thread->CurrentSyncLevel,598PreviousSyncLevel, ObjDesc->Mutex.AcquisitionDepth,599WalkState->Thread));600601Status = AcpiExReleaseMutexObject (ObjDesc);602if (ACPI_FAILURE (Status))603{604return_ACPI_STATUS (Status);605}606607if (ObjDesc->Mutex.AcquisitionDepth == 0)608{609/* Restore the previous SyncLevel */610611OwnerThread->CurrentSyncLevel = PreviousSyncLevel;612}613614ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,615"Released: Object SyncLevel %u, Thread SyncLevel, %u, "616"Prev SyncLevel %u, Depth %u\n",617ObjDesc->Mutex.SyncLevel, WalkState->Thread->CurrentSyncLevel,618PreviousSyncLevel, ObjDesc->Mutex.AcquisitionDepth));619620return_ACPI_STATUS (Status);621}622623624/*******************************************************************************625*626* FUNCTION: AcpiExReleaseAllMutexes627*628* PARAMETERS: Thread - Current executing thread object629*630* RETURN: Status631*632* DESCRIPTION: Release all mutexes held by this thread633*634* NOTE: This function is called as the thread is exiting the interpreter.635* Mutexes are not released when an individual control method is exited, but636* only when the parent thread actually exits the interpreter. This allows one637* method to acquire a mutex, and a different method to release it, as long as638* this is performed underneath a single parent control method.639*640******************************************************************************/641642void643AcpiExReleaseAllMutexes (644ACPI_THREAD_STATE *Thread)645{646ACPI_OPERAND_OBJECT *Next = Thread->AcquiredMutexList;647ACPI_OPERAND_OBJECT *ObjDesc;648649650ACPI_FUNCTION_TRACE (ExReleaseAllMutexes);651652653/* Traverse the list of owned mutexes, releasing each one */654655while (Next)656{657ObjDesc = Next;658ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,659"Mutex [%4.4s] force-release, SyncLevel %u Depth %u\n",660ObjDesc->Mutex.Node->Name.Ascii, ObjDesc->Mutex.SyncLevel,661ObjDesc->Mutex.AcquisitionDepth));662663/* Release the mutex, special case for Global Lock */664665if (ObjDesc == AcpiGbl_GlobalLockMutex)666{667/* Ignore errors */668669(void) AcpiEvReleaseGlobalLock ();670}671else672{673AcpiOsReleaseMutex (ObjDesc->Mutex.OsMutex);674}675676/* Update Thread SyncLevel (Last mutex is the important one) */677678Thread->CurrentSyncLevel = ObjDesc->Mutex.OriginalSyncLevel;679680/* Mark mutex unowned */681682Next = ObjDesc->Mutex.Next;683684ObjDesc->Mutex.Prev = NULL;685ObjDesc->Mutex.Next = NULL;686ObjDesc->Mutex.AcquisitionDepth = 0;687ObjDesc->Mutex.OwnerThread = NULL;688ObjDesc->Mutex.ThreadId = 0;689}690691return_VOID;692}693694695