[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [win-pv-devel] [PATCH] Add registry override to prevent interception of Trim requests
Add a REG_DWORD called 'InterceptTrim' to XENDISK's parameters key (now created by xenvbd.inf). Set the value to zero to disable Trim interception. This patch also adds registry code to XENDISK, brings util.h up to date, and fixes some cosmetic issues in thread.c. Signed-off-by: Paul Durrant <paul.durrant@xxxxxxxxxx> --- src/xendisk/driver.c | 90 ++- src/xendisk/driver.h | 5 + src/xendisk/fdo.c | 2 +- src/xendisk/pdo.c | 28 +- src/xendisk/registry.c | 1492 ++++++++++++++++++++++++++++++++++++++++ src/xendisk/registry.h | 203 ++++++ src/xendisk/thread.c | 8 +- src/xendisk/util.h | 404 +++++++---- src/xenvbd.inf | 4 + vs2012/xendisk/xendisk.vcxproj | 1 + vs2013/xendisk/xendisk.vcxproj | 1 + 11 files changed, 2097 insertions(+), 141 deletions(-) create mode 100644 src/xendisk/registry.c create mode 100644 src/xendisk/registry.h diff --git a/src/xendisk/driver.c b/src/xendisk/driver.c index fb0a4b3..4b004c5 100644 --- a/src/xendisk/driver.c +++ b/src/xendisk/driver.c @@ -30,14 +30,18 @@ */ #include <ntddk.h> + +#include "registry.h" #include "driver.h" #include "util.h" #include "debug.h" #include "assert.h" + #include <version.h> typedef struct _XENDISK_DRIVER { - PDRIVER_OBJECT DriverObject; + PDRIVER_OBJECT DriverObject; + HANDLE ParametersKey; } XENDISK_DRIVER, *PXENDISK_DRIVER; static XENDISK_DRIVER Driver; @@ -66,6 +70,30 @@ DriverGetDriverObject( return __DriverGetDriverObject(); } +static FORCEINLINE VOID +__DriverSetParametersKey( + IN HANDLE Key + ) +{ + Driver.ParametersKey = Key; +} + +static FORCEINLINE HANDLE +__DriverGetParametersKey( + VOID + ) +{ + return Driver.ParametersKey; +} + +HANDLE +DriverGetParametersKey( + VOID + ) +{ + return __DriverGetParametersKey(); +} + DRIVER_UNLOAD DriverUnload; VOID @@ -73,10 +101,28 @@ DriverUnload( IN PDRIVER_OBJECT DriverObject ) { + HANDLE ParametersKey; + ASSERT3P(DriverObject, ==, __DriverGetDriverObject()); Trace("====>\n"); + ParametersKey = __DriverGetParametersKey(); + __DriverSetParametersKey(NULL); + + RegistryCloseKey(ParametersKey); + + RegistryTeardown(); + + Verbose("XENDISK %d.%d.%d (%d) (%02d.%02d.%04d)\n", + MAJOR_VERSION, + MINOR_VERSION, + MICRO_VERSION, + BUILD_NUMBER, + DAY, + MONTH, + YEAR); + __DriverSetDriverObject(NULL); ASSERT(IsZeroMemory(&Driver, sizeof (XENDISK_DRIVER))); @@ -162,7 +208,10 @@ DriverEntry( IN PUNICODE_STRING RegistryPath ) { + HANDLE ServiceKey; + HANDLE ParametersKey; ULONG Index; + NTSTATUS status; ASSERT3P(__DriverGetDriverObject(), ==, NULL); UNREFERENCED_PARAMETER(RegistryPath); @@ -184,6 +233,25 @@ DriverEntry( MONTH, YEAR); + status = RegistryInitialize(RegistryPath); + if (!NT_SUCCESS(status)) + goto fail1; + + status = RegistryOpenServiceKey(KEY_ALL_ACCESS, &ServiceKey); + if (!NT_SUCCESS(status)) + goto fail2; + + status = RegistryOpenSubKey(ServiceKey, + "Parameters", + KEY_READ, + &ParametersKey); + if (!NT_SUCCESS(status)) + goto fail3; + + __DriverSetParametersKey(ParametersKey); + + RegistryCloseKey(ServiceKey); + DriverObject->DriverExtension->AddDevice = AddDevice; for (Index = 0; Index <= IRP_MJ_MAXIMUM_FUNCTION; Index++) { @@ -193,5 +261,25 @@ DriverEntry( } Trace("<====\n"); + return STATUS_SUCCESS; + +fail3: + Error("fail3\n"); + + RegistryCloseKey(ServiceKey); + +fail2: + Error("fail2\n"); + + RegistryTeardown(); + +fail1: + Error("fail1 (%08x)\n", status); + + __DriverSetDriverObject(NULL); + + ASSERT(IsZeroMemory(&Driver, sizeof (XENDISK_DRIVER))); + + return status; } diff --git a/src/xendisk/driver.h b/src/xendisk/driver.h index 42662dd..f1dc821 100644 --- a/src/xendisk/driver.h +++ b/src/xendisk/driver.h @@ -40,6 +40,11 @@ DriverGetDriverObject( VOID ); +extern HANDLE +DriverGetParametersKey( + VOID + ); + #pragma warning(push) #pragma warning(disable:4201) // nonstandard extension used : nameless struct/union diff --git a/src/xendisk/fdo.c b/src/xendisk/fdo.c index 8d66e30..f00d47e 100644 --- a/src/xendisk/fdo.c +++ b/src/xendisk/fdo.c @@ -67,7 +67,7 @@ __FdoAllocate( IN ULONG Length ) { - return __AllocateNonPagedPoolWithTag(__FUNCTION__, __LINE__, Length, FDO_TAG); + return __AllocatePoolWithTag(NonPagedPool, Length, FDO_TAG); } static FORCEINLINE VOID diff --git a/src/xendisk/pdo.c b/src/xendisk/pdo.c index 9ca96da..0f719d1 100644 --- a/src/xendisk/pdo.c +++ b/src/xendisk/pdo.c @@ -43,6 +43,7 @@ #include "fdo.h" #include "pdo.h" #include "driver.h" +#include "registry.h" #include "thread.h" #include "debug.h" #include "assert.h" @@ -62,6 +63,7 @@ struct _XENDISK_PDO { PXENDISK_FDO Fdo; + BOOLEAN InterceptTrim; ULONG SectorSize; }; @@ -70,7 +72,7 @@ __PdoAllocate( IN ULONG Length ) { - return __AllocateNonPagedPoolWithTag(__FUNCTION__, __LINE__, Length, PDO_TAG); + return __AllocatePoolWithTag(NonPagedPool, Length, PDO_TAG); } static FORCEINLINE VOID @@ -616,6 +618,11 @@ PdoQueryProperty( switch (Query->PropertyId) { case StorageDeviceTrimProperty: + if (!Pdo->InterceptTrim) { + status = PdoForwardIrpAndForget(Pdo, Irp); + break; + } + if (Query->QueryType == PropertyStandardQuery) { PDEVICE_TRIM_DESCRIPTOR Trim; @@ -662,6 +669,11 @@ PdoManageDataSetAttributes( switch (Attributes->Action) { case DeviceDsmAction_Trim: + if (!Pdo->InterceptTrim) { + status = PdoForwardIrpAndForget(Pdo, Irp); + break; + } + Ranges = (PDEVICE_DATA_SET_RANGE)((PUCHAR)Attributes + Attributes->DataSetRangesOffset); NumRanges = Attributes->DataSetRangesLength / sizeof(DEVICE_DATA_SET_RANGE); @@ -1992,6 +2004,8 @@ PdoCreate( PDEVICE_OBJECT FilterDeviceObject; PXENDISK_DX Dx; PXENDISK_PDO Pdo; + HANDLE ParametersKey; + ULONG InterceptTrim; NTSTATUS status; LowerDeviceObject = IoGetAttachedDeviceReference(PhysicalDeviceObject); @@ -2045,6 +2059,16 @@ PdoCreate( if (!NT_SUCCESS(status)) goto fail5; + ParametersKey = DriverGetParametersKey(); + + Pdo->InterceptTrim = TRUE; + + status = RegistryQueryDwordValue(ParametersKey, + "InterceptTrim", + &InterceptTrim); + if (NT_SUCCESS(status)) + Pdo->InterceptTrim = (InterceptTrim != 0) ? TRUE : FALSE; + Verbose("%p\n", FilterDeviceObject); Dx->Pdo = Pdo; @@ -2110,6 +2134,8 @@ PdoDestroy( Dx->Pdo = NULL; + Pdo->InterceptTrim = FALSE; + ThreadAlert(Pdo->DevicePowerThread); ThreadJoin(Pdo->DevicePowerThread); Pdo->DevicePowerThread = NULL; diff --git a/src/xendisk/registry.c b/src/xendisk/registry.c new file mode 100644 index 0000000..56f3942 --- /dev/null +++ b/src/xendisk/registry.c @@ -0,0 +1,1492 @@ +/* Copyright (c) Citrix Systems Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, + * with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <ntddk.h> + +#include "registry.h" +#include "assert.h" +#include "util.h" + +#define REGISTRY_TAG 'GERX' + +static UNICODE_STRING RegistryPath; + +static FORCEINLINE PVOID +__RegistryAllocate( + IN ULONG Length + ) +{ + return __AllocatePoolWithTag(NonPagedPool, Length, REGISTRY_TAG); +} + +static FORCEINLINE VOID +__RegistryFree( + IN PVOID Buffer + ) +{ + __FreePoolWithTag(Buffer, REGISTRY_TAG); +} + +NTSTATUS +RegistryInitialize( + IN PUNICODE_STRING Path + ) +{ + NTSTATUS status; + + ASSERT3P(RegistryPath.Buffer, ==, NULL); + + status = RtlUpcaseUnicodeString(&RegistryPath, Path, TRUE); + if (!NT_SUCCESS(status)) + goto fail1; + + return STATUS_SUCCESS; + +fail1: + Error("fail1 (%08x)\n", status); + + return status; +} + +VOID +RegistryTeardown( + VOID + ) +{ + RtlFreeUnicodeString(&RegistryPath); + RegistryPath.Buffer = NULL; + RegistryPath.MaximumLength = RegistryPath.Length = 0; +} + +NTSTATUS +RegistryOpenKey( + IN HANDLE Parent, + IN PUNICODE_STRING Path, + IN ACCESS_MASK DesiredAccess, + OUT PHANDLE Key + ) +{ + OBJECT_ATTRIBUTES Attributes; + NTSTATUS status; + + InitializeObjectAttributes(&Attributes, + Path, + OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, + Parent, + NULL); + + status = ZwOpenKey(Key, + DesiredAccess, + &Attributes); + if (!NT_SUCCESS(status)) + goto fail1; + + return STATUS_SUCCESS; + +fail1: + return status; +} + +static NTSTATUS +RegistryOpenRoot( + IN PWCHAR Path, + OUT PHANDLE Parent, + OUT PWCHAR *ChildPath + ) +{ + const WCHAR Prefix[] = L"\\Registry\\Machine\\"; + ULONG Length; + UNICODE_STRING Unicode; + NTSTATUS status; + + Length = (ULONG)wcslen(Prefix); + + status = STATUS_INVALID_PARAMETER; + if (_wcsnicmp(Path, Prefix, Length) != 0) + goto fail1; + + RtlInitUnicodeString(&Unicode, Prefix); + + status = RegistryOpenKey(NULL, &Unicode, KEY_ALL_ACCESS, Parent); + if (!NT_SUCCESS(status)) + goto fail2; + + *ChildPath = Path + Length; + + return STATUS_SUCCESS; + +fail2: +fail1: + return status; +} + +NTSTATUS +RegistryCreateKey( + IN HANDLE Parent, + IN PUNICODE_STRING Path, + IN ULONG Options, + OUT PHANDLE Key + ) +{ + PWCHAR Buffer; + HANDLE Root; + PWCHAR ChildPath; + PWCHAR ChildName; + PWCHAR Context; + HANDLE Child; + NTSTATUS status; + + // + // UNICODE_STRINGs are not guaranteed to have NUL terminated + // buffers. + // + + Buffer = __RegistryAllocate(Path->MaximumLength + sizeof (WCHAR)); + + status = STATUS_NO_MEMORY; + if (Buffer == NULL) + goto fail1; + + RtlCopyMemory(Buffer, Path->Buffer, Path->Length); + + Root = Parent; + + if (Parent != NULL) { + ChildPath = Buffer; + } else { + status = RegistryOpenRoot(Buffer, &Parent, &ChildPath); + if (!NT_SUCCESS(status)) + goto fail2; + } + + ChildName = __wcstok_r(ChildPath, L"\\", &Context); + + status = STATUS_INVALID_PARAMETER; + if (ChildName == NULL) + goto fail3; + + Child = NULL; + + while (ChildName != NULL) { + UNICODE_STRING Unicode; + OBJECT_ATTRIBUTES Attributes; + + RtlInitUnicodeString(&Unicode, ChildName); + + InitializeObjectAttributes(&Attributes, + &Unicode, + OBJ_CASE_INSENSITIVE | + OBJ_KERNEL_HANDLE | + OBJ_OPENIF, + Parent, + NULL); + + status = ZwCreateKey(&Child, + KEY_ALL_ACCESS, + &Attributes, + 0, + NULL, + Options, + NULL + ); + if (!NT_SUCCESS(status)) + goto fail4; + + ChildName = __wcstok_r(NULL, L"\\", &Context); + + if (Parent != Root) + ZwClose(Parent); + + Parent = Child; + } + + ASSERT(Child != NULL); + + *Key = Child; + + __RegistryFree(Buffer); + + return STATUS_SUCCESS; + +fail4: +fail3: + if (Parent != Root) + ZwClose(Parent); + +fail2: + __RegistryFree(Buffer); + +fail1: + return status; +} + +NTSTATUS +RegistryOpenServiceKey( + IN ACCESS_MASK DesiredAccess, + OUT PHANDLE Key + ) +{ + return RegistryOpenKey(NULL, &RegistryPath, DesiredAccess, Key); +} + +NTSTATUS +RegistryCreateServiceKey( + OUT PHANDLE Key + ) +{ + return RegistryCreateKey(NULL, &RegistryPath, REG_OPTION_NON_VOLATILE, Key); +} + +NTSTATUS +RegistryOpenSoftwareKey( + IN PDEVICE_OBJECT DeviceObject, + IN ACCESS_MASK DesiredAccess, + OUT PHANDLE Key + ) +{ + NTSTATUS status; + + status = IoOpenDeviceRegistryKey(DeviceObject, + PLUGPLAY_REGKEY_DRIVER, + DesiredAccess, + Key); + if (!NT_SUCCESS(status)) + goto fail1; + + return STATUS_SUCCESS; + +fail1: + return status; +} + +NTSTATUS +RegistryOpenHardwareKey( + IN PDEVICE_OBJECT DeviceObject, + IN ACCESS_MASK DesiredAccess, + OUT PHANDLE Key + ) +{ + HANDLE SubKey; + ULONG Length; + PKEY_NAME_INFORMATION Info; + PWCHAR Cursor; + UNICODE_STRING Unicode; + NTSTATUS status; + + status = IoOpenDeviceRegistryKey(DeviceObject, + PLUGPLAY_REGKEY_DEVICE, + KEY_READ, + &SubKey); + if (!NT_SUCCESS(status)) + goto fail1; + + Length = 0; + status = ZwQueryKey(SubKey, + KeyNameInformation, + NULL, + 0, + &Length); + if (status != STATUS_BUFFER_OVERFLOW && + status != STATUS_BUFFER_TOO_SMALL) + goto fail2; + +#pragma prefast(suppress:6102) + Info = __RegistryAllocate(Length + sizeof (WCHAR)); + + status = STATUS_NO_MEMORY; + if (Info == NULL) + goto fail3; + + status = ZwQueryKey(SubKey, + KeyNameInformation, + Info, + Length, + &Length); + if (!NT_SUCCESS(status)) + goto fail4; + + Info->Name[Info->NameLength / sizeof (WCHAR)] = '\0'; + + Cursor = wcsrchr(Info->Name, L'\\'); + ASSERT(Cursor != NULL); + + *Cursor = L'\0'; + + RtlInitUnicodeString(&Unicode, Info->Name); + + status = RegistryOpenKey(NULL, &Unicode, DesiredAccess, Key); + if (!NT_SUCCESS(status)) + goto fail5; + + __RegistryFree(Info); + + RegistryCloseKey(SubKey); + + return STATUS_SUCCESS; + +fail5: +fail4: + __RegistryFree(Info); + +fail3: +fail2: + RegistryCloseKey(SubKey); + +fail1: + return status; +} + +NTSTATUS +RegistryOpenSubKey( + IN PHANDLE Key, + IN PCHAR Name, + IN ACCESS_MASK DesiredAccess, + OUT PHANDLE SubKey + ) +{ + ANSI_STRING Ansi; + UNICODE_STRING Unicode; + NTSTATUS status; + + RtlInitAnsiString(&Ansi, Name); + + status = RtlAnsiStringToUnicodeString(&Unicode, &Ansi, TRUE); + if (!NT_SUCCESS(status)) + goto fail1; + + status = RegistryOpenKey(Key, &Unicode, DesiredAccess, SubKey); + if (!NT_SUCCESS(status)) + goto fail2; + + RtlFreeUnicodeString(&Unicode); + + return STATUS_SUCCESS; + +fail2: + RtlFreeUnicodeString(&Unicode); + +fail1: + return status; +} + +NTSTATUS +RegistryCreateSubKey( + IN PHANDLE Key, + IN PCHAR Name, + IN ULONG Options, + OUT PHANDLE SubKey + ) +{ + ANSI_STRING Ansi; + UNICODE_STRING Unicode; + NTSTATUS status; + + RtlInitAnsiString(&Ansi, Name); + + status = RtlAnsiStringToUnicodeString(&Unicode, &Ansi, TRUE); + if (!NT_SUCCESS(status)) + goto fail1; + + status = RegistryCreateKey(Key, &Unicode, Options, SubKey); + if (!NT_SUCCESS(status)) + goto fail2; + + RtlFreeUnicodeString(&Unicode); + + return STATUS_SUCCESS; + +fail2: + RtlFreeUnicodeString(&Unicode); + +fail1: + return status; +} + +NTSTATUS +RegistryDeleteSubKey( + IN PHANDLE Key, + IN PCHAR Name + ) +{ + ANSI_STRING Ansi; + UNICODE_STRING Unicode; + HANDLE SubKey; + NTSTATUS status; + + RtlInitAnsiString(&Ansi, Name); + + status = RtlAnsiStringToUnicodeString(&Unicode, &Ansi, TRUE); + if (!NT_SUCCESS(status)) + goto fail1; + + status = RegistryOpenKey(Key, &Unicode, KEY_ALL_ACCESS, &SubKey); + if (!NT_SUCCESS(status)) + goto fail2; + + status = ZwDeleteKey(SubKey); + if (!NT_SUCCESS(status)) + goto fail3; + + ZwClose(SubKey); + + (VOID) ZwFlushKey(Key); + + RtlFreeUnicodeString(&Unicode); + + return STATUS_SUCCESS; + +fail3: + ZwClose(SubKey); + +fail2: + RtlFreeUnicodeString(&Unicode); + +fail1: + return status; +} + +NTSTATUS +RegistryEnumerateSubKeys( + IN HANDLE Key, + IN NTSTATUS (*Callback)(PVOID, HANDLE, PANSI_STRING), + IN PVOID Context + ) +{ + ULONG Size; + NTSTATUS status; + PKEY_FULL_INFORMATION Full; + PKEY_BASIC_INFORMATION Basic; + ULONG Index; + + status = ZwQueryKey(Key, + KeyFullInformation, + NULL, + 0, + &Size); + if (status != STATUS_BUFFER_OVERFLOW && + status != STATUS_BUFFER_TOO_SMALL) + goto fail1; + +#pragma prefast(suppress:6102) + Full = __RegistryAllocate(Size); + + status = STATUS_NO_MEMORY; + if (Full == NULL) + goto fail2; + + status = ZwQueryKey(Key, + KeyFullInformation, + Full, + Size, + &Size); + if (!NT_SUCCESS(status)) + goto fail3; + + Size = FIELD_OFFSET(KEY_BASIC_INFORMATION, Name) + + Full->MaxNameLen; + + Basic = __RegistryAllocate(Size); + status = STATUS_NO_MEMORY; + if (Basic == NULL) + goto fail4; + + for (Index = 0; Index < Full->SubKeys; Index++) { + ULONG Ignore; + UNICODE_STRING Unicode; + ANSI_STRING Ansi; + + status = ZwEnumerateKey(Key, + Index, + KeyBasicInformation, + Basic, + Size, + &Ignore); + if (!NT_SUCCESS(status)) + goto fail5; + + Unicode.MaximumLength = (USHORT)Basic->NameLength; + Unicode.Buffer = Basic->Name; + Unicode.Length = (USHORT)Basic->NameLength; + + Ansi.MaximumLength = (USHORT)((Basic->NameLength / sizeof (WCHAR)) + sizeof (CHAR)); + Ansi.Buffer = __RegistryAllocate(Ansi.MaximumLength); + + status = STATUS_NO_MEMORY; + if (Ansi.Buffer == NULL) + goto fail6; + + status = RtlUnicodeStringToAnsiString(&Ansi, &Unicode, FALSE); + ASSERT(NT_SUCCESS(status)); + + Ansi.Length = (USHORT)(strlen(Ansi.Buffer) * sizeof (CHAR)); + + status = Callback(Context, Key, &Ansi); + + __RegistryFree(Ansi.Buffer); + Ansi.Buffer = NULL; + + if (!NT_SUCCESS(status)) + goto fail7; + } + + __RegistryFree(Basic); + + __RegistryFree(Full); + + return STATUS_SUCCESS; + +fail7: +fail6: +fail5: + __RegistryFree(Basic); + +fail4: +fail3: + __RegistryFree(Full); + +fail2: +fail1: + return status; +} + +NTSTATUS +RegistryEnumerateValues( + IN HANDLE Key, + IN NTSTATUS (*Callback)(PVOID, HANDLE, PANSI_STRING, ULONG), + IN PVOID Context + ) +{ + ULONG Size; + NTSTATUS status; + PKEY_FULL_INFORMATION Full; + PKEY_VALUE_BASIC_INFORMATION Basic; + ULONG Index; + + status = ZwQueryKey(Key, + KeyFullInformation, + NULL, + 0, + &Size); + if (status != STATUS_BUFFER_OVERFLOW && + status != STATUS_BUFFER_TOO_SMALL) + goto fail1; + +#pragma prefast(suppress:6102) + Full = __RegistryAllocate(Size); + + status = STATUS_NO_MEMORY; + if (Full == NULL) + goto fail2; + + status = ZwQueryKey(Key, + KeyFullInformation, + Full, + Size, + &Size); + if (!NT_SUCCESS(status)) + goto fail3; + + Size = FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name) + + Full->MaxValueNameLen; + + Basic = __RegistryAllocate(Size); + status = STATUS_NO_MEMORY; + if (Basic == NULL) + goto fail4; + + for (Index = 0; Index < Full->Values; Index++) { + ULONG Ignore; + UNICODE_STRING Unicode; + ANSI_STRING Ansi; + + status = ZwEnumerateValueKey(Key, + Index, + KeyValueBasicInformation, + Basic, + Size, + &Ignore); + if (!NT_SUCCESS(status)) + goto fail5; + + Unicode.MaximumLength = (USHORT)Basic->NameLength; + Unicode.Buffer = Basic->Name; + Unicode.Length = (USHORT)Basic->NameLength; + + Ansi.MaximumLength = (USHORT)((Basic->NameLength / sizeof (WCHAR)) + sizeof (CHAR)); + Ansi.Buffer = __RegistryAllocate(Ansi.MaximumLength); + + status = RtlUnicodeStringToAnsiString(&Ansi, &Unicode, FALSE); + ASSERT(NT_SUCCESS(status)); + + Ansi.Length = (USHORT)(strlen(Ansi.Buffer) * sizeof (CHAR)); + + status = Callback(Context, Key, &Ansi, Basic->Type); + + __RegistryFree(Ansi.Buffer); + + if (!NT_SUCCESS(status)) + goto fail6; + } + + __RegistryFree(Basic); + + __RegistryFree(Full); + + return STATUS_SUCCESS; + +fail6: +fail5: + __RegistryFree(Basic); + +fail4: +fail3: + __RegistryFree(Full); + +fail2: +fail1: + return status; +} + +NTSTATUS +RegistryDeleteValue( + IN PHANDLE Key, + IN PCHAR Name + ) +{ + ANSI_STRING Ansi; + UNICODE_STRING Unicode; + NTSTATUS status; + + RtlInitAnsiString(&Ansi, Name); + + status = RtlAnsiStringToUnicodeString(&Unicode, &Ansi, TRUE); + if (!NT_SUCCESS(status)) + goto fail1; + + status = ZwDeleteValueKey(Key, &Unicode); + if (!NT_SUCCESS(status)) + goto fail2; + + RtlFreeUnicodeString(&Unicode); + + (VOID) ZwFlushKey(Key); + + return STATUS_SUCCESS; + +fail2: + RtlFreeUnicodeString(&Unicode); + +fail1: + return status; +} + +NTSTATUS +RegistryQueryDwordValue( + IN HANDLE Key, + IN PCHAR Name, + OUT PULONG Value + ) +{ + ANSI_STRING Ansi; + UNICODE_STRING Unicode; + PKEY_VALUE_PARTIAL_INFORMATION Partial; + ULONG Size; + NTSTATUS status; + + RtlInitAnsiString(&Ansi, Name); + + status = RtlAnsiStringToUnicodeString(&Unicode, &Ansi, TRUE); + if (!NT_SUCCESS(status)) + goto fail1; + + status = ZwQueryValueKey(Key, + &Unicode, + KeyValuePartialInformation, + NULL, + 0, + &Size); + if (status != STATUS_BUFFER_OVERFLOW && + status != STATUS_BUFFER_TOO_SMALL) + goto fail2; + +#pragma prefast(suppress:6102) + Partial = __RegistryAllocate(Size); + + status = STATUS_NO_MEMORY; + if (Partial == NULL) + goto fail3; + + status = ZwQueryValueKey(Key, + &Unicode, + KeyValuePartialInformation, + Partial, + Size, + &Size); + if (!NT_SUCCESS(status)) + goto fail4; + + status = STATUS_INVALID_PARAMETER; + if (Partial->Type != REG_DWORD || + Partial->DataLength != sizeof (ULONG)) + goto fail5; + + *Value = *(PULONG)Partial->Data; + + __RegistryFree(Partial); + + RtlFreeUnicodeString(&Unicode); + + return STATUS_SUCCESS; + +fail5: +fail4: + __RegistryFree(Partial); + +fail3: +fail2: + RtlFreeUnicodeString(&Unicode); + +fail1: + return status; +} + +NTSTATUS +RegistryUpdateDwordValue( + IN HANDLE Key, + IN PCHAR Name, + IN ULONG Value + ) +{ + ANSI_STRING Ansi; + UNICODE_STRING Unicode; + PKEY_VALUE_PARTIAL_INFORMATION Partial; + NTSTATUS status; + + RtlInitAnsiString(&Ansi, Name); + + status = RtlAnsiStringToUnicodeString(&Unicode, &Ansi, TRUE); + if (!NT_SUCCESS(status)) + goto fail1; + + Partial = __RegistryAllocate(FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data) + + sizeof (ULONG)); + + status = STATUS_NO_MEMORY; + if (Partial == NULL) + goto fail2; + + Partial->TitleIndex = 0; + Partial->Type = REG_DWORD; + Partial->DataLength = sizeof (ULONG); + *(PULONG)Partial->Data = Value; + + status = ZwSetValueKey(Key, + &Unicode, + Partial->TitleIndex, + Partial->Type, + Partial->Data, + Partial->DataLength); + if (!NT_SUCCESS(status)) + goto fail3; + + __RegistryFree(Partial); + + (VOID) ZwFlushKey(Key); + + RtlFreeUnicodeString(&Unicode); + + return STATUS_SUCCESS; + +fail3: + __RegistryFree(Partial); + +fail2: + RtlFreeUnicodeString(&Unicode); + +fail1: + + return status; +} + +static PANSI_STRING +RegistrySzToAnsi( + IN PWCHAR Buffer + ) +{ + PANSI_STRING Ansi; + ULONG Length; + UNICODE_STRING Unicode; + NTSTATUS status; + + Ansi = __RegistryAllocate(sizeof (ANSI_STRING) * 2); + + status = STATUS_NO_MEMORY; + if (Ansi == NULL) + goto fail1; + + Length = (ULONG)wcslen(Buffer); + Ansi[0].MaximumLength = (USHORT)(Length + 1) * sizeof (CHAR); + Ansi[0].Buffer = __RegistryAllocate(Ansi[0].MaximumLength); + + status = STATUS_NO_MEMORY; + if (Ansi[0].Buffer == NULL) + goto fail2; + + RtlInitUnicodeString(&Unicode, Buffer); + status = RtlUnicodeStringToAnsiString(&Ansi[0], &Unicode, FALSE); + ASSERT(NT_SUCCESS(status)); + + Ansi[0].Length = (USHORT)Length * sizeof (CHAR); + + return Ansi; + +fail2: + __RegistryFree(Ansi); + +fail1: + return NULL; +} + +static PANSI_STRING +RegistryMultiSzToAnsi( + IN PWCHAR Buffer + ) +{ + PANSI_STRING Ansi; + LONG Index; + LONG Count; + NTSTATUS status; + + Index = 0; + Count = 0; + for (;;) { + ULONG Length; + + Length = (ULONG)wcslen(&Buffer[Index]); + if (Length == 0) + break; + + Index += Length + 1; + Count++; + } + + Ansi = __RegistryAllocate(sizeof (ANSI_STRING) * (Count + 1)); + + status = STATUS_NO_MEMORY; + if (Ansi == NULL) + goto fail1; + + for (Index = 0; Index < Count; Index++) { + ULONG Length; + UNICODE_STRING Unicode; + + Length = (ULONG)wcslen(Buffer); + Ansi[Index].MaximumLength = (USHORT)(Length + 1) * sizeof (CHAR); + Ansi[Index].Buffer = __RegistryAllocate(Ansi[Index].MaximumLength); + + status = STATUS_NO_MEMORY; + if (Ansi[Index].Buffer == NULL) + goto fail2; + + RtlInitUnicodeString(&Unicode, Buffer); + + status = RtlUnicodeStringToAnsiString(&Ansi[Index], &Unicode, FALSE); + ASSERT(NT_SUCCESS(status)); + + Ansi[Index].Length = (USHORT)Length * sizeof (CHAR); + Buffer += Length + 1; + } + + return Ansi; + +fail2: + while (--Index >= 0) + __RegistryFree(Ansi[Index].Buffer); + + __RegistryFree(Ansi); + +fail1: + return NULL; +} + +NTSTATUS +RegistryQuerySzValue( + IN HANDLE Key, + IN PCHAR Name, + OUT PULONG Type OPTIONAL, + OUT PANSI_STRING *Array + ) +{ + ANSI_STRING Ansi; + UNICODE_STRING Unicode; + PKEY_VALUE_PARTIAL_INFORMATION Value; + ULONG Size; + NTSTATUS status; + + RtlInitAnsiString(&Ansi, Name); + + status = RtlAnsiStringToUnicodeString(&Unicode, &Ansi, TRUE); + if (!NT_SUCCESS(status)) + goto fail1; + + status = ZwQueryValueKey(Key, + &Unicode, + KeyValuePartialInformation, + NULL, + 0, + &Size); + if (status != STATUS_BUFFER_OVERFLOW && + status != STATUS_BUFFER_TOO_SMALL) + goto fail2; + +#pragma prefast(suppress:6102) + Value = __RegistryAllocate(Size); + + status = STATUS_NO_MEMORY; + if (Value == NULL) + goto fail3; + + status = ZwQueryValueKey(Key, + &Unicode, + KeyValuePartialInformation, + Value, + Size, + &Size); + if (!NT_SUCCESS(status)) + goto fail4; + + switch (Value->Type) { + case REG_SZ: + status = STATUS_NO_MEMORY; + *Array = RegistrySzToAnsi((PWCHAR)Value->Data); + break; + + case REG_MULTI_SZ: + status = STATUS_NO_MEMORY; + *Array = RegistryMultiSzToAnsi((PWCHAR)Value->Data); + break; + + default: + status = STATUS_INVALID_PARAMETER; + *Array = NULL; + break; + } + + if (*Array == NULL) + goto fail5; + + if (Type != NULL) + *Type = Value->Type; + + __RegistryFree(Value); + + RtlFreeUnicodeString(&Unicode); + + return STATUS_SUCCESS; + +fail5: +fail4: + __RegistryFree(Value); + +fail3: +fail2: + RtlFreeUnicodeString(&Unicode); + +fail1: + return status; +} + +NTSTATUS +RegistryQueryBinaryValue( + IN HANDLE Key, + IN PCHAR Name, + OUT PVOID *Buffer, + OUT PULONG Length + ) +{ + ANSI_STRING Ansi; + UNICODE_STRING Unicode; + PKEY_VALUE_PARTIAL_INFORMATION Partial; + ULONG Size; + NTSTATUS status; + + RtlInitAnsiString(&Ansi, Name); + + status = RtlAnsiStringToUnicodeString(&Unicode, &Ansi, TRUE); + if (!NT_SUCCESS(status)) + goto fail1; + + status = ZwQueryValueKey(Key, + &Unicode, + KeyValuePartialInformation, + NULL, + 0, + &Size); + if (status != STATUS_BUFFER_OVERFLOW && + status != STATUS_BUFFER_TOO_SMALL) + goto fail2; + +#pragma prefast(suppress:6102) + Partial = __RegistryAllocate(Size); + + status = STATUS_NO_MEMORY; + if (Partial == NULL) + goto fail3; + + status = ZwQueryValueKey(Key, + &Unicode, + KeyValuePartialInformation, + Partial, + Size, + &Size); + if (!NT_SUCCESS(status)) + goto fail4; + + switch (Partial->Type) { + case REG_BINARY: + *Buffer = __RegistryAllocate(Partial->DataLength); + + status = STATUS_NO_MEMORY; + if (*Buffer == NULL) + break; + + *Length = Partial->DataLength; + RtlCopyMemory(*Buffer, Partial->Data, Partial->DataLength); + break; + + default: + status = STATUS_INVALID_PARAMETER; + *Buffer = NULL; + break; + } + + if (*Buffer == NULL) + goto fail5; + + __RegistryFree(Partial); + + RtlFreeUnicodeString(&Unicode); + + return STATUS_SUCCESS; + +fail5: +fail4: + __RegistryFree(Partial); + +fail3: +fail2: + RtlFreeUnicodeString(&Unicode); + +fail1: + return status; +} + +NTSTATUS +RegistryUpdateBinaryValue( + IN HANDLE Key, + IN PCHAR Name, + IN PVOID Buffer, + IN ULONG Length + ) +{ + ANSI_STRING Ansi; + UNICODE_STRING Unicode; + PKEY_VALUE_PARTIAL_INFORMATION Partial; + NTSTATUS status; + + RtlInitAnsiString(&Ansi, Name); + + status = RtlAnsiStringToUnicodeString(&Unicode, &Ansi, TRUE); + if (!NT_SUCCESS(status)) + goto fail1; + + Partial = __RegistryAllocate(FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data) + + Length); + + status = STATUS_NO_MEMORY; + if (Partial == NULL) + goto fail2; + + Partial->TitleIndex = 0; + Partial->Type = REG_BINARY; + Partial->DataLength = Length; + RtlCopyMemory(Partial->Data, Buffer, Partial->DataLength); + + status = ZwSetValueKey(Key, + &Unicode, + Partial->TitleIndex, + Partial->Type, + Partial->Data, + Partial->DataLength); + if (!NT_SUCCESS(status)) + goto fail3; + + __RegistryFree(Partial); + + (VOID) ZwFlushKey(Key); + + RtlFreeUnicodeString(&Unicode); + + return STATUS_SUCCESS; + +fail3: + __RegistryFree(Partial); + +fail2: + RtlFreeUnicodeString(&Unicode); + +fail1: + + return status; +} + +NTSTATUS +RegistryQueryKeyName( + IN HANDLE Key, + OUT PANSI_STRING *Array + ) +{ + PKEY_NAME_INFORMATION Value; + ULONG Size; + NTSTATUS status; + + status = ZwQueryKey(Key, + KeyNameInformation, + NULL, + 0, + &Size); + if (status != STATUS_BUFFER_OVERFLOW && + status != STATUS_BUFFER_TOO_SMALL) + goto fail1; + + // Name information is not intrinsically NULL terminated +#pragma prefast(suppress:6102) + Value = __RegistryAllocate(Size + sizeof (WCHAR)); + + status = STATUS_NO_MEMORY; + if (Value == NULL) + goto fail2; + + status = ZwQueryKey(Key, + KeyNameInformation, + Value, + Size, + &Size); + if (!NT_SUCCESS(status)) + goto fail3; + + Value->Name[Value->NameLength / sizeof (WCHAR)] = L'\0'; + *Array = RegistrySzToAnsi((PWCHAR)Value->Name); + + status = STATUS_NO_MEMORY; + if (*Array == NULL) + goto fail4; + + __RegistryFree(Value); + + return STATUS_SUCCESS; + +fail4: +fail3: + __RegistryFree(Value); + +fail2: +fail1: + return status; +} + +NTSTATUS +RegistryQuerySystemStartOption( + IN PCHAR Prefix, + OUT PANSI_STRING *Value + ) +{ + UNICODE_STRING Unicode; + HANDLE Key; + PANSI_STRING Ansi; + ULONG Length; + PCHAR Option; + PCHAR Context; + NTSTATUS status; + + RtlInitUnicodeString(&Unicode, L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control"); + + status = RegistryOpenKey(NULL, &Unicode, KEY_READ, &Key); + if (!NT_SUCCESS(status)) + goto fail1; + + status = RegistryQuerySzValue(Key, "SystemStartOptions", NULL, &Ansi); + if (!NT_SUCCESS(status)) + goto fail2; + + // SystemStartOptions is a space separated list of options. + // Scan it looking for the one we want. + Length = (ULONG)strlen(Prefix); + + Option = __strtok_r(Ansi[0].Buffer, " ", &Context); + while (Option != NULL) { + if (strncmp(Prefix, Option, Length) == 0) + goto found; + + Option = __strtok_r(NULL, " ", &Context); + } + + status = STATUS_OBJECT_NAME_NOT_FOUND; + goto fail3; + +found: + *Value = __RegistryAllocate(sizeof (ANSI_STRING) * 2); + + status = STATUS_NO_MEMORY; + if (*Value == NULL) + goto fail4; + + Length = (ULONG)strlen(Option); + (*Value)[0].MaximumLength = (USHORT)(Length + 1) * sizeof (CHAR); + (*Value)[0].Buffer = __RegistryAllocate((*Value)[0].MaximumLength); + + status = STATUS_NO_MEMORY; + if ((*Value)[0].Buffer == NULL) + goto fail5; + + RtlCopyMemory((*Value)[0].Buffer, Option, Length * sizeof (CHAR)); + + (*Value)[0].Length = (USHORT)Length * sizeof (CHAR); + + RegistryFreeSzValue(Ansi); + + ZwClose(Key); + + return STATUS_SUCCESS; + +fail5: + __RegistryFree(*Value); + +fail4: +fail3: + RegistryFreeSzValue(Ansi); + +fail2: + ZwClose(Key); + +fail1: + return status; +} + +static PKEY_VALUE_PARTIAL_INFORMATION +RegistryAnsiToSz( + PANSI_STRING Ansi + ) +{ + ULONG Length; + PKEY_VALUE_PARTIAL_INFORMATION Partial; + UNICODE_STRING Unicode; + NTSTATUS status; + + Length = Ansi->Length + 1; + Partial = __RegistryAllocate(FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data) + + Length * sizeof (WCHAR)); + + status = STATUS_NO_MEMORY; + if (Partial == NULL) + goto fail1; + + Partial->TitleIndex = 0; + Partial->Type = REG_SZ; + Partial->DataLength = Length * sizeof (WCHAR); + + Unicode.MaximumLength = (UCHAR)Partial->DataLength; + Unicode.Buffer = (PWCHAR)Partial->Data; + Unicode.Length = 0; + + status = RtlAnsiStringToUnicodeString(&Unicode, Ansi, FALSE); + if (!NT_SUCCESS(status)) + goto fail2; + + return Partial; + +fail2: + __RegistryFree(Partial); + +fail1: + return NULL; +} + +static PKEY_VALUE_PARTIAL_INFORMATION +RegistryAnsiToMultiSz( + PANSI_STRING Ansi + ) +{ + ULONG Length; + ULONG Index; + PKEY_VALUE_PARTIAL_INFORMATION Partial; + UNICODE_STRING Unicode; + NTSTATUS status; + + Length = 1; + for (Index = 0; Ansi[Index].Buffer != NULL; Index++) + Length += Ansi[Index].Length + 1; + + Partial = __RegistryAllocate(FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data) + + Length * sizeof (WCHAR)); + + status = STATUS_NO_MEMORY; + if (Partial == NULL) + goto fail1; + + Partial->TitleIndex = 0; + Partial->Type = REG_MULTI_SZ; + Partial->DataLength = Length * sizeof (WCHAR); + + Unicode.MaximumLength = (USHORT)Partial->DataLength; + Unicode.Buffer = (PWCHAR)Partial->Data; + Unicode.Length = 0; + + for (Index = 0; Ansi[Index].Buffer != NULL; Index++) { + status = RtlAnsiStringToUnicodeString(&Unicode, &Ansi[Index], FALSE); + if (!NT_SUCCESS(status)) + goto fail2; + + Length = Unicode.Length / sizeof (WCHAR); + + ASSERT3U(Unicode.MaximumLength, >=, (Length + 1) * sizeof (WCHAR)); + Unicode.MaximumLength -= (USHORT)((Length + 1) * sizeof (WCHAR)); + Unicode.Buffer += Length + 1; + Unicode.Length = 0; + } + *Unicode.Buffer = L'\0'; + + return Partial; + +fail2: + __RegistryFree(Partial); + +fail1: + return NULL; +} + +NTSTATUS +RegistryUpdateSzValue( + IN HANDLE Key, + IN PCHAR Name, + IN ULONG Type, + IN PANSI_STRING Array + ) +{ + ANSI_STRING Ansi; + UNICODE_STRING Unicode; + PKEY_VALUE_PARTIAL_INFORMATION Partial; + NTSTATUS status; + + RtlInitAnsiString(&Ansi, Name); + + status = RtlAnsiStringToUnicodeString(&Unicode, &Ansi, TRUE); + if (!NT_SUCCESS(status)) + goto fail1; + + switch (Type) { + case REG_SZ: + status = STATUS_NO_MEMORY; + Partial = RegistryAnsiToSz(Array); + break; + + case REG_MULTI_SZ: + status = STATUS_NO_MEMORY; + Partial = RegistryAnsiToMultiSz(Array); + break; + + default: + status = STATUS_INVALID_PARAMETER; + Partial = NULL; + break; + } + + if (Partial == NULL) + goto fail2; + + status = ZwSetValueKey(Key, + &Unicode, + Partial->TitleIndex, + Partial->Type, + Partial->Data, + Partial->DataLength); + if (!NT_SUCCESS(status)) + goto fail3; + + __RegistryFree(Partial); + + (VOID) ZwFlushKey(Key); + + RtlFreeUnicodeString(&Unicode); + + return STATUS_SUCCESS; + +fail3: + __RegistryFree(Partial); + +fail2: + RtlFreeUnicodeString(&Unicode); + +fail1: + return status; +} + +VOID +RegistryFreeSzValue( + IN PANSI_STRING Array + ) +{ + ULONG Index; + + if (Array == NULL) + return; + + for (Index = 0; Array[Index].Buffer != NULL; Index++) + __RegistryFree(Array[Index].Buffer); + + __RegistryFree(Array); +} + +VOID +RegistryFreeBinaryValue( + IN PVOID Buffer + ) +{ + __RegistryFree(Buffer); +} + +VOID +RegistryCloseKey( + IN HANDLE Key + ) +{ + ZwClose(Key); +} diff --git a/src/xendisk/registry.h b/src/xendisk/registry.h new file mode 100644 index 0000000..24c0bf3 --- /dev/null +++ b/src/xendisk/registry.h @@ -0,0 +1,203 @@ +/* Copyright (c) Citrix Systems Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, + * with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _XENDISK_REGISTRY_H +#define _XENDISK_REGISTRY_H + +#include <ntddk.h> + +extern NTSTATUS +RegistryInitialize( + IN PUNICODE_STRING Path + ); + +extern VOID +RegistryTeardown( + VOID + ); + +extern NTSTATUS +RegistryOpenKey( + IN HANDLE Parent, + IN PUNICODE_STRING Path, + IN ACCESS_MASK DesiredAccess, + OUT PHANDLE Key + ); + +extern NTSTATUS +RegistryCreateKey( + IN HANDLE Parent, + IN PUNICODE_STRING Path, + IN ULONG Options, + OUT PHANDLE Key + ); + +extern NTSTATUS +RegistryOpenServiceKey( + IN ACCESS_MASK DesiredAccess, + OUT PHANDLE Key + ); + +extern NTSTATUS +RegistryCreateServiceKey( + OUT PHANDLE Key + ); + +extern NTSTATUS +RegistryOpenSoftwareKey( + IN PDEVICE_OBJECT DeviceObject, + IN ACCESS_MASK DesiredAccess, + OUT PHANDLE Key + ); + +extern NTSTATUS +RegistryOpenHardwareKey( + IN PDEVICE_OBJECT DeviceObject, + IN ACCESS_MASK DesiredAccess, + OUT PHANDLE Key + ); + +extern NTSTATUS +RegistryOpenSubKey( + IN HANDLE Key, + IN PCHAR Name, + IN ACCESS_MASK DesiredAccess, + OUT PHANDLE SubKey + ); + +extern NTSTATUS +RegistryCreateSubKey( + IN HANDLE Key, + IN PCHAR Name, + IN ULONG Options, + OUT PHANDLE SubKey + ); + +extern NTSTATUS +RegistryDeleteSubKey( + IN HANDLE Key, + IN PCHAR Name + ); + +extern NTSTATUS +RegistryEnumerateSubKeys( + IN HANDLE Key, + IN NTSTATUS (*Callback)(PVOID, HANDLE, PANSI_STRING), + IN PVOID Context + ); + +extern NTSTATUS +RegistryEnumerateValues( + IN HANDLE Key, + IN NTSTATUS (*Callback)(PVOID, HANDLE, PANSI_STRING, ULONG), + IN PVOID Context + ); + +extern NTSTATUS +RegistryDeleteValue( + IN HANDLE Key, + IN PCHAR Name + ); + +extern NTSTATUS +RegistryQueryDwordValue( + IN HANDLE Key, + IN PCHAR Name, + OUT PULONG Value + ); + +extern NTSTATUS +RegistryUpdateDwordValue( + IN HANDLE Key, + IN PCHAR Name, + IN ULONG Value + ); + +extern NTSTATUS +RegistryQuerySzValue( + IN HANDLE Key, + IN PCHAR Name, + OUT PULONG Type OPTIONAL, + OUT PANSI_STRING *Array + ); + +extern NTSTATUS +RegistryQueryBinaryValue( + IN HANDLE Key, + IN PCHAR Name, + OUT PVOID *Buffer, + OUT PULONG Length + ); + +extern NTSTATUS +RegistryUpdateBinaryValue( + IN HANDLE Key, + IN PCHAR Name, + IN PVOID Buffer, + IN ULONG Length + ); + +extern NTSTATUS +RegistryQueryKeyName( + IN HANDLE Key, + OUT PANSI_STRING *Array + ); + +extern NTSTATUS +RegistryQuerySystemStartOption( + IN PCHAR Name, + OUT PANSI_STRING *Option + ); + +extern VOID +RegistryFreeSzValue( + IN PANSI_STRING Array + ); + +extern VOID +RegistryFreeBinaryValue( + IN PVOID Buffer + ); + +extern NTSTATUS +RegistryUpdateSzValue( + IN HANDLE Key, + IN PCHAR Name, + IN ULONG Type, + IN PANSI_STRING Array + ); + +extern VOID +RegistryCloseKey( + IN HANDLE Key + ); + +#endif // _XENDISK_REGISTRY_H diff --git a/src/xendisk/thread.c b/src/xendisk/thread.c index b7f3b2d..335b55a 100644 --- a/src/xendisk/thread.c +++ b/src/xendisk/thread.c @@ -36,10 +36,10 @@ #include "assert.h" #include "util.h" -#define THREAD_POOL 'ERHT' +#define THREAD_TAG 'ERHT' struct _XENDISK_THREAD { - XENDISK_THREAD_FUNCTION Function; + XENDISK_THREAD_FUNCTION Function; PVOID Context; KEVENT Event; BOOLEAN Alerted; @@ -52,7 +52,7 @@ __ThreadAllocate( IN ULONG Length ) { - return __AllocateNonPagedPoolWithTag(__FUNCTION__, __LINE__, Length, THREAD_POOL); + return __AllocatePoolWithTag(NonPagedPool, Length, THREAD_TAG); } static FORCEINLINE VOID @@ -60,7 +60,7 @@ __ThreadFree( IN PVOID Buffer ) { - __FreePoolWithTag(Buffer, THREAD_POOL); + __FreePoolWithTag(Buffer, THREAD_TAG); } static FORCEINLINE VOID diff --git a/src/xendisk/util.h b/src/xendisk/util.h index 99a5b5f..38f2aa7 100644 --- a/src/xendisk/util.h +++ b/src/xendisk/util.h @@ -29,194 +29,330 @@ * SUCH DAMAGE. */ -#ifndef _UTIL_H -#define _UTIL_H +#ifndef _XENDISK_UTIL_H +#define _XENDISK_UTIL_H #include <ntddk.h> #include "assert.h" -typedef struct _NON_PAGED_BUFFER_HEADER { - SIZE_T Length; - ULONG Tag; -} NON_PAGED_BUFFER_HEADER, *PNON_PAGED_BUFFER_HEADER; +#define P2ROUNDUP(_x, _a) \ + (-(-(_x) & -(_a))) -typedef struct _NON_PAGED_BUFFER_TRAILER { - ULONG Tag; -} NON_PAGED_BUFFER_TRAILER, *PNON_PAGED_BUFFER_TRAILER; - -static FORCEINLINE PVOID -__AllocateNonPagedPoolWithTag( - IN PCHAR Caller, - IN ULONG Line, - IN SIZE_T Length, - IN ULONG Tag +static FORCEINLINE LONG +__ffs( + IN unsigned long long mask ) { - PUCHAR Buffer; - PNON_PAGED_BUFFER_HEADER Header; - PNON_PAGED_BUFFER_TRAILER Trailer; - - ASSERT3S(Length, !=, 0); - - Buffer = (PUCHAR)ExAllocatePoolWithTag(NonPagedPool, - sizeof (NON_PAGED_BUFFER_HEADER) + - Length + - sizeof (NON_PAGED_BUFFER_TRAILER), - Tag); - if (Buffer == NULL) { - Warning("%s:%u : AllocFailed %d bytes, %08x tag\n", Caller, Line, Length, Tag); - goto done; - } + unsigned char *array = (unsigned char *)&mask; + unsigned int byte; + unsigned int bit; + unsigned char val; - RtlZeroMemory(Buffer, - sizeof (NON_PAGED_BUFFER_HEADER) + - Length + - sizeof (NON_PAGED_BUFFER_TRAILER)); + val = 0; - Header = (PNON_PAGED_BUFFER_HEADER)Buffer; - Header->Length = Length; - Header->Tag = Tag; + byte = 0; + while (byte < 8) { + val = array[byte]; - Buffer += sizeof (NON_PAGED_BUFFER_HEADER); + if (val != 0) + break; - Trailer = (PNON_PAGED_BUFFER_TRAILER)(Buffer + Length); - Trailer->Tag = Tag; + byte++; + } + if (byte == 8) + return -1; -done: - return Buffer; + bit = 0; + while (bit < 8) { + if (val & 0x01) + break; + + val >>= 1; + bit++; + } + + return (byte * 8) + bit; } +#define __ffu(_mask) \ + __ffs(~(_mask)) + static FORCEINLINE VOID -__FreePoolWithTag( - IN PVOID _Buffer, - IN ULONG Tag +__CpuId( + IN ULONG Leaf, + OUT PULONG EAX OPTIONAL, + OUT PULONG EBX OPTIONAL, + OUT PULONG ECX OPTIONAL, + OUT PULONG EDX OPTIONAL ) { - PUCHAR Buffer = (PUCHAR)_Buffer; - SIZE_T Length; - PNON_PAGED_BUFFER_HEADER Header; - PNON_PAGED_BUFFER_TRAILER Trailer; + ULONG Value[4] = {0}; - ASSERT3P(Buffer, !=, NULL); + __cpuid(Value, Leaf); - Buffer -= sizeof (NON_PAGED_BUFFER_HEADER); + if (EAX) + *EAX = Value[0]; - Header = (PNON_PAGED_BUFFER_HEADER)Buffer; - ASSERT3U(Tag, ==, Header->Tag); - Length = Header->Length; + if (EBX) + *EBX = Value[1]; - Buffer += sizeof (NON_PAGED_BUFFER_HEADER); + if (ECX) + *ECX = Value[2]; - Trailer = (PNON_PAGED_BUFFER_TRAILER)(Buffer + Length); - ASSERT3U(Tag, ==, Trailer->Tag); + if (EDX) + *EDX = Value[3]; +} - Buffer -= sizeof (NON_PAGED_BUFFER_HEADER); +static FORCEINLINE LONG +__InterlockedAdd( + IN LONG *Value, + IN LONG Delta + ) +{ + LONG New; + LONG Old; - RtlFillMemory(Buffer, - sizeof (NON_PAGED_BUFFER_HEADER) + - Length + - sizeof (NON_PAGED_BUFFER_TRAILER), - 0xAA); + do { + Old = *Value; + New = Old + Delta; + } while (InterlockedCompareExchange(Value, New, Old) != Old); - ExFreePoolWithTag(Buffer, Tag); + return New; } -static FORCEINLINE PMDL -__AllocPagesForMdl( - IN SIZE_T Size +static FORCEINLINE LONG +__InterlockedSubtract( + IN LONG *Value, + IN LONG Delta ) { - PMDL Mdl; - PHYSICAL_ADDRESS LowAddr; - PHYSICAL_ADDRESS HighAddr; - PHYSICAL_ADDRESS SkipBytes; + LONG New; + LONG Old; - SkipBytes.QuadPart = 0ull; - HighAddr.QuadPart = ~0ull; - - // try > 4GB - LowAddr.QuadPart = 0x100000000ull; - Mdl = MmAllocatePagesForMdlEx(LowAddr, HighAddr, SkipBytes, Size, MmCached, 0); - if (Mdl) { - if (MmGetMdlByteCount(Mdl) == Size) { - goto done; - } - MmFreePagesFromMdl(Mdl); - ExFreePool(Mdl); - Mdl = NULL; - } + do { + Old = *Value; + New = Old - Delta; + } while (InterlockedCompareExchange(Value, New, Old) != Old); - // try > 2GB - LowAddr.QuadPart = 0x80000000ull; - Mdl = MmAllocatePagesForMdlEx(LowAddr, HighAddr, SkipBytes, Size, MmCached, 0); - if (Mdl) { - if (MmGetMdlByteCount(Mdl) == Size) { - goto done; - } - MmFreePagesFromMdl(Mdl); - ExFreePool(Mdl); - Mdl = NULL; - } + return New; +} - // try anywhere - LowAddr.QuadPart = 0ull; - Mdl = MmAllocatePagesForMdlEx(LowAddr, HighAddr, SkipBytes, Size, MmCached, 0); - // Mdl byte count gets checked again after this returns +static FORCEINLINE PVOID +__AllocatePoolWithTag( + IN POOL_TYPE PoolType, + IN SIZE_T NumberOfBytes, + IN ULONG Tag + ) +{ + PUCHAR Buffer; -done: - return Mdl; + __analysis_assume(PoolType == NonPagedPool || + PoolType == PagedPool); + + Buffer = ExAllocatePoolWithTag(PoolType, NumberOfBytes, Tag); + if (Buffer == NULL) + return NULL; + + RtlZeroMemory(Buffer, NumberOfBytes); + return Buffer; } -static FORCEINLINE PVOID -___AllocPages( - IN PCHAR Caller, - IN ULONG Line, - IN SIZE_T Size, - OUT PMDL* Mdl + +static FORCEINLINE VOID +__FreePoolWithTag( + IN PVOID Buffer, + IN ULONG Tag ) { - PVOID Buffer; + ExFreePoolWithTag(Buffer, Tag); +} - *Mdl = __AllocPagesForMdl(Size); - if (*Mdl == NULL) { - Warning("%s:%u : MmAllocatePagesForMdlEx Failed %d bytes\n", Caller, Line, Size); +static FORCEINLINE PMDL +__AllocatePages( + IN ULONG Count + ) +{ + PHYSICAL_ADDRESS LowAddress; + PHYSICAL_ADDRESS HighAddress; + LARGE_INTEGER SkipBytes; + SIZE_T TotalBytes; + PMDL Mdl; + PUCHAR MdlMappedSystemVa; + NTSTATUS status; + + LowAddress.QuadPart = 0ull; + HighAddress.QuadPart = ~0ull; + SkipBytes.QuadPart = 0ull; + TotalBytes = (SIZE_T)PAGE_SIZE * Count; + + Mdl = MmAllocatePagesForMdlEx(LowAddress, + HighAddress, + SkipBytes, + TotalBytes, + MmCached, + MM_DONT_ZERO_ALLOCATION); + + status = STATUS_NO_MEMORY; + if (Mdl == NULL) goto fail1; - } - if (MmGetMdlByteCount(*Mdl) != Size) { - Warning("%s:%u : %d bytes != %d bytes requested\n", Caller, Line, MmGetMdlByteCount(*Mdl), Size); + if (Mdl->ByteCount < TotalBytes) goto fail2; - } - Buffer = MmMapLockedPagesSpecifyCache(*Mdl, KernelMode, MmCached, NULL, FALSE, NormalPagePriority); - if (Buffer == NULL) { - Warning("%s:%u : MmMapLockedPagesSpecifyCache Failed %d bytes\n", Caller, Line, Size); + ASSERT((Mdl->MdlFlags & (MDL_MAPPED_TO_SYSTEM_VA | + MDL_PARTIAL_HAS_BEEN_MAPPED | + MDL_PARTIAL | + MDL_PARENT_MAPPED_SYSTEM_VA | + MDL_SOURCE_IS_NONPAGED_POOL | + MDL_IO_SPACE)) == 0); + + MdlMappedSystemVa = MmMapLockedPagesSpecifyCache(Mdl, + KernelMode, + MmCached, + NULL, + FALSE, + NormalPagePriority); + + status = STATUS_UNSUCCESSFUL; + if (MdlMappedSystemVa == NULL) goto fail3; - } - return Buffer; + ASSERT3P(MdlMappedSystemVa, ==, Mdl->MappedSystemVa); + + RtlZeroMemory(MdlMappedSystemVa, Mdl->ByteCount); + + return Mdl; fail3: + Error("fail3\n"); + fail2: - MmFreePagesFromMdl(*Mdl); - ExFreePool(*Mdl); + Error("fail2\n"); + + MmFreePagesFromMdl(Mdl); + ExFreePool(Mdl); + fail1: - *Mdl = NULL; + Error("fail1 (%08x)\n", status); + return NULL; } -#define __AllocPages(Size, Mdl) ___AllocPages(__FUNCTION__, __LINE__, Size, Mdl) + +#define __AllocatePage() __AllocatePages(1) static FORCEINLINE VOID __FreePages( - IN PVOID Buffer, - IN PMDL Mdl + IN PMDL Mdl ) { - if (Buffer && Mdl) { - MmUnmapLockedPages(Buffer, Mdl); - MmFreePagesFromMdl(Mdl); - ExFreePool(Mdl); - } + PUCHAR MdlMappedSystemVa; + + ASSERT(Mdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA); + MdlMappedSystemVa = Mdl->MappedSystemVa; + + MmUnmapLockedPages(MdlMappedSystemVa, Mdl); + + MmFreePagesFromMdl(Mdl); +} + +#define __FreePage(_Mdl) __FreePages(_Mdl) + +static FORCEINLINE PCHAR +__strtok_r( + IN PCHAR Buffer, + IN PCHAR Delimiter, + IN OUT PCHAR *Context + ) +{ + PCHAR Token; + PCHAR End; + + if (Buffer != NULL) + *Context = Buffer; + + Token = *Context; + + if (Token == NULL) + return NULL; + + while (*Token != '\0' && + strchr(Delimiter, *Token) != NULL) + Token++; + + if (*Token == '\0') + return NULL; + + End = Token + 1; + while (*End != '\0' && + strchr(Delimiter, *End) == NULL) + End++; + + if (*End != '\0') + *End++ = '\0'; + + *Context = End; + + return Token; +} + +static FORCEINLINE PWCHAR +__wcstok_r( + IN PWCHAR Buffer, + IN PWCHAR Delimiter, + IN OUT PWCHAR *Context + ) +{ + PWCHAR Token; + PWCHAR End; + + if (Buffer != NULL) + *Context = Buffer; + + Token = *Context; + + if (Token == NULL) + return NULL; + + while (*Token != L'\0' && + wcschr(Delimiter, *Token) != NULL) + Token++; + + if (*Token == L'\0') + return NULL; + + End = Token + 1; + while (*End != L'\0' && + wcschr(Delimiter, *End) == NULL) + End++; + + if (*End != L'\0') + *End++ = L'\0'; + + *Context = End; + + return Token; +} + +static FORCEINLINE CHAR +__toupper( + IN CHAR Character + ) +{ + if (Character < 'a' || Character > 'z') + return Character; + + return 'A' + Character - 'a'; +} + +static FORCEINLINE CHAR +__tolower( + IN CHAR Character + ) +{ + if (Character < 'A' || Character > 'Z') + return Character; + + return 'a' + Character - 'A'; } -#endif // _UTIL_H +#endif // _XENDISK_UTIL_H diff --git a/src/xenvbd.inf b/src/xenvbd.inf index 7037e45..68e7a15 100644 --- a/src/xenvbd.inf +++ b/src/xenvbd.inf @@ -83,6 +83,10 @@ StartType=%SERVICE_BOOT_START% ErrorControl=%SERVICE_ERROR_NORMAL% ServiceBinary=%12%\xendisk.sys LoadOrderGroup="Scsi Miniport" +AddReg=XenDisk_Parameters + +[XenDisk_Parameters] +HKR,"Parameters",,0x00000010 [XenVbd_Service] DisplayName=%XenVbdName% diff --git a/vs2012/xendisk/xendisk.vcxproj b/vs2012/xendisk/xendisk.vcxproj index c68e886..478b7f0 100644 --- a/vs2012/xendisk/xendisk.vcxproj +++ b/vs2012/xendisk/xendisk.vcxproj @@ -75,6 +75,7 @@ <ClCompile Include="../../src/xendisk/driver.c" /> <ClCompile Include="../../src/xendisk/fdo.c" /> <ClCompile Include="../../src/xendisk/pdo.c" /> + <ClCompile Include="../../src/xendisk/registry.c" /> <ClCompile Include="../../src/xendisk/thread.c" /> </ItemGroup> <ItemGroup> diff --git a/vs2013/xendisk/xendisk.vcxproj b/vs2013/xendisk/xendisk.vcxproj index f5c341e..73812d8 100644 --- a/vs2013/xendisk/xendisk.vcxproj +++ b/vs2013/xendisk/xendisk.vcxproj @@ -103,6 +103,7 @@ <ClCompile Include="../../src/xendisk/driver.c" /> <ClCompile Include="../../src/xendisk/fdo.c" /> <ClCompile Include="../../src/xendisk/pdo.c" /> + <ClCompile Include="../../src/xendisk/registry.c" /> <ClCompile Include="../../src/xendisk/thread.c" /> </ItemGroup> <ItemGroup> -- 2.5.3 _______________________________________________ win-pv-devel mailing list win-pv-devel@xxxxxxxxxxxxxxxxxxxx https://lists.xenproject.org/cgi-bin/mailman/listinfo/win-pv-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |