[KMTESTS]

- Add KmtGetSystemRoutineAddress and use it to avoid importing functions that are not available in some versions of Windows. This allows running kmtests on Windows XP SP3 (and probably Server 2003 SP0/SP2). Note that failures on XP are still not valid bugs, this is purely for convenience!  Dedicated to Jérôme.
ROSTESTS-150

svn path=/trunk/; revision=66281
This commit is contained in:
Thomas Faber 2015-02-15 10:23:21 +00:00
parent af36a2a4df
commit e6c56afe8c
9 changed files with 440 additions and 138 deletions

View file

@ -132,6 +132,7 @@ VOID KmtSetIrql(IN KIRQL NewIrql);
BOOLEAN KmtAreInterruptsEnabled(VOID); BOOLEAN KmtAreInterruptsEnabled(VOID);
ULONG KmtGetPoolTag(PVOID Memory); ULONG KmtGetPoolTag(PVOID Memory);
USHORT KmtGetPoolType(PVOID Memory); USHORT KmtGetPoolType(PVOID Memory);
PVOID KmtGetSystemRoutineAddress(IN PCWSTR RoutineName);
PKTHREAD KmtStartThread(IN PKSTART_ROUTINE StartRoutine, IN PVOID StartContext OPTIONAL); PKTHREAD KmtStartThread(IN PKSTART_ROUTINE StartRoutine, IN PVOID StartContext OPTIONAL);
VOID KmtFinishThread(IN PKTHREAD Thread OPTIONAL, IN PKEVENT Event OPTIONAL); VOID KmtFinishThread(IN PKTHREAD Thread OPTIONAL, IN PKEVENT Event OPTIONAL);
#elif defined KMT_USER_MODE #elif defined KMT_USER_MODE

View file

@ -126,6 +126,13 @@ USHORT KmtGetPoolType(PVOID Memory)
return Header->PoolType; return Header->PoolType;
} }
PVOID KmtGetSystemRoutineAddress(IN PCWSTR RoutineName)
{
UNICODE_STRING RoutineNameString;
RtlInitUnicodeString(&RoutineNameString, (PWSTR)RoutineName);
return MmGetSystemRoutineAddress(&RoutineNameString);
}
PKTHREAD KmtStartThread(IN PKSTART_ROUTINE StartRoutine, IN PVOID StartContext OPTIONAL) PKTHREAD KmtStartThread(IN PKSTART_ROUTINE StartRoutine, IN PVOID StartContext OPTIONAL)
{ {
NTSTATUS Status; NTSTATUS Status;

View file

@ -94,7 +94,7 @@ const KMT_TEST TestList[] =
{ "KeIrql", Test_KeIrql }, { "KeIrql", Test_KeIrql },
{ "KeMutex", Test_KeMutex }, { "KeMutex", Test_KeMutex },
{ "-KeProcessor", Test_KeProcessor }, { "-KeProcessor", Test_KeProcessor },
{ "KeSpinLock", Test_KeSpinLock }, { "KeSpinLock", Test_KeSpinLock },
{ "KeTimer", Test_KeTimer }, { "KeTimer", Test_KeTimer },
{ "-KernelType", Test_KernelType }, { "-KernelType", Test_KernelType },
{ "MmSection", Test_MmSection }, { "MmSection", Test_MmSection },

View file

@ -10,9 +10,23 @@
//#define NDEBUG //#define NDEBUG
#include <debug.h> #include <debug.h>
NTKERNELAPI VOID FASTCALL ExiAcquireFastMutex(IN OUT PFAST_MUTEX FastMutex); static
NTKERNELAPI VOID FASTCALL ExiReleaseFastMutex(IN OUT PFAST_MUTEX FastMutex); VOID
NTKERNELAPI BOOLEAN FASTCALL ExiTryToAcquireFastMutex(IN OUT PFAST_MUTEX FastMutex); (FASTCALL
*pExEnterCriticalRegionAndAcquireFastMutexUnsafe)(
_Inout_ PFAST_MUTEX FastMutex
);
static
VOID
(FASTCALL
*pExReleaseFastMutexUnsafeAndLeaveCriticalRegion)(
_Inout_ PFAST_MUTEX FastMutex
);
static VOID (FASTCALL *pExiAcquireFastMutex)(IN OUT PFAST_MUTEX FastMutex);
static VOID (FASTCALL *pExiReleaseFastMutex)(IN OUT PFAST_MUTEX FastMutex);
static BOOLEAN (FASTCALL *pExiTryToAcquireFastMutex)(IN OUT PFAST_MUTEX FastMutex);
#define CheckMutex(Mutex, ExpectedCount, ExpectedOwner, \ #define CheckMutex(Mutex, ExpectedCount, ExpectedOwner, \
ExpectedContention, ExpectedOldIrql, \ ExpectedContention, ExpectedOldIrql, \
@ -44,15 +58,18 @@ TestFastMutex(
ExReleaseFastMutex(Mutex); ExReleaseFastMutex(Mutex);
CheckMutex(Mutex, 1L, NULL, 0LU, OriginalIrql, OriginalIrql); CheckMutex(Mutex, 1L, NULL, 0LU, OriginalIrql, OriginalIrql);
#ifdef _M_IX86
/* ntoskrnl's fastcall version */ /* ntoskrnl's fastcall version */
ExiAcquireFastMutex(Mutex); if (!skip(pExiAcquireFastMutex &&
CheckMutex(Mutex, 0L, Thread, 0LU, OriginalIrql, APC_LEVEL); pExiReleaseFastMutex &&
ok_bool_false(ExiTryToAcquireFastMutex(Mutex), "ExiTryToAcquireFastMutex returned"); pExiTryToAcquireFastMutex, "No fastcall fast mutex functions\n"))
CheckMutex(Mutex, 0L, Thread, 0LU, OriginalIrql, APC_LEVEL); {
ExiReleaseFastMutex(Mutex); pExiAcquireFastMutex(Mutex);
CheckMutex(Mutex, 1L, NULL, 0LU, OriginalIrql, OriginalIrql); CheckMutex(Mutex, 0L, Thread, 0LU, OriginalIrql, APC_LEVEL);
#endif ok_bool_false(pExiTryToAcquireFastMutex(Mutex), "ExiTryToAcquireFastMutex returned");
CheckMutex(Mutex, 0L, Thread, 0LU, OriginalIrql, APC_LEVEL);
pExiReleaseFastMutex(Mutex);
CheckMutex(Mutex, 1L, NULL, 0LU, OriginalIrql, OriginalIrql);
}
/* try to acquire */ /* try to acquire */
ok_bool_true(ExTryToAcquireFastMutex(Mutex), "ExTryToAcquireFastMutex returned"); ok_bool_true(ExTryToAcquireFastMutex(Mutex), "ExTryToAcquireFastMutex returned");
@ -61,9 +78,14 @@ TestFastMutex(
CheckMutex(Mutex, 1L, NULL, 0LU, OriginalIrql, OriginalIrql); CheckMutex(Mutex, 1L, NULL, 0LU, OriginalIrql, OriginalIrql);
/* shortcut functions with critical region */ /* shortcut functions with critical region */
ExEnterCriticalRegionAndAcquireFastMutexUnsafe(Mutex); if (!skip(pExEnterCriticalRegionAndAcquireFastMutexUnsafe &&
ok_bool_true(KeAreApcsDisabled(), "KeAreApcsDisabled returned"); pExReleaseFastMutexUnsafeAndLeaveCriticalRegion,
ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(Mutex); "Shortcut functions not available"))
{
pExEnterCriticalRegionAndAcquireFastMutexUnsafe(Mutex);
ok_bool_true(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
pExReleaseFastMutexUnsafeAndLeaveCriticalRegion(Mutex);
}
/* acquire/release unsafe */ /* acquire/release unsafe */
if (!KmtIsCheckedBuild || OriginalIrql == APC_LEVEL) if (!KmtIsCheckedBuild || OriginalIrql == APC_LEVEL)
@ -291,6 +313,13 @@ START_TEST(ExFastMutex)
FAST_MUTEX Mutex; FAST_MUTEX Mutex;
KIRQL Irql; KIRQL Irql;
pExEnterCriticalRegionAndAcquireFastMutexUnsafe = KmtGetSystemRoutineAddress(L"ExEnterCriticalRegionAndAcquireFastMutexUnsafe");
pExReleaseFastMutexUnsafeAndLeaveCriticalRegion = KmtGetSystemRoutineAddress(L"ExReleaseFastMutexUnsafeAndLeaveCriticalRegion");
pExiAcquireFastMutex = KmtGetSystemRoutineAddress(L"ExiAcquireFastMutex");
pExiReleaseFastMutex = KmtGetSystemRoutineAddress(L"ExiReleaseFastMutex");
pExiTryToAcquireFastMutex = KmtGetSystemRoutineAddress(L"ExiTryToAcquireFastMutex");
memset(&Mutex, 0x55, sizeof Mutex); memset(&Mutex, 0x55, sizeof Mutex);
ExInitializeFastMutex(&Mutex); ExInitializeFastMutex(&Mutex);
CheckMutex(&Mutex, 1L, NULL, 0LU, 0x55555555LU, PASSIVE_LEVEL); CheckMutex(&Mutex, 1L, NULL, 0LU, 0x55555555LU, PASSIVE_LEVEL);

View file

@ -10,6 +10,49 @@
//#define NDEBUG //#define NDEBUG
#include <debug.h> #include <debug.h>
static
_IRQL_requires_max_(APC_LEVEL)
_Acquires_lock_(_Global_critical_region_)
PVOID
(NTAPI
*pExEnterCriticalRegionAndAcquireResourceShared)(
_Inout_ _Requires_lock_not_held_(*_Curr_) _Acquires_shared_lock_(*_Curr_)
PERESOURCE Resource);
static
_IRQL_requires_max_(APC_LEVEL)
_Acquires_lock_(_Global_critical_region_)
PVOID
(NTAPI
*pExEnterCriticalRegionAndAcquireResourceExclusive)(
_Inout_ _Requires_lock_not_held_(*_Curr_) _Acquires_exclusive_lock_(*_Curr_)
PERESOURCE Resource);
static
_IRQL_requires_max_(APC_LEVEL)
_Acquires_lock_(_Global_critical_region_)
PVOID
(NTAPI
*pExEnterCriticalRegionAndAcquireSharedWaitForExclusive)(
_Inout_ _Requires_lock_not_held_(*_Curr_) _Acquires_lock_(*_Curr_)
PERESOURCE Resource);
static
_IRQL_requires_max_(DISPATCH_LEVEL)
_Releases_lock_(_Global_critical_region_)
VOID
(FASTCALL
*pExReleaseResourceAndLeaveCriticalRegion)(
_Inout_ _Requires_lock_held_(*_Curr_) _Releases_lock_(*_Curr_)
PERESOURCE Resource);
static
_IRQL_requires_min_(PASSIVE_LEVEL)
_IRQL_requires_max_(DISPATCH_LEVEL)
BOOLEAN
(NTAPI
*pKeAreAllApcsDisabled)(VOID);
/* TODO: This is getting pretty long, make it somehow easier to read if possible */ /* TODO: This is getting pretty long, make it somehow easier to read if possible */
/* TODO: this is the Windows Server 2003 version! ROS should use this! /* TODO: this is the Windows Server 2003 version! ROS should use this!
@ -137,65 +180,83 @@ TestResourceUndocumentedShortcuts(
LONG Count = 0; LONG Count = 0;
ok_bool_false(KeAreApcsDisabled(), "KeAreApcsDisabled returned"); ok_bool_false(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
ok_eq_uint(KeAreAllApcsDisabled(), AreApcsDisabled); if (pKeAreAllApcsDisabled)
ok_eq_uint(pKeAreAllApcsDisabled(), AreApcsDisabled);
if (skip(pExEnterCriticalRegionAndAcquireResourceShared &&
pExEnterCriticalRegionAndAcquireSharedWaitForExclusive &&
pExEnterCriticalRegionAndAcquireResourceExclusive &&
pExReleaseResourceAndLeaveCriticalRegion, "No shortcuts\n"))
{
return;
}
/* ExEnterCriticalRegionAndAcquireResourceShared, ExEnterCriticalRegionAndAcquireSharedWaitForExclusive */ /* ExEnterCriticalRegionAndAcquireResourceShared, ExEnterCriticalRegionAndAcquireSharedWaitForExclusive */
Count = 0; Count = 0;
Ret = ExEnterCriticalRegionAndAcquireResourceShared(Res); ++Count; Ret = pExEnterCriticalRegionAndAcquireResourceShared(Res); ++Count;
ok_eq_pointer(Ret, KeGetCurrentThread()->Win32Thread); ok_eq_pointer(Ret, KeGetCurrentThread()->Win32Thread);
ok_bool_true(KeAreApcsDisabled(), "KeAreApcsDisabled returned"); ok_bool_true(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
ok_eq_bool(KeAreAllApcsDisabled(), AreApcsDisabled); if (pKeAreAllApcsDisabled)
ok_eq_bool(pKeAreAllApcsDisabled(), AreApcsDisabled);
CheckResourceStatus(Res, FALSE, Count, 0LU, 0LU); CheckResourceStatus(Res, FALSE, Count, 0LU, 0LU);
Ret = ExEnterCriticalRegionAndAcquireResourceShared(Res); ++Count; Ret = pExEnterCriticalRegionAndAcquireResourceShared(Res); ++Count;
ok_eq_pointer(Ret, KeGetCurrentThread()->Win32Thread); ok_eq_pointer(Ret, KeGetCurrentThread()->Win32Thread);
ok_bool_true(KeAreApcsDisabled(), "KeAreApcsDisabled returned"); ok_bool_true(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
ok_eq_bool(KeAreAllApcsDisabled(), AreApcsDisabled); if (pKeAreAllApcsDisabled)
ok_eq_bool(pKeAreAllApcsDisabled(), AreApcsDisabled);
CheckResourceStatus(Res, FALSE, Count, 0LU, 0LU); CheckResourceStatus(Res, FALSE, Count, 0LU, 0LU);
ExEnterCriticalRegionAndAcquireSharedWaitForExclusive(Res); ++Count; pExEnterCriticalRegionAndAcquireSharedWaitForExclusive(Res); ++Count;
ok_eq_pointer(Ret, KeGetCurrentThread()->Win32Thread); ok_eq_pointer(Ret, KeGetCurrentThread()->Win32Thread);
ok_bool_true(KeAreApcsDisabled(), "KeAreApcsDisabled returned"); ok_bool_true(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
ok_eq_bool(KeAreAllApcsDisabled(), AreApcsDisabled); if (pKeAreAllApcsDisabled)
ok_eq_bool(pKeAreAllApcsDisabled(), AreApcsDisabled);
CheckResourceStatus(Res, FALSE, Count, 0LU, 0LU); CheckResourceStatus(Res, FALSE, Count, 0LU, 0LU);
while (Count-- > 1) while (Count-- > 1)
{ {
ExReleaseResourceAndLeaveCriticalRegion(Res); pExReleaseResourceAndLeaveCriticalRegion(Res);
ok_bool_true(KeAreApcsDisabled(), "KeAreApcsDisabled returned"); ok_bool_true(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
ok_eq_bool(KeAreAllApcsDisabled(), AreApcsDisabled); if (pKeAreAllApcsDisabled)
ok_eq_bool(pKeAreAllApcsDisabled(), AreApcsDisabled);
CheckResourceStatus(Res, FALSE, Count, 0LU, 0LU); CheckResourceStatus(Res, FALSE, Count, 0LU, 0LU);
} }
ExReleaseResourceAndLeaveCriticalRegion(Res); pExReleaseResourceAndLeaveCriticalRegion(Res);
ok_bool_false(KeAreApcsDisabled(), "KeAreApcsDisabled returned"); ok_bool_false(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
ok_eq_bool(KeAreAllApcsDisabled(), AreApcsDisabled); if (pKeAreAllApcsDisabled)
ok_eq_bool(pKeAreAllApcsDisabled(), AreApcsDisabled);
CheckResourceStatus(Res, FALSE, Count, 0LU, 0LU); CheckResourceStatus(Res, FALSE, Count, 0LU, 0LU);
/* ExEnterCriticalRegionAndAcquireResourceExclusive */ /* ExEnterCriticalRegionAndAcquireResourceExclusive */
Count = 0; Count = 0;
ok_bool_false(KeAreApcsDisabled(), "KeAreApcsDisabled returned"); ok_bool_false(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
ok_eq_bool(KeAreAllApcsDisabled(), AreApcsDisabled); if (pKeAreAllApcsDisabled)
Ret = ExEnterCriticalRegionAndAcquireResourceExclusive(Res); ++Count; ok_eq_bool(pKeAreAllApcsDisabled(), AreApcsDisabled);
Ret = pExEnterCriticalRegionAndAcquireResourceExclusive(Res); ++Count;
ok_eq_pointer(Ret, KeGetCurrentThread()->Win32Thread); ok_eq_pointer(Ret, KeGetCurrentThread()->Win32Thread);
ok_bool_true(KeAreApcsDisabled(), "KeAreApcsDisabled returned"); ok_bool_true(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
ok_eq_bool(KeAreAllApcsDisabled(), AreApcsDisabled); if (pKeAreAllApcsDisabled)
ok_eq_bool(pKeAreAllApcsDisabled(), AreApcsDisabled);
CheckResourceStatus(Res, TRUE, Count, 0LU, 0LU); CheckResourceStatus(Res, TRUE, Count, 0LU, 0LU);
Ret = ExEnterCriticalRegionAndAcquireResourceExclusive(Res); ++Count; Ret = pExEnterCriticalRegionAndAcquireResourceExclusive(Res); ++Count;
ok_eq_pointer(Ret, KeGetCurrentThread()->Win32Thread); ok_eq_pointer(Ret, KeGetCurrentThread()->Win32Thread);
ok_bool_true(KeAreApcsDisabled(), "KeAreApcsDisabled returned"); ok_bool_true(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
ok_eq_bool(KeAreAllApcsDisabled(), AreApcsDisabled); if (pKeAreAllApcsDisabled)
ok_eq_bool(pKeAreAllApcsDisabled(), AreApcsDisabled);
CheckResourceStatus(Res, TRUE, Count, 0LU, 0LU); CheckResourceStatus(Res, TRUE, Count, 0LU, 0LU);
ExReleaseResourceAndLeaveCriticalRegion(Res); --Count; pExReleaseResourceAndLeaveCriticalRegion(Res); --Count;
ok_bool_true(KeAreApcsDisabled(), "KeAreApcsDisabled returned"); ok_bool_true(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
ok_eq_bool(KeAreAllApcsDisabled(), AreApcsDisabled); if (pKeAreAllApcsDisabled)
ok_eq_bool(pKeAreAllApcsDisabled(), AreApcsDisabled);
CheckResourceStatus(Res, TRUE, Count, 0LU, 0LU); CheckResourceStatus(Res, TRUE, Count, 0LU, 0LU);
ExReleaseResourceAndLeaveCriticalRegion(Res); --Count; pExReleaseResourceAndLeaveCriticalRegion(Res); --Count;
ok_bool_false(KeAreApcsDisabled(), "KeAreApcsDisabled returned"); ok_bool_false(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
ok_eq_uint(KeAreAllApcsDisabled(), AreApcsDisabled); if (pKeAreAllApcsDisabled)
ok_eq_uint(pKeAreAllApcsDisabled(), AreApcsDisabled);
CheckResourceStatus(Res, FALSE, Count, 0LU, 0LU); CheckResourceStatus(Res, FALSE, Count, 0LU, 0LU);
} }
@ -400,6 +461,17 @@ START_TEST(ExResource)
ERESOURCE Res; ERESOURCE Res;
KIRQL Irql; KIRQL Irql;
pExEnterCriticalRegionAndAcquireResourceShared = KmtGetSystemRoutineAddress(L"ExEnterCriticalRegionAndAcquireResourceShared");
pExEnterCriticalRegionAndAcquireSharedWaitForExclusive = KmtGetSystemRoutineAddress(L"ExEnterCriticalRegionAndAcquireSharedWaitForExclusive");
pExEnterCriticalRegionAndAcquireResourceExclusive = KmtGetSystemRoutineAddress(L"ExEnterCriticalRegionAndAcquireResourceExclusive");
pExReleaseResourceAndLeaveCriticalRegion = KmtGetSystemRoutineAddress(L"ExReleaseResourceAndLeaveCriticalRegion");
pKeAreAllApcsDisabled = KmtGetSystemRoutineAddress(L"KeAreAllApcsDisabled");
if (skip(pKeAreAllApcsDisabled != NULL, "KeAreAllApcsDisabled unavailable\n"))
{
/* We can live without this function here */
}
/* this must be true even with the different structure versions */ /* this must be true even with the different structure versions */
ASSERT(sizeof(ERESOURCE) == sizeof(ERESOURCE_2K3)); ASSERT(sizeof(ERESOURCE) == sizeof(ERESOURCE_2K3));

View file

@ -7,11 +7,33 @@
#include <kmt_test.h> #include <kmt_test.h>
static
_IRQL_requires_min_(PASSIVE_LEVEL)
_IRQL_requires_max_(DISPATCH_LEVEL)
BOOLEAN
(NTAPI
*pKeAreAllApcsDisabled)(VOID);
static
_Acquires_lock_(_Global_critical_region_)
_IRQL_requires_max_(APC_LEVEL)
VOID
(NTAPI
*pKeEnterGuardedRegion)(VOID);
static
_Releases_lock_(_Global_critical_region_)
_IRQL_requires_max_(APC_LEVEL)
VOID
(NTAPI
*pKeLeaveGuardedRegion)(VOID);
#define CheckApcs(KernelApcsDisabled, SpecialApcsDisabled, AllApcsDisabled, Irql) do \ #define CheckApcs(KernelApcsDisabled, SpecialApcsDisabled, AllApcsDisabled, Irql) do \
{ \ { \
ok_eq_bool(KeAreApcsDisabled(), KernelApcsDisabled || SpecialApcsDisabled); \ ok_eq_bool(KeAreApcsDisabled(), KernelApcsDisabled || SpecialApcsDisabled); \
ok_eq_int(Thread->KernelApcDisable, KernelApcsDisabled); \ ok_eq_int(Thread->KernelApcDisable, KernelApcsDisabled); \
ok_eq_bool(KeAreAllApcsDisabled(), AllApcsDisabled); \ if (pKeAreAllApcsDisabled) \
ok_eq_bool(pKeAreAllApcsDisabled(), AllApcsDisabled); \
ok_eq_int(Thread->SpecialApcDisable, SpecialApcsDisabled); \ ok_eq_int(Thread->SpecialApcDisable, SpecialApcsDisabled); \
ok_irql(Irql); \ ok_irql(Irql); \
} while (0) } while (0)
@ -19,7 +41,18 @@
START_TEST(KeApc) START_TEST(KeApc)
{ {
KIRQL Irql; KIRQL Irql;
PKTHREAD Thread = KeGetCurrentThread(); PKTHREAD Thread;
pKeAreAllApcsDisabled = KmtGetSystemRoutineAddress(L"KeAreAllApcsDisabled");
pKeEnterGuardedRegion = KmtGetSystemRoutineAddress(L"KeEnterGuardedRegion");
pKeLeaveGuardedRegion = KmtGetSystemRoutineAddress(L"KeLeaveGuardedRegion");
if (skip(pKeAreAllApcsDisabled != NULL, "KeAreAllApcsDisabled unavailable\n"))
{
/* We can live without this function here */
}
Thread = KeGetCurrentThread();
CheckApcs(0, 0, FALSE, PASSIVE_LEVEL); CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
@ -38,37 +71,41 @@ START_TEST(KeApc)
CheckApcs(0, 0, FALSE, PASSIVE_LEVEL); CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
/* guarded region */ /* guarded region */
KeEnterGuardedRegion(); if (!skip(pKeEnterGuardedRegion &&
CheckApcs(0, -1, TRUE, PASSIVE_LEVEL); pKeLeaveGuardedRegion, "Guarded regions not available\n"))
KeEnterGuardedRegion(); {
CheckApcs(0, -2, TRUE, PASSIVE_LEVEL); pKeEnterGuardedRegion();
KeEnterGuardedRegion(); CheckApcs(0, -1, TRUE, PASSIVE_LEVEL);
CheckApcs(0, -3, TRUE, PASSIVE_LEVEL); pKeEnterGuardedRegion();
KeLeaveGuardedRegion(); CheckApcs(0, -2, TRUE, PASSIVE_LEVEL);
CheckApcs(0, -2, TRUE, PASSIVE_LEVEL); pKeEnterGuardedRegion();
KeLeaveGuardedRegion(); CheckApcs(0, -3, TRUE, PASSIVE_LEVEL);
CheckApcs(0, -1, TRUE, PASSIVE_LEVEL); pKeLeaveGuardedRegion();
KeLeaveGuardedRegion(); CheckApcs(0, -2, TRUE, PASSIVE_LEVEL);
CheckApcs(0, 0, FALSE, PASSIVE_LEVEL); pKeLeaveGuardedRegion();
CheckApcs(0, -1, TRUE, PASSIVE_LEVEL);
pKeLeaveGuardedRegion();
CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
/* mix them */ /* mix them */
KeEnterGuardedRegion(); pKeEnterGuardedRegion();
CheckApcs(0, -1, TRUE, PASSIVE_LEVEL); CheckApcs(0, -1, TRUE, PASSIVE_LEVEL);
KeEnterCriticalRegion(); KeEnterCriticalRegion();
CheckApcs(-1, -1, TRUE, PASSIVE_LEVEL); CheckApcs(-1, -1, TRUE, PASSIVE_LEVEL);
KeLeaveCriticalRegion(); KeLeaveCriticalRegion();
CheckApcs(0, -1, TRUE, PASSIVE_LEVEL); CheckApcs(0, -1, TRUE, PASSIVE_LEVEL);
KeLeaveGuardedRegion(); pKeLeaveGuardedRegion();
CheckApcs(0, 0, FALSE, PASSIVE_LEVEL); CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
KeEnterCriticalRegion(); KeEnterCriticalRegion();
CheckApcs(-1, 0, FALSE, PASSIVE_LEVEL); CheckApcs(-1, 0, FALSE, PASSIVE_LEVEL);
KeEnterGuardedRegion(); pKeEnterGuardedRegion();
CheckApcs(-1, -1, TRUE, PASSIVE_LEVEL); CheckApcs(-1, -1, TRUE, PASSIVE_LEVEL);
KeLeaveGuardedRegion(); pKeLeaveGuardedRegion();
CheckApcs(-1, 0, FALSE, PASSIVE_LEVEL); CheckApcs(-1, 0, FALSE, PASSIVE_LEVEL);
KeLeaveCriticalRegion(); KeLeaveCriticalRegion();
CheckApcs(0, 0, FALSE, PASSIVE_LEVEL); CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
}
/* leave without entering */ /* leave without entering */
if (!KmtIsCheckedBuild) if (!KmtIsCheckedBuild)
@ -78,19 +115,23 @@ START_TEST(KeApc)
KeEnterCriticalRegion(); KeEnterCriticalRegion();
CheckApcs(0, 0, FALSE, PASSIVE_LEVEL); CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
KeLeaveGuardedRegion(); if (!skip(pKeEnterGuardedRegion &&
CheckApcs(0, 1, TRUE, PASSIVE_LEVEL); pKeLeaveGuardedRegion, "Guarded regions not available\n"))
KeEnterGuardedRegion(); {
CheckApcs(0, 0, FALSE, PASSIVE_LEVEL); pKeLeaveGuardedRegion();
CheckApcs(0, 1, TRUE, PASSIVE_LEVEL);
pKeEnterGuardedRegion();
CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
KeLeaveCriticalRegion(); KeLeaveCriticalRegion();
CheckApcs(1, 0, FALSE, PASSIVE_LEVEL); CheckApcs(1, 0, FALSE, PASSIVE_LEVEL);
KeLeaveGuardedRegion(); pKeLeaveGuardedRegion();
CheckApcs(1, 1, TRUE, PASSIVE_LEVEL); CheckApcs(1, 1, TRUE, PASSIVE_LEVEL);
KeEnterCriticalRegion(); KeEnterCriticalRegion();
CheckApcs(0, 1, TRUE, PASSIVE_LEVEL); CheckApcs(0, 1, TRUE, PASSIVE_LEVEL);
KeEnterGuardedRegion(); pKeEnterGuardedRegion();
CheckApcs(0, 0, FALSE, PASSIVE_LEVEL); CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
}
} }
/* manually disable APCs */ /* manually disable APCs */
@ -130,38 +171,42 @@ START_TEST(KeApc)
CheckApcs(0, 0, TRUE, HIGH_LEVEL); CheckApcs(0, 0, TRUE, HIGH_LEVEL);
/* Ke*GuardedRegion assert at > APC_LEVEL */ /* Ke*GuardedRegion assert at > APC_LEVEL */
if (!KmtIsCheckedBuild) if (!KmtIsCheckedBuild &&
!skip(pKeEnterGuardedRegion &&
pKeLeaveGuardedRegion, "Guarded regions not available\n"))
{ {
KeEnterGuardedRegion(); pKeEnterGuardedRegion();
CheckApcs(0, -1, TRUE, HIGH_LEVEL); CheckApcs(0, -1, TRUE, HIGH_LEVEL);
KeLeaveGuardedRegion(); pKeLeaveGuardedRegion();
} }
CheckApcs(0, 0, TRUE, HIGH_LEVEL); CheckApcs(0, 0, TRUE, HIGH_LEVEL);
KeLowerIrql(Irql); KeLowerIrql(Irql);
CheckApcs(0, 0, FALSE, PASSIVE_LEVEL); CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
if (!KmtIsCheckedBuild) if (!KmtIsCheckedBuild &&
!skip(pKeEnterGuardedRegion &&
pKeLeaveGuardedRegion, "Guarded regions not available\n"))
{ {
KeRaiseIrql(HIGH_LEVEL, &Irql); KeRaiseIrql(HIGH_LEVEL, &Irql);
CheckApcs(0, 0, TRUE, HIGH_LEVEL); CheckApcs(0, 0, TRUE, HIGH_LEVEL);
KeEnterCriticalRegion(); KeEnterCriticalRegion();
CheckApcs(-1, 0, TRUE, HIGH_LEVEL); CheckApcs(-1, 0, TRUE, HIGH_LEVEL);
KeEnterGuardedRegion(); pKeEnterGuardedRegion();
CheckApcs(-1, -1, TRUE, HIGH_LEVEL); CheckApcs(-1, -1, TRUE, HIGH_LEVEL);
KeLowerIrql(Irql); KeLowerIrql(Irql);
CheckApcs(-1, -1, TRUE, PASSIVE_LEVEL); CheckApcs(-1, -1, TRUE, PASSIVE_LEVEL);
KeLeaveCriticalRegion(); KeLeaveCriticalRegion();
CheckApcs(0, -1, TRUE, PASSIVE_LEVEL); CheckApcs(0, -1, TRUE, PASSIVE_LEVEL);
KeLeaveGuardedRegion(); pKeLeaveGuardedRegion();
CheckApcs(0, 0, FALSE, PASSIVE_LEVEL); CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
KeEnterGuardedRegion(); pKeEnterGuardedRegion();
CheckApcs(0, -1, TRUE, PASSIVE_LEVEL); CheckApcs(0, -1, TRUE, PASSIVE_LEVEL);
KeRaiseIrql(HIGH_LEVEL, &Irql); KeRaiseIrql(HIGH_LEVEL, &Irql);
CheckApcs(0, -1, TRUE, HIGH_LEVEL); CheckApcs(0, -1, TRUE, HIGH_LEVEL);
KeEnterCriticalRegion(); KeEnterCriticalRegion();
CheckApcs(-1, -1, TRUE, HIGH_LEVEL); CheckApcs(-1, -1, TRUE, HIGH_LEVEL);
KeLeaveGuardedRegion(); pKeLeaveGuardedRegion();
CheckApcs(-1, 0, TRUE, HIGH_LEVEL); CheckApcs(-1, 0, TRUE, HIGH_LEVEL);
KeLowerIrql(Irql); KeLowerIrql(Irql);
CheckApcs(-1, 0, FALSE, PASSIVE_LEVEL); CheckApcs(-1, 0, FALSE, PASSIVE_LEVEL);
@ -172,13 +217,13 @@ START_TEST(KeApc)
CheckApcs(-1, 0, FALSE, PASSIVE_LEVEL); CheckApcs(-1, 0, FALSE, PASSIVE_LEVEL);
KeRaiseIrql(HIGH_LEVEL, &Irql); KeRaiseIrql(HIGH_LEVEL, &Irql);
CheckApcs(-1, 0, TRUE, HIGH_LEVEL); CheckApcs(-1, 0, TRUE, HIGH_LEVEL);
KeEnterGuardedRegion(); pKeEnterGuardedRegion();
CheckApcs(-1, -1, TRUE, HIGH_LEVEL); CheckApcs(-1, -1, TRUE, HIGH_LEVEL);
KeLeaveCriticalRegion(); KeLeaveCriticalRegion();
CheckApcs(0, -1, TRUE, HIGH_LEVEL); CheckApcs(0, -1, TRUE, HIGH_LEVEL);
KeLowerIrql(Irql); KeLowerIrql(Irql);
CheckApcs(0, -1, TRUE, PASSIVE_LEVEL); CheckApcs(0, -1, TRUE, PASSIVE_LEVEL);
KeLeaveGuardedRegion(); pKeLeaveGuardedRegion();
CheckApcs(0, 0, FALSE, PASSIVE_LEVEL); CheckApcs(0, 0, FALSE, PASSIVE_LEVEL);
} }

View file

@ -10,6 +10,86 @@
#define NDEBUG #define NDEBUG
#include <debug.h> #include <debug.h>
static
_IRQL_requires_min_(PASSIVE_LEVEL)
_IRQL_requires_max_(DISPATCH_LEVEL)
BOOLEAN
(NTAPI
*pKeAreAllApcsDisabled)(VOID);
static
_Acquires_lock_(_Global_critical_region_)
_Requires_lock_not_held_(*Mutex)
_Acquires_lock_(*Mutex)
_IRQL_requires_max_(APC_LEVEL)
_IRQL_requires_min_(PASSIVE_LEVEL)
VOID
(FASTCALL
*pKeAcquireGuardedMutex)(
_Inout_ PKGUARDED_MUTEX GuardedMutex);
static
_Requires_lock_not_held_(*FastMutex)
_Acquires_lock_(*FastMutex)
_IRQL_requires_max_(APC_LEVEL)
_IRQL_requires_min_(PASSIVE_LEVEL)
VOID
(FASTCALL
*pKeAcquireGuardedMutexUnsafe)(
_Inout_ PKGUARDED_MUTEX GuardedMutex);
static
_Acquires_lock_(_Global_critical_region_)
_IRQL_requires_max_(APC_LEVEL)
VOID
(NTAPI
*pKeEnterGuardedRegion)(VOID);
static
_Releases_lock_(_Global_critical_region_)
_IRQL_requires_max_(APC_LEVEL)
VOID
(NTAPI
*pKeLeaveGuardedRegion)(VOID);
static
_IRQL_requires_max_(APC_LEVEL)
_IRQL_requires_min_(PASSIVE_LEVEL)
VOID
(FASTCALL
*pKeInitializeGuardedMutex)(
_Out_ PKGUARDED_MUTEX GuardedMutex);
static
_Requires_lock_held_(*FastMutex)
_Releases_lock_(*FastMutex)
_IRQL_requires_max_(APC_LEVEL)
VOID
(FASTCALL
*pKeReleaseGuardedMutexUnsafe)(
_Inout_ PKGUARDED_MUTEX GuardedMutex);
static
_Releases_lock_(_Global_critical_region_)
_Requires_lock_held_(*Mutex)
_Releases_lock_(*Mutex)
_IRQL_requires_max_(APC_LEVEL)
VOID
(FASTCALL
*pKeReleaseGuardedMutex)(
_Inout_ PKGUARDED_MUTEX GuardedMutex);
static
_Must_inspect_result_
_Success_(return != FALSE)
_IRQL_requires_max_(APC_LEVEL)
_Post_satisfies_(return == 1 || return == 0)
BOOLEAN
(FASTCALL
*pKeTryToAcquireGuardedMutex)(
_When_ (return, _Requires_lock_not_held_(*_Curr_) _Acquires_exclusive_lock_(*_Curr_)) _Acquires_lock_(_Global_critical_region_)
_Inout_ PKGUARDED_MUTEX GuardedMutex);
#define CheckMutex(Mutex, ExpectedCount, ExpectedOwner, ExpectedContention, \ #define CheckMutex(Mutex, ExpectedCount, ExpectedOwner, ExpectedContention, \
ExpectedKernelApcDisable, ExpectedSpecialApcDisable, \ ExpectedKernelApcDisable, ExpectedSpecialApcDisable, \
KernelApcsDisabled, SpecialApcsDisabled, AllApcsDisabled, \ KernelApcsDisabled, SpecialApcsDisabled, AllApcsDisabled, \
@ -25,7 +105,7 @@
ok_eq_int((Mutex)->SpecialApcDisable, 0x5555); \ ok_eq_int((Mutex)->SpecialApcDisable, 0x5555); \
ok_eq_bool(KeAreApcsDisabled(), KernelApcsDisabled || SpecialApcsDisabled); \ ok_eq_bool(KeAreApcsDisabled(), KernelApcsDisabled || SpecialApcsDisabled); \
ok_eq_int(Thread->KernelApcDisable, KernelApcsDisabled); \ ok_eq_int(Thread->KernelApcDisable, KernelApcsDisabled); \
ok_eq_bool(KeAreAllApcsDisabled(), AllApcsDisabled); \ ok_eq_bool(pKeAreAllApcsDisabled(), AllApcsDisabled); \
ok_eq_int(Thread->SpecialApcDisable, SpecialApcsDisabled); \ ok_eq_int(Thread->SpecialApcDisable, SpecialApcsDisabled); \
ok_irql(ExpectedIrql); \ ok_irql(ExpectedIrql); \
} while (0) } while (0)
@ -48,17 +128,17 @@ TestGuardedMutex(
if (!KmtIsCheckedBuild || OriginalIrql <= APC_LEVEL) if (!KmtIsCheckedBuild || OriginalIrql <= APC_LEVEL)
{ {
/* acquire/release normally */ /* acquire/release normally */
KeAcquireGuardedMutex(Mutex); pKeAcquireGuardedMutex(Mutex);
CheckMutex(Mutex, 0L, Thread, 0LU, 0x5555, SpecialApcsDisabled - 1, KernelApcsDisabled, SpecialApcsDisabled - 1, TRUE, OriginalIrql); CheckMutex(Mutex, 0L, Thread, 0LU, 0x5555, SpecialApcsDisabled - 1, KernelApcsDisabled, SpecialApcsDisabled - 1, TRUE, OriginalIrql);
ok_bool_false(KeTryToAcquireGuardedMutex(Mutex), "KeTryToAcquireGuardedMutex returned"); ok_bool_false(pKeTryToAcquireGuardedMutex(Mutex), "KeTryToAcquireGuardedMutex returned");
CheckMutex(Mutex, 0L, Thread, 0LU, 0x5555, SpecialApcsDisabled - 1, KernelApcsDisabled, SpecialApcsDisabled - 1, TRUE, OriginalIrql); CheckMutex(Mutex, 0L, Thread, 0LU, 0x5555, SpecialApcsDisabled - 1, KernelApcsDisabled, SpecialApcsDisabled - 1, TRUE, OriginalIrql);
KeReleaseGuardedMutex(Mutex); pKeReleaseGuardedMutex(Mutex);
CheckMutex(Mutex, 1L, NULL, 0LU, 0x5555, SpecialApcsDisabled - 1, KernelApcsDisabled, SpecialApcsDisabled, AllApcsDisabled, OriginalIrql); CheckMutex(Mutex, 1L, NULL, 0LU, 0x5555, SpecialApcsDisabled - 1, KernelApcsDisabled, SpecialApcsDisabled, AllApcsDisabled, OriginalIrql);
/* try to acquire */ /* try to acquire */
ok_bool_true(KeTryToAcquireGuardedMutex(Mutex), "KeTryToAcquireGuardedMutex returned"); ok_bool_true(pKeTryToAcquireGuardedMutex(Mutex), "KeTryToAcquireGuardedMutex returned");
CheckMutex(Mutex, 0L, Thread, 0LU, 0x5555, SpecialApcsDisabled - 1, KernelApcsDisabled, SpecialApcsDisabled - 1, TRUE, OriginalIrql); CheckMutex(Mutex, 0L, Thread, 0LU, 0x5555, SpecialApcsDisabled - 1, KernelApcsDisabled, SpecialApcsDisabled - 1, TRUE, OriginalIrql);
KeReleaseGuardedMutex(Mutex); pKeReleaseGuardedMutex(Mutex);
CheckMutex(Mutex, 1L, NULL, 0LU, 0x5555, SpecialApcsDisabled - 1, KernelApcsDisabled, SpecialApcsDisabled, AllApcsDisabled, OriginalIrql); CheckMutex(Mutex, 1L, NULL, 0LU, 0x5555, SpecialApcsDisabled - 1, KernelApcsDisabled, SpecialApcsDisabled, AllApcsDisabled, OriginalIrql);
} }
else else
@ -69,9 +149,9 @@ TestGuardedMutex(
if (!KmtIsCheckedBuild || OriginalIrql == APC_LEVEL || SpecialApcsDisabled < 0) if (!KmtIsCheckedBuild || OriginalIrql == APC_LEVEL || SpecialApcsDisabled < 0)
{ {
/* acquire/release unsafe */ /* acquire/release unsafe */
KeAcquireGuardedMutexUnsafe(Mutex); pKeAcquireGuardedMutexUnsafe(Mutex);
CheckMutex(Mutex, 0L, Thread, 0LU, 0x5555, SpecialApcsDisabled - 1, KernelApcsDisabled, SpecialApcsDisabled, AllApcsDisabled, OriginalIrql); CheckMutex(Mutex, 0L, Thread, 0LU, 0x5555, SpecialApcsDisabled - 1, KernelApcsDisabled, SpecialApcsDisabled, AllApcsDisabled, OriginalIrql);
KeReleaseGuardedMutexUnsafe(Mutex); pKeReleaseGuardedMutexUnsafe(Mutex);
CheckMutex(Mutex, 1L, NULL, 0LU, 0x5555, SpecialApcsDisabled - 1, KernelApcsDisabled, SpecialApcsDisabled, AllApcsDisabled, OriginalIrql); CheckMutex(Mutex, 1L, NULL, 0LU, 0x5555, SpecialApcsDisabled - 1, KernelApcsDisabled, SpecialApcsDisabled, AllApcsDisabled, OriginalIrql);
} }
@ -79,29 +159,29 @@ TestGuardedMutex(
if (!KmtIsCheckedBuild) if (!KmtIsCheckedBuild)
{ {
/* mismatched acquire/release */ /* mismatched acquire/release */
KeAcquireGuardedMutex(Mutex); pKeAcquireGuardedMutex(Mutex);
CheckMutex(Mutex, 0L, Thread, 0LU, 0x5555, SpecialApcsDisabled - 1, KernelApcsDisabled, SpecialApcsDisabled - 1, TRUE, OriginalIrql); CheckMutex(Mutex, 0L, Thread, 0LU, 0x5555, SpecialApcsDisabled - 1, KernelApcsDisabled, SpecialApcsDisabled - 1, TRUE, OriginalIrql);
KeReleaseGuardedMutexUnsafe(Mutex); pKeReleaseGuardedMutexUnsafe(Mutex);
CheckMutex(Mutex, 1L, NULL, 0LU, 0x5555, SpecialApcsDisabled - 1, KernelApcsDisabled, SpecialApcsDisabled - 1, TRUE, OriginalIrql); CheckMutex(Mutex, 1L, NULL, 0LU, 0x5555, SpecialApcsDisabled - 1, KernelApcsDisabled, SpecialApcsDisabled - 1, TRUE, OriginalIrql);
KeLeaveGuardedRegion(); pKeLeaveGuardedRegion();
CheckMutex(Mutex, 1L, NULL, 0LU, 0x5555, SpecialApcsDisabled - 1, KernelApcsDisabled, SpecialApcsDisabled, AllApcsDisabled, OriginalIrql); CheckMutex(Mutex, 1L, NULL, 0LU, 0x5555, SpecialApcsDisabled - 1, KernelApcsDisabled, SpecialApcsDisabled, AllApcsDisabled, OriginalIrql);
KeAcquireGuardedMutexUnsafe(Mutex); pKeAcquireGuardedMutexUnsafe(Mutex);
CheckMutex(Mutex, 0L, Thread, 0LU, 0x5555, SpecialApcsDisabled - 1, KernelApcsDisabled, SpecialApcsDisabled, AllApcsDisabled, OriginalIrql); CheckMutex(Mutex, 0L, Thread, 0LU, 0x5555, SpecialApcsDisabled - 1, KernelApcsDisabled, SpecialApcsDisabled, AllApcsDisabled, OriginalIrql);
KeReleaseGuardedMutex(Mutex); pKeReleaseGuardedMutex(Mutex);
CheckMutex(Mutex, 1L, NULL, 0LU, 0x5555, SpecialApcsDisabled - 1, KernelApcsDisabled, SpecialApcsDisabled + 1, OriginalIrql >= APC_LEVEL || SpecialApcsDisabled != -1, OriginalIrql); CheckMutex(Mutex, 1L, NULL, 0LU, 0x5555, SpecialApcsDisabled - 1, KernelApcsDisabled, SpecialApcsDisabled + 1, OriginalIrql >= APC_LEVEL || SpecialApcsDisabled != -1, OriginalIrql);
KeEnterGuardedRegion(); pKeEnterGuardedRegion();
CheckMutex(Mutex, 1L, NULL, 0LU, 0x5555, SpecialApcsDisabled - 1, KernelApcsDisabled, SpecialApcsDisabled, AllApcsDisabled, OriginalIrql); CheckMutex(Mutex, 1L, NULL, 0LU, 0x5555, SpecialApcsDisabled - 1, KernelApcsDisabled, SpecialApcsDisabled, AllApcsDisabled, OriginalIrql);
/* release without acquire */ /* release without acquire */
KeReleaseGuardedMutexUnsafe(Mutex); pKeReleaseGuardedMutexUnsafe(Mutex);
CheckMutex(Mutex, 0L, NULL, 0LU, 0x5555, SpecialApcsDisabled - 1, KernelApcsDisabled, SpecialApcsDisabled, AllApcsDisabled, OriginalIrql); CheckMutex(Mutex, 0L, NULL, 0LU, 0x5555, SpecialApcsDisabled - 1, KernelApcsDisabled, SpecialApcsDisabled, AllApcsDisabled, OriginalIrql);
KeReleaseGuardedMutex(Mutex); pKeReleaseGuardedMutex(Mutex);
CheckMutex(Mutex, 1L, NULL, 0LU, 0x5555, SpecialApcsDisabled, KernelApcsDisabled, SpecialApcsDisabled + 1, OriginalIrql >= APC_LEVEL || SpecialApcsDisabled != -1, OriginalIrql); CheckMutex(Mutex, 1L, NULL, 0LU, 0x5555, SpecialApcsDisabled, KernelApcsDisabled, SpecialApcsDisabled + 1, OriginalIrql >= APC_LEVEL || SpecialApcsDisabled != -1, OriginalIrql);
KeReleaseGuardedMutex(Mutex); pKeReleaseGuardedMutex(Mutex);
/* TODO: here we see that Mutex->Count isn't actually just a count. Test the bits correctly! */ /* TODO: here we see that Mutex->Count isn't actually just a count. Test the bits correctly! */
CheckMutex(Mutex, 0L, NULL, 0LU, 0x5555, SpecialApcsDisabled, KernelApcsDisabled, SpecialApcsDisabled + 2, OriginalIrql >= APC_LEVEL || SpecialApcsDisabled != -2, OriginalIrql); CheckMutex(Mutex, 0L, NULL, 0LU, 0x5555, SpecialApcsDisabled, KernelApcsDisabled, SpecialApcsDisabled + 2, OriginalIrql >= APC_LEVEL || SpecialApcsDisabled != -2, OriginalIrql);
KeReleaseGuardedMutex(Mutex); pKeReleaseGuardedMutex(Mutex);
CheckMutex(Mutex, 1L, NULL, 0LU, 0x5555, SpecialApcsDisabled, KernelApcsDisabled, SpecialApcsDisabled + 3, OriginalIrql >= APC_LEVEL || SpecialApcsDisabled != -3, OriginalIrql); CheckMutex(Mutex, 1L, NULL, 0LU, 0x5555, SpecialApcsDisabled, KernelApcsDisabled, SpecialApcsDisabled + 3, OriginalIrql >= APC_LEVEL || SpecialApcsDisabled != -3, OriginalIrql);
Thread->SpecialApcDisable -= 3; Thread->SpecialApcDisable -= 3;
} }
@ -242,10 +322,10 @@ TestGuardedMutexConcurrent(
LARGE_INTEGER Timeout; LARGE_INTEGER Timeout;
Timeout.QuadPart = -50 * 1000 * 10; /* 50 ms */ Timeout.QuadPart = -50 * 1000 * 10; /* 50 ms */
InitThreadData(&ThreadData, Mutex, KeAcquireGuardedMutex, NULL, KeReleaseGuardedMutex); InitThreadData(&ThreadData, Mutex, pKeAcquireGuardedMutex, NULL, pKeReleaseGuardedMutex);
InitThreadData(&ThreadData2, Mutex, KeAcquireGuardedMutex, NULL, KeReleaseGuardedMutex); InitThreadData(&ThreadData2, Mutex, pKeAcquireGuardedMutex, NULL, pKeReleaseGuardedMutex);
InitThreadData(&ThreadDataUnsafe, Mutex, KeAcquireGuardedMutexUnsafe, NULL, KeReleaseGuardedMutexUnsafe); InitThreadData(&ThreadDataUnsafe, Mutex, pKeAcquireGuardedMutexUnsafe, NULL, pKeReleaseGuardedMutexUnsafe);
InitThreadData(&ThreadDataTry, Mutex, NULL, KeTryToAcquireGuardedMutex, KeReleaseGuardedMutex); InitThreadData(&ThreadDataTry, Mutex, NULL, pKeTryToAcquireGuardedMutex, pKeReleaseGuardedMutex);
/* have a thread acquire the mutex */ /* have a thread acquire the mutex */
Status = StartThread(&ThreadData, NULL, PASSIVE_LEVEL, FALSE, FALSE); Status = StartThread(&ThreadData, NULL, PASSIVE_LEVEL, FALSE, FALSE);
@ -337,6 +417,29 @@ START_TEST(KeGuardedMutex)
}; };
int i; int i;
pKeAreAllApcsDisabled = KmtGetSystemRoutineAddress(L"KeAreAllApcsDisabled");
pKeInitializeGuardedMutex = KmtGetSystemRoutineAddress(L"KeInitializeGuardedMutex");
pKeAcquireGuardedMutex = KmtGetSystemRoutineAddress(L"KeAcquireGuardedMutex");
pKeAcquireGuardedMutexUnsafe = KmtGetSystemRoutineAddress(L"KeAcquireGuardedMutexUnsafe");
pKeEnterGuardedRegion = KmtGetSystemRoutineAddress(L"KeEnterGuardedRegion");
pKeLeaveGuardedRegion = KmtGetSystemRoutineAddress(L"KeLeaveGuardedRegion");
pKeReleaseGuardedMutex = KmtGetSystemRoutineAddress(L"KeReleaseGuardedMutex");
pKeReleaseGuardedMutexUnsafe = KmtGetSystemRoutineAddress(L"KeReleaseGuardedMutexUnsafe");
pKeTryToAcquireGuardedMutex = KmtGetSystemRoutineAddress(L"KeTryToAcquireGuardedMutex");
if (skip(pKeAreAllApcsDisabled &&
pKeInitializeGuardedMutex &&
pKeAcquireGuardedMutex &&
pKeAcquireGuardedMutexUnsafe &&
pKeEnterGuardedRegion &&
pKeLeaveGuardedRegion &&
pKeReleaseGuardedMutex &&
pKeReleaseGuardedMutexUnsafe &&
pKeTryToAcquireGuardedMutex, "No guarded mutexes\n"))
{
return;
}
for (i = 0; i < sizeof TestIterations / sizeof TestIterations[0]; ++i) for (i = 0; i < sizeof TestIterations / sizeof TestIterations[0]; ++i)
{ {
trace("Run %d\n", i); trace("Run %d\n", i);
@ -345,7 +448,7 @@ START_TEST(KeGuardedMutex)
Thread->SpecialApcDisable = TestIterations[i].SpecialApcsDisabled; Thread->SpecialApcDisable = TestIterations[i].SpecialApcsDisabled;
RtlFillMemory(&Mutex, sizeof Mutex, 0x55); RtlFillMemory(&Mutex, sizeof Mutex, 0x55);
KeInitializeGuardedMutex(&Mutex); pKeInitializeGuardedMutex(&Mutex);
CheckMutex(&Mutex, 1L, NULL, 0LU, 0x5555, 0x5555, TestIterations[i].KernelApcsDisabled, TestIterations[i].SpecialApcsDisabled, TestIterations[i].AllApcsDisabled, TestIterations[i].Irql); CheckMutex(&Mutex, 1L, NULL, 0LU, 0x5555, 0x5555, TestIterations[i].KernelApcsDisabled, TestIterations[i].SpecialApcsDisabled, TestIterations[i].AllApcsDisabled, TestIterations[i].Irql);
TestGuardedMutex(&Mutex, TestIterations[i].KernelApcsDisabled, TestIterations[i].SpecialApcsDisabled, TestIterations[i].AllApcsDisabled, TestIterations[i].Irql); TestGuardedMutex(&Mutex, TestIterations[i].KernelApcsDisabled, TestIterations[i].SpecialApcsDisabled, TestIterations[i].AllApcsDisabled, TestIterations[i].Irql);
@ -356,6 +459,6 @@ START_TEST(KeGuardedMutex)
trace("Concurrent test\n"); trace("Concurrent test\n");
RtlFillMemory(&Mutex, sizeof Mutex, 0x55); RtlFillMemory(&Mutex, sizeof Mutex, 0x55);
KeInitializeGuardedMutex(&Mutex); pKeInitializeGuardedMutex(&Mutex);
TestGuardedMutexConcurrent(&Mutex); TestGuardedMutexConcurrent(&Mutex);
} }

View file

@ -7,6 +7,13 @@
#include <kmt_test.h> #include <kmt_test.h>
static
_IRQL_requires_min_(PASSIVE_LEVEL)
_IRQL_requires_max_(DISPATCH_LEVEL)
BOOLEAN
(NTAPI
*pKeAreAllApcsDisabled)(VOID);
#define ULONGS_PER_POINTER (sizeof(PVOID) / sizeof(ULONG)) #define ULONGS_PER_POINTER (sizeof(PVOID) / sizeof(ULONG))
#define MUTANT_SIZE (2 + 6 * ULONGS_PER_POINTER) #define MUTANT_SIZE (2 + 6 * ULONGS_PER_POINTER)
@ -55,7 +62,8 @@ C_ASSERT(sizeof(KMUTANT) == MUTANT_SIZE * sizeof(ULONG));
{ \ { \
ok_eq_bool(KeAreApcsDisabled(), KernelApcsDisabled || SpecialApcsDisabled); \ ok_eq_bool(KeAreApcsDisabled(), KernelApcsDisabled || SpecialApcsDisabled); \
ok_eq_int(Thread->KernelApcDisable, KernelApcsDisabled); \ ok_eq_int(Thread->KernelApcDisable, KernelApcsDisabled); \
ok_eq_bool(KeAreAllApcsDisabled(), AllApcsDisabled); \ if (pKeAreAllApcsDisabled) \
ok_eq_bool(pKeAreAllApcsDisabled(), AllApcsDisabled); \
ok_eq_int(Thread->SpecialApcDisable, SpecialApcsDisabled); \ ok_eq_int(Thread->SpecialApcDisable, SpecialApcsDisabled); \
ok_irql(Irql); \ ok_irql(Irql); \
} while (0) } while (0)
@ -137,6 +145,12 @@ TestMutex(VOID)
START_TEST(KeMutex) START_TEST(KeMutex)
{ {
pKeAreAllApcsDisabled = KmtGetSystemRoutineAddress(L"KeAreAllApcsDisabled");
if (skip(pKeAreAllApcsDisabled != NULL, "KeAreAllApcsDisabled unavailable\n"))
{
/* We can live without this function here */
}
TestMutant(); TestMutant();
TestMutex(); TestMutex();
} }

View file

@ -20,20 +20,37 @@ __declspec(dllimport) void __stdcall KeReleaseSpinLockFromDpcLevel(unsigned long
//#define NDEBUG //#define NDEBUG
#include <debug.h> #include <debug.h>
/* TODO: these are documented for Vista+ */ static
NTKERNELAPI _Must_inspect_result_
_IRQL_requires_min_(DISPATCH_LEVEL)
_Post_satisfies_(return == 1 || return == 0)
BOOLEAN
(FASTCALL
*pKeTryToAcquireSpinLockAtDpcLevel)(
_Inout_ _Requires_lock_not_held_(*_Curr_)
_When_(return!=0, _Acquires_lock_(*_Curr_))
PKSPIN_LOCK SpinLock);
static
VOID VOID
FASTCALL (FASTCALL
KeAcquireInStackQueuedSpinLockForDpc( *pKeAcquireInStackQueuedSpinLockForDpc)(
IN OUT PKSPIN_LOCK SpinLock, IN OUT PKSPIN_LOCK SpinLock,
OUT PKLOCK_QUEUE_HANDLE LockHandle); OUT PKLOCK_QUEUE_HANDLE LockHandle);
NTKERNELAPI static
VOID VOID
FASTCALL (FASTCALL
KeReleaseInStackQueuedSpinLockForDpc( *pKeReleaseInStackQueuedSpinLockForDpc)(
IN PKLOCK_QUEUE_HANDLE LockHandle); IN PKLOCK_QUEUE_HANDLE LockHandle);
static
_Must_inspect_result_
BOOLEAN
(FASTCALL
*pKeTestSpinLock)(
_In_ PKSPIN_LOCK SpinLock);
/* TODO: multiprocessor testing */ /* TODO: multiprocessor testing */
struct _CHECK_DATA; struct _CHECK_DATA;
@ -119,8 +136,8 @@ DEFINE_ACQUIRE(AcquireForDpc, TRUE, CheckData->Irql = KeAcquireSpinLock
DEFINE_RELEASE(ReleaseForDpc, TRUE, KeReleaseSpinLockForDpc(SpinLock, CheckData->Irql)) DEFINE_RELEASE(ReleaseForDpc, TRUE, KeReleaseSpinLockForDpc(SpinLock, CheckData->Irql))
#endif #endif
DEFINE_ACQUIRE(AcquireInStackForDpc, FALSE, KeAcquireInStackQueuedSpinLockForDpc(SpinLock, &CheckData->QueueHandle)) DEFINE_ACQUIRE(AcquireInStackForDpc, FALSE, pKeAcquireInStackQueuedSpinLockForDpc(SpinLock, &CheckData->QueueHandle))
DEFINE_RELEASE(ReleaseInStackForDpc, FALSE, KeReleaseInStackQueuedSpinLockForDpc(&CheckData->QueueHandle)) DEFINE_RELEASE(ReleaseInStackForDpc, FALSE, pKeReleaseInStackQueuedSpinLockForDpc(&CheckData->QueueHandle))
#ifdef _X86_ #ifdef _X86_
DEFINE_ACQUIRE(AcquireInt, FALSE, KiAcquireSpinLock(SpinLock)) DEFINE_ACQUIRE(AcquireInt, FALSE, KiAcquireSpinLock(SpinLock))
@ -142,7 +159,7 @@ BOOLEAN TryQueuedSynch(PKSPIN_LOCK SpinLock, PCHECK_DATA CheckData) {
return Ret; return Ret;
} }
BOOLEAN TryNoRaise(PKSPIN_LOCK SpinLock, PCHECK_DATA CheckData) { BOOLEAN TryNoRaise(PKSPIN_LOCK SpinLock, PCHECK_DATA CheckData) {
BOOLEAN Ret = KeTryToAcquireSpinLockAtDpcLevel(SpinLock); BOOLEAN Ret = pKeTryToAcquireSpinLockAtDpcLevel(SpinLock);
return Ret; return Ret;
} }
@ -197,7 +214,7 @@ BOOLEAN TryNoRaise(PKSPIN_LOCK SpinLock, PCHECK_DATA CheckData) {
#define CheckSpinLock(SpinLock, CheckData, Value) do \ #define CheckSpinLock(SpinLock, CheckData, Value) do \
{ \ { \
BOOLEAN Ret = SpinLock ? KeTestSpinLock(SpinLock) : TRUE; \ BOOLEAN Ret = SpinLock && pKeTestSpinLock ? pKeTestSpinLock(SpinLock) : TRUE; \
KIRQL ExpectedIrql = (CheckData)->OriginalIrql; \ KIRQL ExpectedIrql = (CheckData)->OriginalIrql; \
\ \
switch ((CheckData)->Check) \ switch ((CheckData)->Check) \
@ -257,7 +274,10 @@ TestSpinLock(
} }
if (CheckData->AcquireNoRaise && if (CheckData->AcquireNoRaise &&
(CheckData->OriginalIrql >= DISPATCH_LEVEL || !KmtIsCheckedBuild)) (CheckData->OriginalIrql >= DISPATCH_LEVEL || !KmtIsCheckedBuild) &&
(CheckData->AcquireNoRaise != AcquireInStackForDpc ||
!skip(pKeAcquireInStackQueuedSpinLockForDpc &&
pKeReleaseInStackQueuedSpinLockForDpc, "No DPC spinlock functions\n")))
{ {
/* acquire/release without irql change */ /* acquire/release without irql change */
CheckData->AcquireNoRaise(SpinLock, CheckData); CheckData->AcquireNoRaise(SpinLock, CheckData);
@ -279,7 +299,8 @@ TestSpinLock(
CheckData->IsAcquired = FALSE; CheckData->IsAcquired = FALSE;
KmtSetIrql(CheckData->OriginalIrql); KmtSetIrql(CheckData->OriginalIrql);
if (CheckData->TryAcquireNoRaise) if (CheckData->TryAcquireNoRaise &&
!skip(pKeTryToAcquireSpinLockAtDpcLevel != NULL, "KeTryToAcquireSpinLockAtDpcLevel unavailable\n"))
{ {
CheckSpinLock(SpinLock, CheckData, 0); CheckSpinLock(SpinLock, CheckData, 0);
ok_bool_true(CheckData->TryAcquireNoRaise(SpinLock, CheckData), "TryAcquireNoRaise returned"); ok_bool_true(CheckData->TryAcquireNoRaise(SpinLock, CheckData), "TryAcquireNoRaise returned");
@ -320,7 +341,14 @@ START_TEST(KeSpinLock)
{ CheckQueue, SynchIrql, AcquireQueuedSynch, ReleaseQueued, TryQueuedSynch, NULL, NULL, NULL, LockQueuePfnLock }, { CheckQueue, SynchIrql, AcquireQueuedSynch, ReleaseQueued, TryQueuedSynch, NULL, NULL, NULL, LockQueuePfnLock },
}; };
int i, iIrql; int i, iIrql;
PKPRCB Prcb = KeGetCurrentPrcb(); PKPRCB Prcb;
pKeTryToAcquireSpinLockAtDpcLevel = KmtGetSystemRoutineAddress(L"KeTryToAcquireSpinLockAtDpcLevel");
pKeAcquireInStackQueuedSpinLockForDpc = KmtGetSystemRoutineAddress(L"KeAcquireInStackQueuedSpinLockForDpc");
pKeReleaseInStackQueuedSpinLockForDpc = KmtGetSystemRoutineAddress(L"KeReleaseInStackQueuedSpinLockForDpc");
pKeTestSpinLock = KmtGetSystemRoutineAddress(L"KeTestSpinLock");
Prcb = KeGetCurrentPrcb();
/* KeInitializeSpinLock */ /* KeInitializeSpinLock */
memset(&SpinLock, 0x55, sizeof SpinLock); memset(&SpinLock, 0x55, sizeof SpinLock);
@ -328,17 +356,20 @@ START_TEST(KeSpinLock)
ok_eq_ulongptr(SpinLock, 0); ok_eq_ulongptr(SpinLock, 0);
/* KeTestSpinLock */ /* KeTestSpinLock */
ok_bool_true(KeTestSpinLock(&SpinLock), "KeTestSpinLock returned"); if (!skip(pKeTestSpinLock != NULL, "KeTestSpinLock unavailable\n"))
SpinLock = 1; {
ok_bool_false(KeTestSpinLock(&SpinLock), "KeTestSpinLock returned"); ok_bool_true(pKeTestSpinLock(&SpinLock), "KeTestSpinLock returned");
SpinLock = 2; SpinLock = 1;
ok_bool_false(KeTestSpinLock(&SpinLock), "KeTestSpinLock returned"); ok_bool_false(pKeTestSpinLock(&SpinLock), "KeTestSpinLock returned");
SpinLock = (ULONG_PTR)-1; SpinLock = 2;
ok_bool_false(KeTestSpinLock(&SpinLock), "KeTestSpinLock returned"); ok_bool_false(pKeTestSpinLock(&SpinLock), "KeTestSpinLock returned");
SpinLock = (ULONG_PTR)1 << (sizeof(ULONG_PTR) * CHAR_BIT - 1); SpinLock = (ULONG_PTR)-1;
ok_bool_false(KeTestSpinLock(&SpinLock), "KeTestSpinLock returned"); ok_bool_false(pKeTestSpinLock(&SpinLock), "KeTestSpinLock returned");
SpinLock = 0; SpinLock = (ULONG_PTR)1 << (sizeof(ULONG_PTR) * CHAR_BIT - 1);
ok_bool_true(KeTestSpinLock(&SpinLock), "KeTestSpinLock returned"); ok_bool_false(pKeTestSpinLock(&SpinLock), "KeTestSpinLock returned");
SpinLock = 0;
ok_bool_true(pKeTestSpinLock(&SpinLock), "KeTestSpinLock returned");
}
/* on UP none of the following functions actually looks at the spinlock! */ /* on UP none of the following functions actually looks at the spinlock! */
if (!KmtIsMultiProcessorBuild && !KmtIsCheckedBuild) if (!KmtIsMultiProcessorBuild && !KmtIsCheckedBuild)