On 31.08.2016 18:38, Aric Stewart wrote:
> v2: No longer maintaining a device store
> Suggestions from Sebastian Lackner
>
> We are not handling installing drivers just yet, so we just make use
> of the critical device store. These are drivers that, on Windows, are
> automatically loaded on boot every time. This database is maintained
> in [CurrentControlSet/Control/CriticalDeviceDatabase] The keys in this
> registry key represent a HardwareID that match a device. We query the
> IDs from the bus device’s BusQueryHardwareIDs and if we find a match
> (from most specific to most general) we look at that registry key. The
> CriticalDeviceDatabase entry specify a [Service] value representing
> the driver.
>
> Signed-off-by: Aric Stewart <aric(a)codeweavers.com>
> ---
> dlls/ntoskrnl.exe/pnp_manager.c | 196 +++++++++++++++++++++++++++++++++++++++-
> include/ddk/wdm.h | 3 +-
> 2 files changed, 197 insertions(+), 2 deletions(-)
>
>
>
> v2-0002-ntoskrnl.exe-Implement-loading-plug-and-play-device.txt
>
>
> diff --git a/dlls/ntoskrnl.exe/pnp_manager.c b/dlls/ntoskrnl.exe/pnp_manager.c
> index 7ebd07d..04b218b 100644
> --- a/dlls/ntoskrnl.exe/pnp_manager.c
> +++ b/dlls/ntoskrnl.exe/pnp_manager.c
> @@ -17,6 +17,7 @@
> * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
> */
>
> +#define NONAMELESSUNION
> #include <stdarg.h>
> #include "ntstatus.h"
> #define WIN32_NO_STATUS
> @@ -24,14 +25,207 @@
> #include "winbase.h"
> #include "winternl.h"
> #include "ddk/wdm.h"
> +#include "wine/unicode.h"
> #include "wine/debug.h"
>
> WINE_DEFAULT_DEBUG_CHANNEL(plugplay);
>
> +#define MAX_SERVICE_NAME 260
> +
> +static NTSTATUS WINAPI internal_complete(DEVICE_OBJECT *deviceObject, IRP *irp, void *context)
> +{
> + SetEvent(irp->UserEvent);
> + return STATUS_MORE_PROCESSING_REQUIRED;
> +}
> +
> +static NTSTATUS send_device_irp(DEVICE_OBJECT *device, IRP *irp, ULONG_PTR *info)
> +{
> + NTSTATUS status;
> + IO_STACK_LOCATION *irpsp;
> + HANDLE event = CreateEventA(NULL, FALSE, FALSE, NULL);
> +
> + irp->UserEvent = event;
> + irpsp = IoGetNextIrpStackLocation(irp);
> + irpsp->CompletionRoutine = internal_complete;
> + irpsp->Control = SL_INVOKE_ON_SUCCESS | SL_INVOKE_ON_ERROR;
> +
> + IoCallDriver(device, irp);
> +
> + if (irp->IoStatus.u.Status == STATUS_PENDING)
> + WaitForSingleObject(event, INFINITE);
> +
> + status = irp->IoStatus.u.Status;
> + if (info)
> + *info = irp->IoStatus.Information;
> + IoCompleteRequest(irp, IO_NO_INCREMENT);
> + CloseHandle(event);
> + return status;
> +}
> +
> +static NTSTATUS get_device_id(DEVICE_OBJECT *device, BUS_QUERY_ID_TYPE type, WCHAR **id)
> +{
> + IO_STACK_LOCATION *irpsp;
> + IO_STATUS_BLOCK irp_status;
> + IRP *irp;
> +
> + irp = IoBuildSynchronousFsdRequest(IRP_MJ_PNP, device, NULL, 0, NULL, NULL, &irp_status);
> + if (irp == NULL)
> + return STATUS_NO_MEMORY;
> +
> + irpsp = IoGetNextIrpStackLocation(irp);
> + irpsp->MinorFunction = IRP_MN_QUERY_ID;
> + irpsp->Parameters.QueryId.IdType = type;
> + return send_device_irp(device, irp, (ULONG_PTR*)id);
> +}
> +
> +static NTSTATUS find_driver_for_id(const WCHAR *id, WCHAR *driver)
> +{
> + NTSTATUS rc;
> + static const WCHAR critical_fmtW[] =
> + {'\\','R','e','g','i','s','t','r','y',
> + '\\','M','a','c','h','i','n','e',
> + '\\','S','y','s','t','e','m',
> + '\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t',
> + '\\','C','o','n','t','r','o','l',
> + '\\','C','r','i','t','i','c','a','l','D','e','v','i','c','e','D','a','t','a','b','a','s','e',
> + '\\','%','s',0};
> +
> + HANDLE hkey;
> + WCHAR *regW;
> + UNICODE_STRING key;
> + OBJECT_ATTRIBUTES attr;
> +
> + regW = HeapAlloc(GetProcessHeap(), 0, sizeof(critical_fmtW) + strlenW(id) * sizeof(WCHAR));
> + sprintfW(regW, critical_fmtW, id);
> + RtlInitUnicodeString(&key, regW);
> +
> + InitializeObjectAttributes(&attr, &key, OBJ_CASE_INSENSITIVE, NULL, NULL);
> + rc = ZwOpenKey(&hkey, KEY_ALL_ACCESS, &attr);
> + if (rc == STATUS_SUCCESS)
> + {
> + static const WCHAR serviceW[] = {'S','e','r','v','i','c','e',0};
> + static const UNICODE_STRING serviceStr = {sizeof(serviceW) - sizeof(WCHAR), sizeof(serviceW), (WCHAR*)serviceW};
> + KEY_VALUE_PARTIAL_INFORMATION *info;
> + DWORD total_size = sizeof(*info) + MAX_SERVICE_NAME * sizeof(WCHAR);
> +
> + info = HeapAlloc(GetProcessHeap(), 0, total_size);
> +
> + rc = ZwQueryValueKey(hkey, &serviceStr, KeyValuePartialInformation, info, total_size, &total_size);
> + if (rc == STATUS_SUCCESS && info->Type == REG_SZ && info->DataLength < MAX_SERVICE_NAME * sizeof(WCHAR))
> + {
> + WCHAR *service = (WCHAR*)info->Data;
> + TRACE("Got service %s\n",debugstr_w(service));
> + strcpyW(driver, service);
> + }
> + else
> + {
> + if (info->Type != REG_SZ)
> + ERR("Failed to get Service from registry entry, Bad type\n");
> + else if (info->DataLength >= MAX_SERVICE_NAME * sizeof(WCHAR))
> + ERR("Failed to get Service from registry entry, Buffer too small\n");
> + else
> + ERR("Failed to get Service from registry entry (%x)\n",rc);
I don't think it makes sense to trace this an error, especially when you use a TRACE for the
lack of a critical device database key.
> + }
> + HeapFree(GetProcessHeap(), 0, info);
> + ZwClose(hkey);
> + }
> + else
> + TRACE("Failed to find Critical Device Database entry for %s\n",debugstr_w(id));
> + HeapFree(GetProcessHeap(), 0, regW);
> + return rc;
> +}
> +
> +static void handle_bus_relations(DEVICE_OBJECT *device)
> +{
> + static const WCHAR driverW[] = {'\\','D','r','i','v','e','r','\\',0};
> + static const WCHAR servicesW[] = {'\\','R','e','g','i','s','t','r','y',
> + '\\','M','a','c','h','i','n','e',
> + '\\','S','y','s','t','e','m',
> + '\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t',
> + '\\','S','e','r','v','i','c','e','s',
> + '\\',0};
> +
> + NTSTATUS status;
> + WCHAR *id, *idptr;
> + WCHAR driver[MAX_SERVICE_NAME] = {0};
> + WCHAR fullname[MAX_PATH];
> + DRIVER_OBJECT *driver_obj;
> + UNICODE_STRING driverName;
> + WCHAR driverKey[MAX_PATH];
> + UNICODE_STRING driverPath;
You'll have to allocate bigger buffers for the concatenated strings. In fact,
a single buffer should be sufficient for both the fullname and the driver key.
> +
> + TRACE("Device %p\n", device);
> +
> + /* We could(should?) do a full IRP_MN_QUERY_DEVICE_RELATIONS query,
> + * but we dont have to, We have the DEVICE_OBJECT of the new device
> + * so we can simply handle the process here */
> +
> + status = get_device_id(device, BusQueryCompatibleIDs, &id);
> + if (status != ERROR_SUCCESS || !id)
> + {
> + ERR("Failed to get device IDs\n");
> + return;
> + }
> +
> + idptr = id;
> + while(*idptr != 0)
> + {
> + TRACE("Checking for id %s\n",debugstr_w(idptr));
> + if (find_driver_for_id(idptr, driver) == STATUS_SUCCESS)
> + break;
> + idptr += (strlenW(idptr) + 1);
> + }
> + HeapFree(GetProcessHeap(), 0, id);
> +
> + if (!driver[0])
> + {
> + ERR("No matching driver found for device\n");
> + return;
> + }
> +
> + strcpyW(driverKey, servicesW);
> + strcatW(driverKey, driver);
> + RtlInitUnicodeString(&driverPath, driverKey);
> + if (ZwLoadDriver(&driverPath) != STATUS_SUCCESS)
> + {
> + ERR("Failed to load driver %s\n", debugstr_w(driver));
> + return;
> + }
> +
> + strcpyW(fullname, driverW);
> + strcatW(fullname, driver);
> + RtlInitUnicodeString(&driverName, fullname);
> + if (ObReferenceObjectByName(&driverName, OBJ_CASE_INSENSITIVE, NULL,
> + 0, NULL, KernelMode, NULL, (void**)&driver_obj) != STATUS_SUCCESS)
> + {
> + ERR("Failed to locate loaded driver %s\n", debugstr_w(driver));
> + return;
> + }
> +
> + if (!driver_obj->DriverExtension->AddDevice)
> + status = STATUS_NOT_IMPLEMENTED;
> + else
> + status = driver_obj->DriverExtension->AddDevice(driver_obj, device);
> +
> + ObDereferenceObject(driver_obj);
> +
> + if (status != STATUS_SUCCESS)
> + ERR("AddDevice failed for driver %s\n", debugstr_w(driver));
> +}
> +
> /***********************************************************************
> * IoInvalidateDeviceRelations(NTOSKRNL.EXE.@)
> */
> void WINAPI IoInvalidateDeviceRelations(DEVICE_OBJECT *device_object, DEVICE_RELATION_TYPE type)
> {
> - FIXME("(%p, %i): stub\n", device_object, type);
> + TRACE("(%p, %i)\n", device_object, type);
> +
> + switch (type)
> + {
> + case BusRelations:
> + handle_bus_relations(device_object);
> + break;
> + default:
> + FIXME("Unhandled Relation %i\n", type);
> + }
> }
> diff --git a/include/ddk/wdm.h b/include/ddk/wdm.h
> index bd3b323..e893ba2 100644
> --- a/include/ddk/wdm.h
> +++ b/include/ddk/wdm.h
> @@ -48,6 +48,7 @@ typedef NTSTATUS (WINAPI *PDRIVER_INITIALIZE)(struct _DRIVER_OBJECT *, PUNICODE_
> typedef NTSTATUS (WINAPI *PDRIVER_DISPATCH)(struct _DEVICE_OBJECT *, struct _IRP *);
> typedef void (WINAPI *PDRIVER_STARTIO)(struct _DEVICE_OBJECT *, struct _IRP *);
> typedef void (WINAPI *PDRIVER_UNLOAD)(struct _DRIVER_OBJECT *);
> +typedef NTSTATUS (WINAPI *PDRIVER_ADD_DEVICE)(struct _DRIVER_OBJECT *, struct _DEVICE_OBJECT *);
>
> typedef struct _DISPATCHER_HEADER {
> UCHAR Type;
> @@ -336,7 +337,7 @@ typedef struct _DEVICE_RELATIONS *PDEVICE_RELATIONS;
>
> typedef struct _DRIVER_EXTENSION {
> struct _DRIVER_OBJECT *DriverObject;
> - PVOID AddDevice;
> + PDRIVER_ADD_DEVICE AddDevice;
> ULONG Count;
> UNICODE_STRING ServiceKeyName;
> } DRIVER_EXTENSION, *PDRIVER_EXTENSION;
>
>
>