/* * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel * FILE: ntoskrnl/ex/uuid.c * PURPOSE: UUID generator * * PROGRAMMERS: Eric Kohl Thomas Weidenmueller */ /* INCLUDES *****************************************************************/ #include #define NDEBUG #include #define SEED_BUFFER_SIZE 6 /* Number of 100ns ticks per clock tick. To be safe, assume that the clock resolution is at least 1000 * 100 * (1/1000000) = 1/10 of a second */ #define TICKS_PER_CLOCK_TICK 1000 #define SECSPERDAY 86400 #define TICKSPERSEC 10000000 /* UUID system time starts at October 15, 1582 */ #define SECS_15_OCT_1582_TO_1601 ((17 + 30 + 31 + 365 * 18 + 5) * SECSPERDAY) #define TICKS_15_OCT_1582_TO_1601 ((ULONGLONG)SECS_15_OCT_1582_TO_1601 * TICKSPERSEC) #if defined (ALLOC_PRAGMA) #pragma alloc_text(INIT, ExpInitUuids) #endif /* GLOBALS ****************************************************************/ static FAST_MUTEX UuidMutex; static ULARGE_INTEGER UuidLastTime; static ULONG UuidSequence; static BOOLEAN UuidSequenceInitialized = FALSE; static BOOLEAN UuidSequenceChanged = FALSE; static UCHAR UuidSeed[SEED_BUFFER_SIZE]; static ULONG UuidCount; static LARGE_INTEGER LuidIncrement; static LARGE_INTEGER LuidValue; /* FUNCTIONS ****************************************************************/ VOID INIT_FUNCTION NTAPI ExpInitUuids(VOID) { ExInitializeFastMutex(&UuidMutex); KeQuerySystemTime((PLARGE_INTEGER)&UuidLastTime); UuidLastTime.QuadPart += TICKS_15_OCT_1582_TO_1601; UuidCount = TICKS_PER_CLOCK_TICK; RtlZeroMemory(UuidSeed, SEED_BUFFER_SIZE); } #define VALUE_BUFFER_SIZE 256 static NTSTATUS ExpLoadUuidSequence(PULONG Sequence) { UCHAR ValueBuffer[VALUE_BUFFER_SIZE]; PKEY_VALUE_PARTIAL_INFORMATION ValueInfo; OBJECT_ATTRIBUTES ObjectAttributes; UNICODE_STRING Name; HANDLE KeyHandle; ULONG ValueLength; NTSTATUS Status; RtlInitUnicodeString(&Name, L"\\Registry\\Machine\\Software\\Microsoft\\Rpc"); InitializeObjectAttributes(&ObjectAttributes, &Name, OBJ_CASE_INSENSITIVE, NULL, NULL); Status = ZwOpenKey(&KeyHandle, KEY_QUERY_VALUE, &ObjectAttributes); if (!NT_SUCCESS(Status)) { DPRINT("ZwOpenKey() failed (Status %lx)\n", Status); return Status; } RtlInitUnicodeString(&Name, L"UuidSequenceNumber"); ValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)ValueBuffer; Status = ZwQueryValueKey(KeyHandle, &Name, KeyValuePartialInformation, ValueBuffer, VALUE_BUFFER_SIZE, &ValueLength); ZwClose(KeyHandle); if (!NT_SUCCESS(Status)) { DPRINT("ZwQueryValueKey() failed (Status %lx)\n", Status); return Status; } *Sequence = *((PULONG)ValueInfo->Data); DPRINT("Loaded sequence %lx\n", *Sequence); return STATUS_SUCCESS; } #undef VALUE_BUFFER_SIZE static NTSTATUS ExpSaveUuidSequence(PULONG Sequence) { OBJECT_ATTRIBUTES ObjectAttributes; UNICODE_STRING Name; HANDLE KeyHandle; NTSTATUS Status; RtlInitUnicodeString(&Name, L"\\Registry\\Machine\\Software\\Microsoft\\Rpc"); InitializeObjectAttributes(&ObjectAttributes, &Name, OBJ_CASE_INSENSITIVE, NULL, NULL); Status = ZwOpenKey(&KeyHandle, KEY_SET_VALUE, &ObjectAttributes); if (!NT_SUCCESS(Status)) { DPRINT("ZwOpenKey() failed (Status %lx)\n", Status); return Status; } RtlInitUnicodeString(&Name, L"UuidSequenceNumber"); Status = ZwSetValueKey(KeyHandle, &Name, 0, REG_DWORD, Sequence, sizeof(ULONG)); ZwClose(KeyHandle); if (!NT_SUCCESS(Status)) { DPRINT("ZwSetValueKey() failed (Status %lx)\n", Status); } return Status; } static VOID ExpGetRandomUuidSequence(PULONG Sequence) { LARGE_INTEGER Counter; LARGE_INTEGER Frequency; ULONG Value; Counter = KeQueryPerformanceCounter(&Frequency); Value = Counter.u.LowPart ^ Counter.u.HighPart; *Sequence = *Sequence ^ Value; DPRINT("Sequence %lx\n", *Sequence); } static NTSTATUS ExpCreateUuids(PULARGE_INTEGER Time, PULONG Range, PULONG Sequence) { /* * Generate time element of the UUID. Account for going faster * than our clock as well as the clock going backwards. */ while (1) { KeQuerySystemTime((PLARGE_INTEGER)Time); Time->QuadPart += TICKS_15_OCT_1582_TO_1601; if (Time->QuadPart > UuidLastTime.QuadPart) { UuidCount = 0; break; } if (Time->QuadPart < UuidLastTime.QuadPart) { (*Sequence)++; UuidSequenceChanged = TRUE; UuidCount = 0; break; } if (UuidCount < TICKS_PER_CLOCK_TICK) { UuidCount++; break; } } UuidLastTime.QuadPart = Time->QuadPart; Time->QuadPart += UuidCount; *Range = 10000; /* What does this mean? Ticks per millisecond?*/ return STATUS_SUCCESS; } VOID INIT_FUNCTION NTAPI ExpInitLuid(VOID) { LUID DummyLuidValue = SYSTEM_LUID; LuidValue.u.HighPart = DummyLuidValue.HighPart; LuidValue.u.LowPart = DummyLuidValue.LowPart; LuidIncrement.QuadPart = 1; } VOID NTAPI ExAllocateLocallyUniqueId(OUT LUID *LocallyUniqueId) { LARGE_INTEGER NewLuid, PrevLuid; /* atomically increment the luid */ do { PrevLuid = LuidValue; NewLuid = RtlLargeIntegerAdd(PrevLuid, LuidIncrement); } while(ExInterlockedCompareExchange64(&LuidValue.QuadPart, &NewLuid.QuadPart, &PrevLuid.QuadPart, NULL) != PrevLuid.QuadPart); LocallyUniqueId->LowPart = NewLuid.u.LowPart; LocallyUniqueId->HighPart = NewLuid.u.HighPart; } /* * @implemented */ NTSTATUS NTAPI NtAllocateLocallyUniqueId(OUT LUID *LocallyUniqueId) { LUID NewLuid; KPROCESSOR_MODE PreviousMode; NTSTATUS Status; PAGED_CODE(); /* Probe if user mode */ PreviousMode = ExGetPreviousMode(); if (PreviousMode != KernelMode) { _SEH2_TRY { ProbeForWrite(LocallyUniqueId, sizeof(LUID), sizeof(ULONG)); } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { _SEH2_YIELD(return _SEH2_GetExceptionCode()); } _SEH2_END; } /* Do the allocation */ ExAllocateLocallyUniqueId(&NewLuid); Status = STATUS_SUCCESS; /* Write back LUID to caller */ _SEH2_TRY { *LocallyUniqueId = NewLuid; } _SEH2_EXCEPT(ExSystemExceptionFilter()) { Status = _SEH2_GetExceptionCode(); } _SEH2_END; return Status; } /* * @unimplemented */ NTSTATUS NTAPI ExUuidCreate(OUT UUID *Uuid) { UNIMPLEMENTED; return FALSE; } /* * @unimplemented */ NTSTATUS NTAPI NtAllocateUuids(OUT PULARGE_INTEGER Time, OUT PULONG Range, OUT PULONG Sequence, OUT PUCHAR Seed) { ULARGE_INTEGER IntTime; ULONG IntRange; NTSTATUS Status; PAGED_CODE(); ExAcquireFastMutex(&UuidMutex); if (!UuidSequenceInitialized) { Status = ExpLoadUuidSequence(&UuidSequence); if (NT_SUCCESS(Status)) { UuidSequence++; } else { ExpGetRandomUuidSequence(&UuidSequence); } UuidSequenceInitialized = TRUE; UuidSequenceChanged = TRUE; } Status = ExpCreateUuids(&IntTime, &IntRange, &UuidSequence); if (!NT_SUCCESS(Status)) { ExReleaseFastMutex(&UuidMutex); return Status; } if (UuidSequenceChanged) { Status = ExpSaveUuidSequence(&UuidSequence); if (NT_SUCCESS(Status)) UuidSequenceChanged = FALSE; } ExReleaseFastMutex(&UuidMutex); Time->QuadPart = IntTime.QuadPart; *Range = IntRange; *Sequence = UuidSequence; RtlCopyMemory(Seed, UuidSeed, SEED_BUFFER_SIZE); return STATUS_SUCCESS; } /* * @implemented */ NTSTATUS NTAPI NtSetUuidSeed(IN PUCHAR Seed) { PAGED_CODE(); RtlCopyMemory(UuidSeed, Seed, SEED_BUFFER_SIZE); return STATUS_SUCCESS; } /* EOF */