xref: /reactos/ntoskrnl/ex/uuid.c (revision 25720d75)
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