2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/ex/uuid.c
5 * PURPOSE: UUID generator
6 * PROGRAMMERS: Eric Kohl
10 /* INCLUDES *****************************************************************/
16 #define SEED_BUFFER_SIZE 6
18 /* Number of 100ns ticks per clock tick. To be safe, assume that the clock
19 resolution is at least 1000 * 100 * (1/1000000) = 1/10 of a second */
20 #define TICKS_PER_CLOCK_TICK 1000
21 #define SECSPERDAY 86400
22 #define TICKSPERSEC 10000000
24 /* UUID system time starts at October 15, 1582 */
25 #define SECS_15_OCT_1582_TO_1601 ((17 + 30 + 31 + 365 * 18 + 5) * SECSPERDAY)
26 #define TICKS_15_OCT_1582_TO_1601 ((ULONGLONG)SECS_15_OCT_1582_TO_1601 * TICKSPERSEC)
28 #if defined (ALLOC_PRAGMA)
29 #pragma alloc_text(INIT, ExpInitUuids)
33 /* GLOBALS ****************************************************************/
35 static FAST_MUTEX ExpUuidLock
;
36 static ULARGE_INTEGER UuidLastTime
;
37 static ULONG UuidSequence
;
38 static BOOLEAN UuidSequenceInitialized
= FALSE
;
39 static BOOLEAN UuidSequenceChanged
= FALSE
;
40 static UCHAR UuidSeed
[SEED_BUFFER_SIZE
];
41 static ULONG UuidCount
;
42 static LARGE_INTEGER LuidIncrement
;
43 static LARGE_INTEGER LuidValue
;
45 /* FUNCTIONS ****************************************************************/
52 ExInitializeFastMutex(&ExpUuidLock
);
54 KeQuerySystemTime((PLARGE_INTEGER
)&UuidLastTime
);
55 UuidLastTime
.QuadPart
+= TICKS_15_OCT_1582_TO_1601
;
57 UuidCount
= TICKS_PER_CLOCK_TICK
;
58 RtlZeroMemory(UuidSeed
, SEED_BUFFER_SIZE
);
62 #define VALUE_BUFFER_SIZE 256
65 ExpLoadUuidSequence(PULONG Sequence
)
67 UCHAR ValueBuffer
[VALUE_BUFFER_SIZE
];
68 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo
;
69 OBJECT_ATTRIBUTES ObjectAttributes
;
75 RtlInitUnicodeString(&Name
,
76 L
"\\Registry\\Machine\\Software\\Microsoft\\Rpc");
77 InitializeObjectAttributes(&ObjectAttributes
,
82 Status
= ZwOpenKey(&KeyHandle
,
85 if (!NT_SUCCESS(Status
))
87 DPRINT("ZwOpenKey() failed (Status %lx)\n", Status
);
91 RtlInitUnicodeString(&Name
, L
"UuidSequenceNumber");
93 ValueInfo
= (PKEY_VALUE_PARTIAL_INFORMATION
)ValueBuffer
;
94 Status
= ZwQueryValueKey(KeyHandle
,
96 KeyValuePartialInformation
,
101 if (!NT_SUCCESS(Status
))
103 DPRINT("ZwQueryValueKey() failed (Status %lx)\n", Status
);
107 *Sequence
= *((PULONG
)ValueInfo
->Data
);
109 DPRINT("Loaded sequence %lx\n", *Sequence
);
111 return STATUS_SUCCESS
;
113 #undef VALUE_BUFFER_SIZE
117 ExpSaveUuidSequence(PULONG Sequence
)
119 OBJECT_ATTRIBUTES ObjectAttributes
;
124 RtlInitUnicodeString(&Name
,
125 L
"\\Registry\\Machine\\Software\\Microsoft\\Rpc");
126 InitializeObjectAttributes(&ObjectAttributes
,
128 OBJ_CASE_INSENSITIVE
,
131 Status
= ZwOpenKey(&KeyHandle
,
134 if (!NT_SUCCESS(Status
))
136 DPRINT("ZwOpenKey() failed (Status %lx)\n", Status
);
140 RtlInitUnicodeString(&Name
, L
"UuidSequenceNumber");
141 Status
= ZwSetValueKey(KeyHandle
,
148 if (!NT_SUCCESS(Status
))
150 DPRINT("ZwSetValueKey() failed (Status %lx)\n", Status
);
158 ExpGetRandomUuidSequence(PULONG Sequence
)
160 LARGE_INTEGER Counter
;
161 LARGE_INTEGER Frequency
;
164 Counter
= KeQueryPerformanceCounter(&Frequency
);
165 Value
= Counter
.u
.LowPart
^ Counter
.u
.HighPart
;
167 *Sequence
= *Sequence
^ Value
;
169 DPRINT("Sequence %lx\n", *Sequence
);
174 ExpCreateUuids(PULARGE_INTEGER Time
,
179 * Generate time element of the UUID. Account for going faster
180 * than our clock as well as the clock going backwards.
184 KeQuerySystemTime((PLARGE_INTEGER
)Time
);
185 Time
->QuadPart
+= TICKS_15_OCT_1582_TO_1601
;
187 if (Time
->QuadPart
> UuidLastTime
.QuadPart
)
193 if (Time
->QuadPart
< UuidLastTime
.QuadPart
)
196 UuidSequenceChanged
= TRUE
;
201 if (UuidCount
< TICKS_PER_CLOCK_TICK
)
208 UuidLastTime
.QuadPart
= Time
->QuadPart
;
209 Time
->QuadPart
+= UuidCount
;
211 *Range
= 10000; /* What does this mean? Ticks per millisecond?*/
213 return STATUS_SUCCESS
;
221 LUID DummyLuidValue
= SYSTEM_LUID
;
223 LuidValue
.u
.HighPart
= DummyLuidValue
.HighPart
;
224 LuidValue
.u
.LowPart
= DummyLuidValue
.LowPart
;
225 LuidIncrement
.QuadPart
= 1;
231 ExAllocateLocallyUniqueId(OUT LUID
*LocallyUniqueId
)
233 LARGE_INTEGER NewLuid
, PrevLuid
;
235 /* atomically increment the luid */
238 PrevLuid
= LuidValue
;
239 NewLuid
= RtlLargeIntegerAdd(PrevLuid
,
241 } while(ExInterlockedCompareExchange64(&LuidValue
.QuadPart
,
244 NULL
) != PrevLuid
.QuadPart
);
246 LocallyUniqueId
->LowPart
= NewLuid
.u
.LowPart
;
247 LocallyUniqueId
->HighPart
= NewLuid
.u
.HighPart
;
256 NtAllocateLocallyUniqueId(OUT LUID
*LocallyUniqueId
)
259 KPROCESSOR_MODE PreviousMode
;
263 /* Probe if user mode */
264 PreviousMode
= ExGetPreviousMode();
265 if (PreviousMode
!= KernelMode
)
269 ProbeForWrite(LocallyUniqueId
,
273 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
275 _SEH2_YIELD(return _SEH2_GetExceptionCode());
280 /* Do the allocation */
281 ExAllocateLocallyUniqueId(&NewLuid
);
282 Status
= STATUS_SUCCESS
;
284 /* Write back LUID to caller */
287 *LocallyUniqueId
= NewLuid
;
289 _SEH2_EXCEPT(ExSystemExceptionFilter())
291 Status
= _SEH2_GetExceptionCode();
302 ExUuidCreate(OUT UUID
*Uuid
)
313 NtAllocateUuids(OUT PULARGE_INTEGER Time
,
318 ULARGE_INTEGER IntTime
;
321 KPROCESSOR_MODE PreviousMode
;
325 /* Probe if user mode */
326 PreviousMode
= ExGetPreviousMode();
327 if (PreviousMode
!= KernelMode
)
332 sizeof(ULARGE_INTEGER
),
339 ProbeForWrite(Sequence
,
347 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
349 _SEH2_YIELD(return _SEH2_GetExceptionCode());
354 ExAcquireFastMutex(&ExpUuidLock
);
356 if (!UuidSequenceInitialized
)
358 Status
= ExpLoadUuidSequence(&UuidSequence
);
359 if (NT_SUCCESS(Status
))
365 ExpGetRandomUuidSequence(&UuidSequence
);
368 UuidSequenceInitialized
= TRUE
;
369 UuidSequenceChanged
= TRUE
;
372 Status
= ExpCreateUuids(&IntTime
,
375 if (!NT_SUCCESS(Status
))
377 ExReleaseFastMutex(&ExpUuidLock
);
381 if (UuidSequenceChanged
)
383 Status
= ExpSaveUuidSequence(&UuidSequence
);
384 if (NT_SUCCESS(Status
))
385 UuidSequenceChanged
= FALSE
;
388 ExReleaseFastMutex(&ExpUuidLock
);
390 /* Write back UUIDs to caller */
393 Time
->QuadPart
= IntTime
.QuadPart
;
395 *Sequence
= UuidSequence
;
401 Status
= STATUS_SUCCESS
;
403 _SEH2_EXCEPT(ExSystemExceptionFilter())
405 Status
= _SEH2_GetExceptionCode();
418 NtSetUuidSeed(IN PUCHAR Seed
)
423 SECURITY_SUBJECT_CONTEXT SubjectContext
;
424 LUID CallerLuid
, SystemLuid
= SYSTEM_LUID
;
428 /* Should only be done by umode */
429 ASSERT(KeGetPreviousMode() != KernelMode
);
431 /* No context to release */
435 /* Get our caller context and remember to release it */
436 SeCaptureSubjectContext(&SubjectContext
);
439 /* Get caller access token and its associated ID */
440 Token
= SeQuerySubjectContextToken(&SubjectContext
);
441 Status
= SeQueryAuthenticationIdToken(Token
, &CallerLuid
);
442 if (!NT_SUCCESS(Status
))
444 RtlRaiseStatus(Status
);
447 /* This call is only allowed for SYSTEM */
448 if (!RtlEqualLuid(&CallerLuid
, &SystemLuid
))
450 RtlRaiseStatus(STATUS_ACCESS_DENIED
);
453 /* Check for buffer validity and then copy it to our seed */
454 ProbeForRead(Seed
, SEED_BUFFER_SIZE
, sizeof(UCHAR
));
455 RtlCopyMemory(UuidSeed
, Seed
, SEED_BUFFER_SIZE
);
457 Status
= STATUS_SUCCESS
;
459 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
461 Status
= _SEH2_GetExceptionCode();
465 /* Release context if required */
468 SeReleaseSubjectContext(&SubjectContext
);