1 /* 2 * PROJECT: ReactOS Kernel 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: ntoskrnl/include/internal/cm_x.h 5 * PURPOSE: Inlined Functions for the Configuration Manager 6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) 7 */ 8 9 // 10 // Returns the hashkey corresponding to a convkey 11 // 12 #define GET_HASH_KEY(ConvKey) \ 13 ((CMP_HASH_IRRATIONAL * (ConvKey)) % CMP_HASH_PRIME) 14 15 // 16 // Computes the hashkey of a character 17 // 18 #define COMPUTE_HASH_CHAR(ConvKey, Char) \ 19 (37 * ConvKey + RtlUpcaseUnicodeChar(Char)) 20 21 // 22 // Returns the index into the hash table, or the entry itself 23 // 24 #define GET_HASH_INDEX(ConvKey) \ 25 (GET_HASH_KEY(ConvKey) % CmpHashTableSize) 26 #define GET_HASH_ENTRY(Table, ConvKey) \ 27 (&Table[GET_HASH_INDEX(ConvKey)]) 28 #define ASSERT_VALID_HASH(h) \ 29 ASSERT_KCB_VALID(CONTAINING_RECORD((h), CM_KEY_CONTROL_BLOCK, KeyHash)) 30 31 // 32 // Returns whether or not the cell is cached 33 // 34 #define CMP_IS_CELL_CACHED(c) \ 35 (((c) & HCELL_CACHED) && ((c) != HCELL_NIL)) 36 37 // 38 // Return data from a cached cell 39 // 40 #define CMP_GET_CACHED_CELL(c) \ 41 (ULONG_PTR)((c) & ~HCELL_CACHED) 42 #define CMP_GET_CACHED_DATA(c) \ 43 (&(((PCM_CACHED_VALUE_INDEX)(CMP_GET_CACHED_CELL(c)))->Data.CellData)) 44 #define CMP_GET_CACHED_INDEX(c) \ 45 (&(((PCM_CACHED_ENTRY)(CMP_GET_CACHED_CELL(c)))->CellIndex)) 46 #define CMP_GET_CACHED_VALUE(c) \ 47 (&(((PCM_CACHED_VALUE)(CMP_GET_CACHED_CELL(c)))->KeyValue)) 48 49 // 50 // Makes sure that the registry is locked 51 // 52 #define CMP_ASSERT_REGISTRY_LOCK() \ 53 ASSERT((CmpSpecialBootCondition == TRUE) || \ 54 (CmpTestRegistryLock() == TRUE)) 55 56 // 57 // Makes sure that the registry is locked or loading 58 // 59 #define CMP_ASSERT_REGISTRY_LOCK_OR_LOADING(h) \ 60 ASSERT((CmpSpecialBootCondition == TRUE) || \ 61 (((PCMHIVE)h)->HiveIsLoading == TRUE) || \ 62 (CmpTestRegistryLock() == TRUE)) 63 64 // 65 // Makes sure that the registry is exclusively locked 66 // 67 #define CMP_ASSERT_EXCLUSIVE_REGISTRY_LOCK() \ 68 ASSERT((CmpSpecialBootCondition == TRUE) || \ 69 (CmpTestRegistryLockExclusive() == TRUE)) 70 71 // 72 // Makes sure that the registry is exclusively locked or loading 73 // 74 #define CMP_ASSERT_EXCLUSIVE_REGISTRY_LOCK_OR_LOADING(h) \ 75 ASSERT((CmpSpecialBootCondition == TRUE) || \ 76 (((PCMHIVE)h)->HiveIsLoading == TRUE) || \ 77 (CmpTestRegistryLockExclusive() == TRUE)) 78 79 // 80 // Makes sure this is a valid KCB 81 // 82 #define ASSERT_KCB_VALID(k) \ 83 ASSERT((k)->Signature == CM_KCB_SIGNATURE) 84 85 // 86 // Checks if a KCB is exclusively locked 87 // 88 #define CmpIsKcbLockedExclusive(k) \ 89 (GET_HASH_ENTRY(CmpCacheTable, \ 90 (k)->ConvKey)->Owner == KeGetCurrentThread()) 91 92 // 93 // Shared acquires a KCB by index 94 // 95 #define CmpAcquireKcbLockSharedByIndex(i) \ 96 { \ 97 ExAcquirePushLockShared(&CmpCacheTable[(i)].Lock); \ 98 } 99 100 // 101 // Exclusively acquires a KCB by index 102 // 103 FORCEINLINE 104 VOID 105 CmpAcquireKcbLockExclusiveByIndex(ULONG Index) 106 { 107 ExAcquirePushLockExclusive(&CmpCacheTable[Index].Lock); 108 CmpCacheTable[Index].Owner = KeGetCurrentThread(); 109 } 110 111 // 112 // Exclusively acquires a KCB 113 // 114 FORCEINLINE 115 VOID 116 CmpAcquireKcbLockExclusive(PCM_KEY_CONTROL_BLOCK Kcb) 117 { 118 CmpAcquireKcbLockExclusiveByIndex(GET_HASH_INDEX(Kcb->ConvKey)); 119 } 120 121 // 122 // Exclusively acquires a KCB by key 123 // 124 FORCEINLINE 125 VOID 126 CmpAcquireKcbLockExclusiveByKey(IN ULONG ConvKey) 127 { 128 CmpAcquireKcbLockExclusiveByIndex(GET_HASH_INDEX(ConvKey)); 129 } 130 131 // 132 // Shared acquires a KCB by key 133 // 134 FORCEINLINE 135 VOID 136 CmpAcquireKcbLockSharedByKey( 137 _In_ ULONG ConvKey) 138 { 139 CmpAcquireKcbLockSharedByIndex(GET_HASH_INDEX(ConvKey)); 140 } 141 142 // 143 // Shared acquires a KCB 144 // 145 #define CmpAcquireKcbLockShared(k) \ 146 { \ 147 ExAcquirePushLockShared(&GET_HASH_ENTRY(CmpCacheTable, \ 148 (k)->ConvKey)->Lock); \ 149 } 150 151 // 152 // Tries to convert a KCB lock 153 // 154 FORCEINLINE 155 BOOLEAN 156 CmpTryToConvertKcbSharedToExclusive(IN PCM_KEY_CONTROL_BLOCK k) 157 { 158 ASSERT(CmpIsKcbLockedExclusive(k) == FALSE); 159 if (ExConvertPushLockSharedToExclusive( 160 &GET_HASH_ENTRY(CmpCacheTable, k->ConvKey)->Lock)) 161 { 162 GET_HASH_ENTRY(CmpCacheTable, 163 k->ConvKey)->Owner = KeGetCurrentThread(); 164 return TRUE; 165 } 166 return FALSE; 167 } 168 169 // 170 // Releases an exlusively or shared acquired KCB by index 171 // 172 FORCEINLINE 173 VOID 174 CmpReleaseKcbLockByIndex(ULONG Index) 175 { 176 CmpCacheTable[Index].Owner = NULL; 177 ExReleasePushLock(&CmpCacheTable[Index].Lock); 178 } 179 180 // 181 // Releases an exlusively or shared acquired KCB 182 // 183 FORCEINLINE 184 VOID 185 CmpReleaseKcbLock(PCM_KEY_CONTROL_BLOCK Kcb) 186 { 187 CmpReleaseKcbLockByIndex(GET_HASH_INDEX(Kcb->ConvKey)); 188 } 189 190 // 191 // Releases an exlusively or shared acquired KCB by key 192 // 193 FORCEINLINE 194 VOID 195 CmpReleaseKcbLockByKey(ULONG ConvKey) 196 { 197 CmpReleaseKcbLockByIndex(GET_HASH_INDEX(ConvKey)); 198 } 199 200 // 201 // Converts a KCB lock 202 // 203 FORCEINLINE 204 VOID 205 CmpConvertKcbSharedToExclusive(IN PCM_KEY_CONTROL_BLOCK k) 206 { 207 ASSERT(CmpIsKcbLockedExclusive(k) == FALSE); 208 CmpReleaseKcbLock(k); 209 CmpAcquireKcbLockExclusive(k); 210 } 211 212 // 213 // Exclusively acquires an NCB 214 // 215 #define CmpAcquireNcbLockExclusive(n) \ 216 { \ 217 ExAcquirePushLockExclusive(&GET_HASH_ENTRY(CmpNameCacheTable, \ 218 (n)->ConvKey)->Lock); \ 219 } 220 221 // 222 // Exclusively acquires an NCB by key 223 // 224 #define CmpAcquireNcbLockExclusiveByKey(k) \ 225 { \ 226 ExAcquirePushLockExclusive(&GET_HASH_ENTRY(CmpNameCacheTable, \ 227 (k))->Lock); \ 228 } 229 230 // 231 // Releases an exlusively or shared acquired NCB 232 // 233 #define CmpReleaseNcbLock(k) \ 234 { \ 235 ExReleasePushLock(&GET_HASH_ENTRY(CmpNameCacheTable, \ 236 (k)->ConvKey)->Lock); \ 237 } 238 239 // 240 // Releases an exlusively or shared acquired NCB by key 241 // 242 #define CmpReleaseNcbLockByKey(k) \ 243 { \ 244 ExReleasePushLock(&GET_HASH_ENTRY(CmpNameCacheTable, \ 245 (k))->Lock); \ 246 } 247 248 // 249 // Asserts that either the registry or the KCB is locked 250 // 251 #define CMP_ASSERT_HASH_ENTRY_LOCK(k) \ 252 { \ 253 ASSERT(((GET_HASH_ENTRY(CmpCacheTable, k)->Owner == \ 254 KeGetCurrentThread())) || \ 255 (CmpTestRegistryLockExclusive() == TRUE)); \ 256 } 257 258 // 259 // Asserts that either the registry or the KCB is locked 260 // 261 #define CMP_ASSERT_KCB_LOCK(k) \ 262 { \ 263 ASSERT((CmpIsKcbLockedExclusive(k) == TRUE) || \ 264 (CmpTestRegistryLockExclusive() == TRUE)); \ 265 } 266 267 // 268 // Gets the page attached to the KCB 269 // 270 #define CmpGetAllocPageFromKcb(k) \ 271 (PCM_ALLOC_PAGE)(((ULONG_PTR)(k)) & ~(PAGE_SIZE - 1)) 272 273 // 274 // Gets the page attached to the delayed allocation 275 // 276 #define CmpGetAllocPageFromDelayAlloc(a) \ 277 (PCM_ALLOC_PAGE)(((ULONG_PTR)(a)) & ~(PAGE_SIZE - 1)) 278 279 // 280 // Makes sure that the registry is locked for flushes 281 // 282 #define CMP_ASSERT_FLUSH_LOCK(h) \ 283 ASSERT((CmpSpecialBootCondition == TRUE) || \ 284 (((PCMHIVE)h)->HiveIsLoading == TRUE) || \ 285 (CmpTestHiveFlusherLockShared((PCMHIVE)h) == TRUE) || \ 286 (CmpTestHiveFlusherLockExclusive((PCMHIVE)h) == TRUE) || \ 287 (CmpTestRegistryLockExclusive() == TRUE)); 288