1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS kernel 4 * FILE: ntoskrnl/ex/uuid.c 5 * PURPOSE: UUID generator 6 * 7 * PROGRAMMERS: Eric Kohl 8 Thomas Weidenmueller 9 */ 10 11 /* INCLUDES *****************************************************************/ 12 13 #include <ntoskrnl.h> 14 #define NDEBUG 15 #include <debug.h> 16 17 #define SEED_BUFFER_SIZE 6 18 19 /* Number of 100ns ticks per clock tick. To be safe, assume that the clock 20 resolution is at least 1000 * 100 * (1/1000000) = 1/10 of a second */ 21 #define TICKS_PER_CLOCK_TICK 1000 22 #define SECSPERDAY 86400 23 #define TICKSPERSEC 10000000 24 25 /* UUID system time starts at October 15, 1582 */ 26 #define SECS_15_OCT_1582_TO_1601 ((17 + 30 + 31 + 365 * 18 + 5) * SECSPERDAY) 27 #define TICKS_15_OCT_1582_TO_1601 ((ULONGLONG)SECS_15_OCT_1582_TO_1601 * TICKSPERSEC) 28 29 #if defined (ALLOC_PRAGMA) 30 #pragma alloc_text(INIT, ExpInitUuids) 31 #endif 32 33 34 /* GLOBALS ****************************************************************/ 35 36 static FAST_MUTEX UuidMutex; 37 static ULARGE_INTEGER UuidLastTime; 38 static ULONG UuidSequence; 39 static BOOLEAN UuidSequenceInitialized = FALSE; 40 static BOOLEAN UuidSequenceChanged = FALSE; 41 static UCHAR UuidSeed[SEED_BUFFER_SIZE]; 42 static ULONG UuidCount; 43 static LARGE_INTEGER LuidIncrement; 44 static LARGE_INTEGER LuidValue; 45 46 /* FUNCTIONS ****************************************************************/ 47 48 VOID 49 INIT_FUNCTION 50 NTAPI 51 ExpInitUuids(VOID) 52 { 53 ExInitializeFastMutex(&UuidMutex); 54 55 KeQuerySystemTime((PLARGE_INTEGER)&UuidLastTime); 56 UuidLastTime.QuadPart += TICKS_15_OCT_1582_TO_1601; 57 58 UuidCount = TICKS_PER_CLOCK_TICK; 59 RtlZeroMemory(UuidSeed, SEED_BUFFER_SIZE); 60 } 61 62 63 #define VALUE_BUFFER_SIZE 256 64 65 static NTSTATUS 66 ExpLoadUuidSequence(PULONG Sequence) 67 { 68 UCHAR ValueBuffer[VALUE_BUFFER_SIZE]; 69 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo; 70 OBJECT_ATTRIBUTES ObjectAttributes; 71 UNICODE_STRING Name; 72 HANDLE KeyHandle; 73 ULONG ValueLength; 74 NTSTATUS Status; 75 76 RtlInitUnicodeString(&Name, 77 L"\\Registry\\Machine\\Software\\Microsoft\\Rpc"); 78 InitializeObjectAttributes(&ObjectAttributes, 79 &Name, 80 OBJ_CASE_INSENSITIVE, 81 NULL, 82 NULL); 83 Status = ZwOpenKey(&KeyHandle, 84 KEY_QUERY_VALUE, 85 &ObjectAttributes); 86 if (!NT_SUCCESS(Status)) 87 { 88 DPRINT("ZwOpenKey() failed (Status %lx)\n", Status); 89 return Status; 90 } 91 92 RtlInitUnicodeString(&Name, L"UuidSequenceNumber"); 93 94 ValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)ValueBuffer; 95 Status = ZwQueryValueKey(KeyHandle, 96 &Name, 97 KeyValuePartialInformation, 98 ValueBuffer, 99 VALUE_BUFFER_SIZE, 100 &ValueLength); 101 ZwClose(KeyHandle); 102 if (!NT_SUCCESS(Status)) 103 { 104 DPRINT("ZwQueryValueKey() failed (Status %lx)\n", Status); 105 return Status; 106 } 107 108 *Sequence = *((PULONG)ValueInfo->Data); 109 110 DPRINT("Loaded sequence %lx\n", *Sequence); 111 112 return STATUS_SUCCESS; 113 } 114 #undef VALUE_BUFFER_SIZE 115 116 117 static NTSTATUS 118 ExpSaveUuidSequence(PULONG Sequence) 119 { 120 OBJECT_ATTRIBUTES ObjectAttributes; 121 UNICODE_STRING Name; 122 HANDLE KeyHandle; 123 NTSTATUS Status; 124 125 RtlInitUnicodeString(&Name, 126 L"\\Registry\\Machine\\Software\\Microsoft\\Rpc"); 127 InitializeObjectAttributes(&ObjectAttributes, 128 &Name, 129 OBJ_CASE_INSENSITIVE, 130 NULL, 131 NULL); 132 Status = ZwOpenKey(&KeyHandle, 133 KEY_SET_VALUE, 134 &ObjectAttributes); 135 if (!NT_SUCCESS(Status)) 136 { 137 DPRINT("ZwOpenKey() failed (Status %lx)\n", Status); 138 return Status; 139 } 140 141 RtlInitUnicodeString(&Name, L"UuidSequenceNumber"); 142 Status = ZwSetValueKey(KeyHandle, 143 &Name, 144 0, 145 REG_DWORD, 146 Sequence, 147 sizeof(ULONG)); 148 ZwClose(KeyHandle); 149 if (!NT_SUCCESS(Status)) 150 { 151 DPRINT("ZwSetValueKey() failed (Status %lx)\n", Status); 152 } 153 154 return Status; 155 } 156 157 158 static VOID 159 ExpGetRandomUuidSequence(PULONG Sequence) 160 { 161 LARGE_INTEGER Counter; 162 LARGE_INTEGER Frequency; 163 ULONG Value; 164 165 Counter = KeQueryPerformanceCounter(&Frequency); 166 Value = Counter.u.LowPart ^ Counter.u.HighPart; 167 168 *Sequence = *Sequence ^ Value; 169 170 DPRINT("Sequence %lx\n", *Sequence); 171 } 172 173 174 static NTSTATUS 175 ExpCreateUuids(PULARGE_INTEGER Time, 176 PULONG Range, 177 PULONG Sequence) 178 { 179 /* 180 * Generate time element of the UUID. Account for going faster 181 * than our clock as well as the clock going backwards. 182 */ 183 while (1) 184 { 185 KeQuerySystemTime((PLARGE_INTEGER)Time); 186 Time->QuadPart += TICKS_15_OCT_1582_TO_1601; 187 188 if (Time->QuadPart > UuidLastTime.QuadPart) 189 { 190 UuidCount = 0; 191 break; 192 } 193 194 if (Time->QuadPart < UuidLastTime.QuadPart) 195 { 196 (*Sequence)++; 197 UuidSequenceChanged = TRUE; 198 UuidCount = 0; 199 break; 200 } 201 202 if (UuidCount < TICKS_PER_CLOCK_TICK) 203 { 204 UuidCount++; 205 break; 206 } 207 } 208 209 UuidLastTime.QuadPart = Time->QuadPart; 210 Time->QuadPart += UuidCount; 211 212 *Range = 10000; /* What does this mean? Ticks per millisecond?*/ 213 214 return STATUS_SUCCESS; 215 } 216 217 VOID 218 INIT_FUNCTION 219 NTAPI 220 ExpInitLuid(VOID) 221 { 222 LUID DummyLuidValue = SYSTEM_LUID; 223 224 LuidValue.u.HighPart = DummyLuidValue.HighPart; 225 LuidValue.u.LowPart = DummyLuidValue.LowPart; 226 LuidIncrement.QuadPart = 1; 227 } 228 229 230 NTSTATUS 231 NTAPI 232 ExpAllocateLocallyUniqueId(OUT LUID *LocallyUniqueId) 233 { 234 LARGE_INTEGER NewLuid, PrevLuid; 235 236 /* atomically increment the luid */ 237 do 238 { 239 PrevLuid = LuidValue; 240 NewLuid = RtlLargeIntegerAdd(PrevLuid, 241 LuidIncrement); 242 } while(ExInterlockedCompareExchange64(&LuidValue.QuadPart, 243 &NewLuid.QuadPart, 244 &PrevLuid.QuadPart, 245 NULL) != PrevLuid.QuadPart); 246 247 LocallyUniqueId->LowPart = NewLuid.u.LowPart; 248 LocallyUniqueId->HighPart = NewLuid.u.HighPart; 249 250 return STATUS_SUCCESS; 251 } 252 253 254 /* 255 * @implemented 256 */ 257 NTSTATUS NTAPI 258 NtAllocateLocallyUniqueId(OUT LUID *LocallyUniqueId) 259 { 260 LUID NewLuid; 261 KPROCESSOR_MODE PreviousMode; 262 NTSTATUS Status; 263 264 PAGED_CODE(); 265 266 PreviousMode = ExGetPreviousMode(); 267 268 if(PreviousMode != KernelMode) 269 { 270 _SEH2_TRY 271 { 272 ProbeForWrite(LocallyUniqueId, 273 sizeof(LUID), 274 sizeof(ULONG)); 275 } 276 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 277 { 278 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 279 } 280 _SEH2_END; 281 } 282 283 Status = ExpAllocateLocallyUniqueId(&NewLuid); 284 285 _SEH2_TRY 286 { 287 *LocallyUniqueId = NewLuid; 288 } 289 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 290 { 291 Status = _SEH2_GetExceptionCode(); 292 } 293 _SEH2_END; 294 295 return Status; 296 } 297 298 /* 299 * @unimplemented 300 */ 301 NTSTATUS 302 NTAPI 303 ExUuidCreate(OUT UUID *Uuid) 304 { 305 UNIMPLEMENTED; 306 return FALSE; 307 } 308 309 /* 310 * @unimplemented 311 */ 312 NTSTATUS 313 NTAPI 314 NtAllocateUuids(OUT PULARGE_INTEGER Time, 315 OUT PULONG Range, 316 OUT PULONG Sequence, 317 OUT PUCHAR Seed) 318 { 319 ULARGE_INTEGER IntTime; 320 ULONG IntRange; 321 NTSTATUS Status; 322 323 PAGED_CODE(); 324 325 ExAcquireFastMutex(&UuidMutex); 326 327 if (!UuidSequenceInitialized) 328 { 329 Status = ExpLoadUuidSequence(&UuidSequence); 330 if (NT_SUCCESS(Status)) 331 { 332 UuidSequence++; 333 } 334 else 335 { 336 ExpGetRandomUuidSequence(&UuidSequence); 337 } 338 339 UuidSequenceInitialized = TRUE; 340 UuidSequenceChanged = TRUE; 341 } 342 343 Status = ExpCreateUuids(&IntTime, 344 &IntRange, 345 &UuidSequence); 346 if (!NT_SUCCESS(Status)) 347 { 348 ExReleaseFastMutex(&UuidMutex); 349 return Status; 350 } 351 352 if (UuidSequenceChanged) 353 { 354 Status = ExpSaveUuidSequence(&UuidSequence); 355 if (NT_SUCCESS(Status)) 356 UuidSequenceChanged = FALSE; 357 } 358 359 ExReleaseFastMutex(&UuidMutex); 360 361 Time->QuadPart = IntTime.QuadPart; 362 *Range = IntRange; 363 *Sequence = UuidSequence; 364 365 RtlCopyMemory(Seed, 366 UuidSeed, 367 SEED_BUFFER_SIZE); 368 369 return STATUS_SUCCESS; 370 } 371 372 373 /* 374 * @implemented 375 */ 376 NTSTATUS 377 NTAPI 378 NtSetUuidSeed(IN PUCHAR Seed) 379 { 380 PAGED_CODE(); 381 382 RtlCopyMemory(UuidSeed, 383 Seed, 384 SEED_BUFFER_SIZE); 385 return STATUS_SUCCESS; 386 } 387 388 /* EOF */ 389