* Sync with trunk r64401.
[reactos.git] / ntoskrnl / ex / uuid.c
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 */