// TITLE("Fast Mutex Support") //++ // // Module Name: // // fmutex.s // // Abstract: // // This module implements the code necessary to acquire and release fast // mutxes. // // // Author: // // William K. Cheung (wcheung) 02-Oct-1995 // // Environment: // // Kernel mode only. // // Revision History: // // 08-Feb-96 Updated to EAS2.1 // //-- #include "ksia64.h" .file "fmutex.s" PublicFunction(KeWaitForSingleObject) PublicFunction(KeSetEventBoostPriority) PublicFunction(KiCheckForSoftwareInterrupt) //++ // // VOID // ExAcquireFastMutex ( // IN PFAST_MUTEX FastMutex // ) // // Routine Description: // // This function acquires ownership of a fast mutex and raises IRQL to // APC Level. Must be called at IRQL < DISPATCH_LEVEL. // // Arguments: // // FastMutex (a0) - Supplies a pointer to a fast mutex. // // Return Value: // // None. // //-- // // t0 -- Original value of Fmutex.FmCount // t1 -- Address of Fmutex.FmCount // t2 -- Address of Fmutex.FmOldIrql // t3 -- Address of KiPcr // t4 -- Address of Fmutex.FmContention // t8 -- Address of KiPcr.PcCurrentThread // r35 -- old IRQL // // t5 -- temp // NESTED_ENTRY(ExAcquireFastMutex) .regstk 1, 4, 5, 0 .prologue 0xC, savedpfs alloc savedpfs = ar.pfs, 1, 4, 5, 0 add loc3 = FmOwner, a0 mov savedbrp = brp GET_IRQL (loc2) // Get old IRQL PROLOGUE_END mov t4 = APC_LEVEL add t1 = FmCount, a0 add t2 = FmOldIrql, a0 ;; SET_IRQL (t4) // change IRQL to APC_LEVEL ;; // // synchronize subsequent reads // fetchadd4.acq t0 = [t1], -1 // decrement mutex count add t4 = FmContention, a0 add out0 = FmEvent, a0 mov out1 = Executive // set reason for wait mov out2 = KernelMode // set mode of wait ;; cmp4.le pt7, pt8 = t0, zero // if le, mutex acq failed mov out3 = FALSE // set nonalertable wait mov out4 = zero // set NULL timeout pointer ;; (pt7) ld4 t5 = [t4] // load contention count (pt8) st8 [loc3] = sp // Save the SP so we can identify the owner. (pt8) st4 [t2] = loc2 // save old IRQL (pt8) br.ret.sptk.clr brp // return ;; Eafm10: (pt7) add t5 = 1, t5 // inc contention count ;; st4 [t4] = t5 // save contention count br.call.sptk.many brp = KeWaitForSingleObject add t2 = FmOldIrql, a0 mov ar.pfs = savedpfs // restore pfs mov brp = savedbrp // restore brp ;; st4 [t2] = loc2 // save old IRQL st8 [loc3] = sp // Save the SP so we can identify the owner. br.ret.sptk.clr brp // return NESTED_EXIT(ExAcquireFastMutex) //++ // // VOID // ExReleaseFastMutex ( // IN PFAST_MUTEX FastMutex // ) // // Routine Description: // // This function releases ownership to a fast mutex and lowers IRQL to // its previous level. // // Arguments: // // FastMutex (a0) - Supplies a pointer to a fast mutex. // // Return Value: // // None. // //-- NESTED_ENTRY(ExReleaseFastMutex) NESTED_SETUP(1, 3, 2, 0) add t1 = FmCount, a0 PROLOGUE_END // // Increment mutex count and release waiter if contention. // // // use release semantics to synchronize all previous writes // add t2 = FmOldIrql, a0 ;; ld4 loc2 = [t2] // get old IRQL before releasing lock fetchadd4.rel t9 = [t1], 1 // increment mutex count add out0 = FmEvent, a0 ;; cmp4.eq pt1, pt0 = zero, t9 // if eq, no waiter mov out1 = zero (pt0) br.call.spnt.many brp = KeSetEventBoostPriority ;; LOWER_IRQL (loc2) NESTED_RETURN NESTED_EXIT(ExReleaseFastMutex) //++ // // BOOLEAN // ExTryToAcquireFastMutex ( // IN PFAST_MUTEX FastMutex // ) // // Routine Description: // // This function attempts to acquire ownership of a fast mutex, and if // successful, raises IRQL to APC level. // // Arguments: // // FastMutex (a0) - Supplies a pointer to a fast mutex. // // Return Value: // // If the fast mutex was successfully acquired, then a value of TRUE // is returned as the function value. Otherwise, a valye of FALSE is // returned. // //-- LEAF_ENTRY(ExTryToAcquireFastMutex) mov t4 = APC_LEVEL add t1 = FmCount, a0 add t2 = FmOldIrql, a0 add t6 = FmOwner, a0 GET_IRQL (t0) // get old IRQL SET_IRQL (t4) // change IRQL to APC_LEVEL ;; ld4 t4 = [t1] ;; mov ar.ccv = t4 cmp4.le pt8, pt7 = t4, zero // if le, mutex acq failed add t5 = -1, t4 mov v0 = TRUE // return TRUE by default (pt8) br.spnt.few Ettafm10 ;; // // use acquire semantics to sychronize subsequent reads // cmpxchg4.acq t4 = [t1], t5, ar.ccv ;; cmp4.le pt8, pt7 = t4, zero // if le, mutex acq failed ;; Ettafm10: PSET_IRQL (pt8, t0) // restore IRQL (pt7) st4 [t2] = t0 // save old IRQL (pt8) mov v0 = FALSE // return FALSE (pt7) st8 [t6] = sp // Save the SP so we can identify the owner. br.ret.sptk.clr brp // return LEAF_EXIT(ExTryToAcquireFastMutex) //++ // // VOID // ExAcquireFastMutexUnsafe ( // IN PFAST_MUTEX FastMutex // ) // // Routine Description: // // This function acquires ownership of a fast mutex, but does not raise // IRQL to APC Level. // // Arguments: // // FastMutex (a0) - Supplies a pointer to a fast mutex. // // Return Value: // // None. // //-- NESTED_ENTRY(ExAcquireFastMutexUnsafe) NESTED_SETUP(1, 3, 5, 0) add t1 = FmCount, a0 ;; PROLOGUE_END // // Use acquire semantics to synchronize subsequent reads // fetchadd4.acq t0 = [t1], -1 // decrement mutex count add out0 = FmEvent, a0 add t3 = FmContention, a0 add loc2 = FmOwner, a0 mov out1 = Executive // set reason for wait mov out2 = KernelMode // set mode of wait ;; cmp4.le p0, pt8 = t0, zero // if le, contention mov out3 = FALSE // set nonalertable wait ;; (pt8) st8 [loc2] = sp // Save the SP so we can identify the owner. (pt8) br.ret.sptk.clr brp // return // // Increment the contention count and then call KeWaitForSingleObject(). // The outgoing arguments have been set up ahead of time. // ld4 t4 = [t3] // get contention count ;; add t4 = 1, t4 // increment contention count mov out4 = 0 // set NULL timeout pointer ;; st4 [t3] = t4 // save contention count br.call.sptk.many brp = KeWaitForSingleObject mov ar.pfs = savedpfs // restore pfs mov brp = savedbrp // restore return link st8 [loc2] = sp // Save the sp of the owner br.ret.sptk.clr brp // return NESTED_EXIT(ExAcquireFastMutexUnsafe) //++ // // VOID // ExReleaseFastMutexUnsafe ( // IN PFAST_MUTEX FastMutex // ) // // Routine Description: // // This function releases ownership to a fast mutex, and does not // restore IRQL to its previous level. // // Arguments: // // FastMutex (a0) - Supplies a pointer to a fast mutex. // // Return Value: // // None. // //-- NESTED_ENTRY(ExReleaseFastMutexUnsafe) NESTED_SETUP(1, 2, 2, 0) add t1 = FmCount, a0 ;; PROLOGUE_END // // Increment mutex count and release waiter if contention. // // // Use release semantics to syncrhonize all previous writes // before the mutext is released. // fetchadd4.rel t9 = [t1], 1 // increment mutex count ;; add out0 = FmEvent, a0 cmp4.eq pt7, pt8 = zero, t9 // if eq, no waiter add out1 = zero, zero (pt7) br.ret.sptk.clr brp // return (pt8) br.call.spnt.many brp = KeSetEventBoostPriority mov ar.pfs = savedpfs mov brp = savedbrp br.ret.sptk.clr brp // return NESTED_EXIT(ExReleaseFastMutexUnsafe) //++ // // BOOLEAN // ExTryToAcquireFastMutexUnsafe ( // IN PFAST_MUTEX FastMutex // ) // // Routine Description: // // This function attempts to acquire ownership of a fast mutex, and if // successful, does not raise IRQL to APC level. // // Arguments: // // FastMutex (a0) - Supplies a pointer to a fast mutex. // // Return Value: // // If the fast mutex was successfully acquired, then a value of TRUE // is returned as the function value. Otherwise, a valye of FALSE is // returned. // //-- #if 0 LEAF_ENTRY(ExTryToAcquireFastMutexUnsafe) LEAF_EXIT(ExTryToAcquireFastMutexUnsafe) #endif