started moving tags to a private internal header
[reactos.git] / reactos / ntoskrnl / io / driver.c
index 045390e..a95a142 100644 (file)
@@ -1,42 +1,24 @@
-/* $Id: driver.c,v 1.36 2004/03/14 17:10:48 navaraf Exp $
+/* $Id$
  *
- * COPYRIGHT:      See COPYING in the top level directory
- * PROJECT:        ReactOS kernel
- * FILE:           ntoskrnl/io/driver.c
- * PURPOSE:        Loading and unloading of drivers
- * PROGRAMMER:     David Welch (welch@cwcom.net)
- *                 Filip Navara (xnavara@volny.cz)
- * UPDATE HISTORY:
- *                 15/05/98: Created
+ * COPYRIGHT:       See COPYING in the top level directory
+ * PROJECT:         ReactOS kernel
+ * FILE:            ntoskrnl/io/driver.c
+ * PURPOSE:         Loading and unloading of drivers
+ *
+ * PROGRAMMERS:     David Welch (welch@cwcom.net)
+ *                  Filip Navara (xnavara@volny.cz)
  */
 
 /* INCLUDES *******************************************************************/
 
-#include <limits.h>
-#include <ddk/ntddk.h>
-#include <internal/io.h>
-#include <internal/po.h>
-#include <internal/ldr.h>
-#include <internal/id.h>
-#include <internal/pool.h>
-#include <internal/se.h>
-#include <internal/mm.h>
-#include <internal/ke.h>
-#include <internal/kd.h>
-#include <rosrtl/string.h>
-
-#include <roscfg.h>
-
+#include <ntoskrnl.h>
 #define NDEBUG
 #include <internal/debug.h>
 
 /* ke/main.c */
 extern LOADER_PARAMETER_BLOCK EXPORTED KeLoaderBlock;
-
-NTSTATUS
-IopInitializeService(
-  PDEVICE_NODE DeviceNode,
-  PUNICODE_STRING ImagePath);
+extern ULONG KeTickCount;
+extern BOOLEAN SetupMode;
 
 NTSTATUS
 LdrProcessModule(PVOID ModuleLoadBase,
@@ -48,6 +30,8 @@ typedef struct _SERVICE_GROUP
   LIST_ENTRY GroupListEntry;
   UNICODE_STRING GroupName;
   BOOLEAN ServicesRunning;
+  ULONG TagCount;
+  PULONG TagArray;
 } SERVICE_GROUP, *PSERVICE_GROUP;
 
 typedef struct _SERVICE
@@ -77,67 +61,799 @@ typedef struct _DRIVER_REINIT_ITEM
 /* GLOBALS ********************************************************************/
 
 static LIST_ENTRY DriverReinitListHead;
-static PLIST_ENTRY DriverReinitTailEntry;
 static KSPIN_LOCK DriverReinitListLock;
+static PLIST_ENTRY DriverReinitTailEntry;
+
+static PLIST_ENTRY DriverBootReinitTailEntry;
+static LIST_ENTRY DriverBootReinitListHead;
+static KSPIN_LOCK DriverBootReinitListLock;
 
 static LIST_ENTRY GroupListHead = {NULL, NULL};
 static LIST_ENTRY ServiceListHead  = {NULL, NULL};
 
-POBJECT_TYPE EXPORTED IoDriverObjectType = NULL;
+static UNICODE_STRING IopHardwareDatabaseKey =
+   ROS_STRING_INITIALIZER(L"\\REGISTRY\\MACHINE\\HARDWARE\\DESCRIPTION\\SYSTEM");
+
+POBJECT_TYPE EXPORTED IoDriverObjectType = NULL;
+
+/* DECLARATIONS ***************************************************************/
+
+VOID STDCALL
+IopDeleteDriver(PVOID ObjectBody);
+
+/* PRIVATE FUNCTIONS **********************************************************/
+
+VOID 
+INIT_FUNCTION
+IopInitDriverImplementation(VOID)
+{
+   OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
+   UNICODE_STRING Name;
+
+   DPRINT1("Creating Registry Object Type\n");
+  
+   /* Initialize the Driver object type  */
+   RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer));
+   RtlInitUnicodeString(&Name, L"Driver");
+   ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer);
+   ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(DRIVER_OBJECT);
+   ObjectTypeInitializer.PoolType = NonPagedPool;
+   ObjectTypeInitializer.UseDefaultObject = TRUE;
+   ObjectTypeInitializer.DeleteProcedure = IopDeleteDriver;
+
+   ObpCreateTypeObject(&ObjectTypeInitializer, &Name, &IoDriverObjectType);
+
+   InitializeListHead(&DriverReinitListHead);
+   KeInitializeSpinLock(&DriverReinitListLock);
+   DriverReinitTailEntry = NULL;
+
+   InitializeListHead(&DriverBootReinitListHead);
+   KeInitializeSpinLock(&DriverBootReinitListLock);
+   DriverBootReinitTailEntry = NULL;
+}
+
+NTSTATUS STDCALL
+IopInvalidDeviceRequest(
+   PDEVICE_OBJECT DeviceObject,
+   PIRP Irp)
+{
+   Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
+   Irp->IoStatus.Information = 0;
+   IoCompleteRequest(Irp, IO_NO_INCREMENT);
+   return STATUS_INVALID_DEVICE_REQUEST;
+}
+
+VOID STDCALL
+IopDeleteDriver(PVOID ObjectBody)
+{
+   PDRIVER_OBJECT Object = ObjectBody;
+   KIRQL OldIrql;
+   PPRIVATE_DRIVER_EXTENSIONS DriverExtension, NextDriverExtension;
+
+   DPRINT("IopDeleteDriver(ObjectBody %x)\n", ObjectBody);
+
+   ExFreePool(Object->DriverExtension);
+   ExFreePool(Object->DriverName.Buffer);
+
+   OldIrql = KeRaiseIrqlToDpcLevel();
+
+   for (DriverExtension = Object->DriverSection;
+        DriverExtension != NULL;
+        DriverExtension = NextDriverExtension)
+   {
+      NextDriverExtension = DriverExtension->Link;
+      ExFreePoolWithTag(DriverExtension, TAG_DRIVER_EXTENSION);
+   }
+
+   KfLowerIrql(OldIrql);
+}
+
+NTSTATUS FASTCALL
+IopGetDriverObject(
+   PDRIVER_OBJECT *DriverObject,
+   PUNICODE_STRING ServiceName,
+   BOOLEAN FileSystem)
+{
+   PDRIVER_OBJECT Object;
+   WCHAR NameBuffer[MAX_PATH];
+   UNICODE_STRING DriverName;
+   OBJECT_ATTRIBUTES ObjectAttributes;
+   NTSTATUS Status;
+
+   DPRINT("IopOpenDriverObject(%p '%wZ' %x)\n",
+      DriverObject, ServiceName, FileSystem);
+
+   *DriverObject = NULL;
+
+   /* Create ModuleName string */
+   if (ServiceName == NULL || ServiceName->Buffer == NULL)
+      /* We don't know which DriverObject we have to open */
+      return STATUS_INVALID_PARAMETER_2;
+
+   if (FileSystem == TRUE)
+      wcscpy(NameBuffer, FILESYSTEM_ROOT_NAME);
+   else
+      wcscpy(NameBuffer, DRIVER_ROOT_NAME);
+   wcscat(NameBuffer, ServiceName->Buffer);
+
+   RtlInitUnicodeString(&DriverName, NameBuffer);
+   DPRINT("Driver name: '%wZ'\n", &DriverName);
+
+   /* Initialize ObjectAttributes for driver object */
+   InitializeObjectAttributes(
+      &ObjectAttributes,
+      &DriverName,
+      OBJ_OPENIF | OBJ_KERNEL_HANDLE,
+      NULL,
+      NULL);
+
+   /* Open driver object */
+   Status = ObReferenceObjectByName(
+      &DriverName,
+      0, /* Attributes */
+      NULL, /* PassedAccessState */
+      0, /* DesiredAccess */
+      IoDriverObjectType,
+      KernelMode,
+      NULL, /* ParseContext */
+      (PVOID*)&Object);
+
+   if (!NT_SUCCESS(Status))
+      return Status;
+
+   *DriverObject = Object;
+
+   return STATUS_SUCCESS;
+}
+
+NTSTATUS FASTCALL
+IopCreateDriverObject(
+   PDRIVER_OBJECT *DriverObject,
+   PUNICODE_STRING ServiceName,
+   ULONG CreateAttributes,
+   BOOLEAN FileSystem,
+   PVOID DriverImageStart,
+   ULONG DriverImageSize)
+{
+   PDRIVER_OBJECT Object;
+   WCHAR NameBuffer[MAX_PATH];
+   UNICODE_STRING DriverName;
+   OBJECT_ATTRIBUTES ObjectAttributes;
+   NTSTATUS Status;
+   ULONG i;
+   PWSTR Buffer = NULL;
+
+   DPRINT("IopCreateDriverObject(%p '%wZ' %x %p %x)\n",
+      DriverObject, ServiceName, FileSystem, DriverImageStart, DriverImageSize);
+
+   *DriverObject = NULL;
+
+   /* Create ModuleName string */
+   if (ServiceName != NULL && ServiceName->Buffer != NULL)
+   {
+      if (FileSystem == TRUE)
+         wcscpy(NameBuffer, FILESYSTEM_ROOT_NAME);
+      else
+         wcscpy(NameBuffer, DRIVER_ROOT_NAME);
+      wcscat(NameBuffer, ServiceName->Buffer);
+
+      RtlInitUnicodeString(&DriverName, NameBuffer);
+      DPRINT("Driver name: '%wZ'\n", &DriverName);
+
+      Buffer = (PWSTR)ExAllocatePool(NonPagedPool, DriverName.Length);
+      /* If we don't success, it is not a problem. Our driver
+       * object will not have associated driver name... */
+   }
+   else
+   {
+      RtlInitUnicodeString(&DriverName, NULL);
+   }
+
+   /* Initialize ObjectAttributes for driver object */
+   InitializeObjectAttributes(
+      &ObjectAttributes,
+      &DriverName,
+      CreateAttributes | OBJ_PERMANENT,
+      NULL,
+      NULL);
+
+   /* Create driver object */
+   Status = ObCreateObject(
+      KernelMode,
+      IoDriverObjectType,
+      &ObjectAttributes,
+      KernelMode,
+      NULL,
+      sizeof(DRIVER_OBJECT),
+      0,
+      0,
+      (PVOID*)&Object);
+
+   if (!NT_SUCCESS(Status))
+   {
+      return Status;
+   }
+
+   Status = ObInsertObject(Object,
+                           NULL,
+                           FILE_ALL_ACCESS,
+                           0,
+                           NULL,
+                           NULL);
+   if (!NT_SUCCESS(Status))
+   {
+      return Status;
+   }  
+
+   /* Create driver extension */
+   Object->DriverExtension = (PDRIVER_EXTENSION)
+      ExAllocatePoolWithTag(
+         NonPagedPool,
+         sizeof(DRIVER_EXTENSION),
+         TAG_DRIVER_EXTENSION);
+
+   if (Object->DriverExtension == NULL)
+   {
+      return STATUS_NO_MEMORY;
+   }
+
+   RtlZeroMemory(Object->DriverExtension, sizeof(DRIVER_EXTENSION));
+
+   Object->Type = IO_TYPE_DRIVER;
+
+   for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
+      Object->MajorFunction[i] = IopInvalidDeviceRequest;
+
+   Object->HardwareDatabase = &IopHardwareDatabaseKey;
+
+   Object->DriverStart = DriverImageStart;
+   Object->DriverSize = DriverImageSize;
+   if (Buffer)
+   {
+      if (!Object->DriverName.Buffer)
+      {
+         Object->DriverName.Buffer = Buffer;
+         Object->DriverName.Length = Object->DriverName.MaximumLength = DriverName.Length;
+         RtlCopyMemory(Object->DriverName.Buffer, DriverName.Buffer, DriverName.Length);
+      }
+      else
+         ExFreePool(Buffer);
+   }
+
+   *DriverObject = Object;
+
+   return STATUS_SUCCESS;
+}
+
+/*
+ * IopDisplayLoadingMessage
+ *
+ * Display 'Loading XXX...' message.
+ */
+
+VOID 
+FASTCALL
+INIT_FUNCTION
+IopDisplayLoadingMessage(PVOID ServiceName, 
+                         BOOLEAN Unicode)
+{
+    if (SetupMode) return;
+    CHAR TextBuffer[256];
+    if (Unicode) 
+    {
+        sprintf(TextBuffer, "Loading %S...\n", (PWCHAR)ServiceName);
+    }
+    else
+    {
+        sprintf(TextBuffer, "Loading %s...\n", (PCHAR)ServiceName);
+    }
+    HalDisplayString(TextBuffer);
+}
+
+/*
+ * IopNormalizeImagePath
+ *
+ * Normalize an image path to contain complete path.
+ *
+ * Parameters
+ *    ImagePath
+ *       The input path and on exit the result path. ImagePath.Buffer
+ *       must be allocated by ExAllocatePool on input. Caller is responsible
+ *       for freeing the buffer when it's no longer needed.
+ *
+ *    ServiceName
+ *       Name of the service that ImagePath belongs to.
+ *
+ * Return Value
+ *    Status
+ *
+ * Remarks
+ *    The input image path isn't freed on error.
+ */
+
+NTSTATUS FASTCALL
+IopNormalizeImagePath(
+   IN OUT PUNICODE_STRING ImagePath,
+   IN PUNICODE_STRING ServiceName)
+{
+   UNICODE_STRING InputImagePath;
+
+   RtlCopyMemory(
+      &InputImagePath,
+      ImagePath,
+      sizeof(UNICODE_STRING));
+
+   if (InputImagePath.Length == 0)
+   {
+      ImagePath->Length = (33 * sizeof(WCHAR)) + ServiceName->Length;
+      ImagePath->MaximumLength = ImagePath->Length + sizeof(UNICODE_NULL);
+      ImagePath->Buffer = ExAllocatePool(NonPagedPool, ImagePath->MaximumLength);
+      if (ImagePath->Buffer == NULL)
+         return STATUS_NO_MEMORY;
+
+      wcscpy(ImagePath->Buffer, L"\\SystemRoot\\system32\\drivers\\");
+      wcscat(ImagePath->Buffer, ServiceName->Buffer);
+      wcscat(ImagePath->Buffer, L".sys");
+   } else
+   if (InputImagePath.Buffer[0] != L'\\')
+   {
+      ImagePath->Length = (12 * sizeof(WCHAR)) + InputImagePath.Length;
+      ImagePath->MaximumLength = ImagePath->Length + sizeof(UNICODE_NULL);
+      ImagePath->Buffer = ExAllocatePool(NonPagedPool, ImagePath->MaximumLength);
+      if (ImagePath->Buffer == NULL)
+         return STATUS_NO_MEMORY;
+
+      wcscpy(ImagePath->Buffer, L"\\SystemRoot\\");
+      wcscat(ImagePath->Buffer, InputImagePath.Buffer);
+      ExFreePool(InputImagePath.Buffer);
+   }
+
+   return STATUS_SUCCESS;
+}
+
+/*
+ * IopLoadServiceModule
+ *
+ * Load a module specified by registry settings for service.
+ *
+ * Parameters
+ *    ServiceName
+ *       Name of the service to load.
+ *
+ * Return Value
+ *    Status
+ */
+
+NTSTATUS FASTCALL
+IopLoadServiceModule(
+   IN PUNICODE_STRING ServiceName,
+   OUT PMODULE_OBJECT *ModuleObject)
+{
+   RTL_QUERY_REGISTRY_TABLE QueryTable[3];
+   ULONG ServiceStart;
+   UNICODE_STRING ServiceImagePath;
+   NTSTATUS Status;
+
+   DPRINT("IopLoadServiceModule(%wZ, %x)\n", ServiceName, ModuleObject);
+
+   /*
+    * Get information about the service.
+    */
+
+   RtlZeroMemory(QueryTable, sizeof(QueryTable));
+
+   RtlInitUnicodeString(&ServiceImagePath, NULL);
+
+   QueryTable[0].Name = L"Start";
+   QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
+   QueryTable[0].EntryContext = &ServiceStart;
+
+   QueryTable[1].Name = L"ImagePath";
+   QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
+   QueryTable[1].EntryContext = &ServiceImagePath;
+
+   Status = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES,
+      ServiceName->Buffer, QueryTable, NULL, NULL);
+
+   if (!NT_SUCCESS(Status))
+   {
+      DPRINT("RtlQueryRegistryValues() failed (Status %x)\n", Status);
+      return Status;
+   }
+   
+   IopDisplayLoadingMessage(ServiceName->Buffer, TRUE);
+
+   /*
+    * Normalize the image path for all later processing.
+    */
+
+   Status = IopNormalizeImagePath(&ServiceImagePath, ServiceName);
+
+   if (!NT_SUCCESS(Status))
+   {
+      DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status);
+      return Status;
+   }
+
+   /*
+    * Load the module.
+    */
+
+   *ModuleObject = LdrGetModuleObject(&ServiceImagePath);
+
+   if (*ModuleObject == NULL)
+   {
+      Status = STATUS_UNSUCCESSFUL;
+
+      /*
+       * Special case for boot modules that were loaded by boot loader.
+       */
+
+      if (ServiceStart == 0)
+      {
+         ULONG i;
+         CHAR SearchName[256];
+         PCHAR ModuleName;
+         PLOADER_MODULE KeLoaderModules =
+            (PLOADER_MODULE)KeLoaderBlock.ModsAddr;
+
+         /*
+          * FIXME:
+          * Improve this searching algorithm by using the image name
+          * stored in registry entry ImageName and use the whole path
+          * (requires change in FreeLoader).
+          */
+
+         _snprintf(SearchName, sizeof(SearchName), "%wZ.sys", ServiceName);
+         for (i = 1; i < KeLoaderBlock.ModsCount; i++)
+         {
+            ModuleName = (PCHAR)KeLoaderModules[i].String;
+            if (!_stricmp(ModuleName, SearchName))
+            {
+               DPRINT("Initializing boot module\n");
+
+               /* Tell, that the module is already loaded */
+               KeLoaderModules[i].Reserved = 1;
+
+               Status = LdrProcessModule(
+                  (PVOID)KeLoaderModules[i].ModStart,
+                  &ServiceImagePath,
+                  ModuleObject);
+
+              KDB_SYMBOLFILE_HOOK(SearchName);
+
+               break;
+            }
+         }
+      }
+
+      /*
+       * Case for rest of the drivers (except disabled)
+       */
+
+      else if (ServiceStart < 4)
+      {
+         DPRINT("Loading module\n");
+         Status = LdrLoadModule(&ServiceImagePath, ModuleObject);
+      }
+   }
+   else
+   {
+      DPRINT("Module already loaded\n");
+      Status = STATUS_IMAGE_ALREADY_LOADED;
+   }
+
+   ExFreePool(ServiceImagePath.Buffer);
+
+   /*
+    * Now check if the module was loaded successfully.
+    */
+
+   if (!NT_SUCCESS(Status))
+   {
+      DPRINT("Module loading failed (Status %x)\n", Status);
+   }
+
+   DPRINT("Module loading (Status %x)\n", Status);
+
+   return Status;
+}
+
+/*
+ * IopInitializeDriverModule
+ *
+ * Initalize a loaded driver.
+ *
+ * Parameters
+ *    DeviceNode
+ *       Pointer to device node.
+ *
+ *    ModuleObject
+ *       Module object representing the driver. It can be retrieve by
+ *       IopLoadServiceModule.
+ *
+ *    ServiceName
+ *       Name of the service (as in registry).
+ *
+ *    FileSystemDriver
+ *       Set to TRUE for file system drivers.
+ *
+ *    DriverObject
+ *       On successful return this contains the driver object representing
+ *       the loaded driver.
+ */
+
+NTSTATUS FASTCALL
+IopInitializeDriverModule(
+   IN PDEVICE_NODE DeviceNode,
+   IN PMODULE_OBJECT ModuleObject,
+   IN PUNICODE_STRING ServiceName,
+   IN BOOLEAN FileSystemDriver,
+   OUT PDRIVER_OBJECT *DriverObject)
+{
+   const WCHAR ServicesKeyName[] = L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\";
+   UNICODE_STRING RegistryKey;
+   PDRIVER_INITIALIZE DriverEntry;
+   NTSTATUS Status;
+
+   DriverEntry = ModuleObject->EntryPoint;
+
+   if (ServiceName != NULL && ServiceName->Length != 0)
+   {
+      RegistryKey.Length = 0;
+      RegistryKey.MaximumLength = sizeof(ServicesKeyName) + ServiceName->Length;
+      RegistryKey.Buffer = ExAllocatePool(PagedPool, RegistryKey.MaximumLength);
+      if (RegistryKey.Buffer == NULL)
+      {
+         return STATUS_INSUFFICIENT_RESOURCES;
+      }
+      RtlAppendUnicodeToString(&RegistryKey, ServicesKeyName);
+      RtlAppendUnicodeStringToString(&RegistryKey, ServiceName);
+   }
+   else
+   {
+      RtlInitUnicodeString(&RegistryKey, NULL);
+   }
+
+   Status = IopCreateDriverObject(
+      DriverObject,
+      ServiceName,
+      0,
+      FileSystemDriver,
+      ModuleObject->Base,
+      ModuleObject->Length);
+
+   if (!NT_SUCCESS(Status))
+   {
+      DPRINT("IopCreateDriverObject failed (Status %x)\n", Status);
+      return Status;
+   }
+
+   DPRINT("RegistryKey: %wZ\n", &RegistryKey);
+   DPRINT("Calling driver entrypoint at %08lx\n", DriverEntry);
+
+   IopMarkLastReinitializeDriver();
+
+   Status = DriverEntry(*DriverObject, &RegistryKey);
+
+   RtlFreeUnicodeString(&RegistryKey);
+
+   if (!NT_SUCCESS(Status))
+   {
+      ObMakeTemporaryObject(*DriverObject);
+      ObDereferenceObject(*DriverObject);
+      return Status;
+   }
+
+   IopReinitializeDrivers();
+
+   return STATUS_SUCCESS;
+}
+
+/*
+ * IopAttachFilterDriversCallback
+ *
+ * Internal routine used by IopAttachFilterDrivers.
+ */
+
+NTSTATUS STDCALL
+IopAttachFilterDriversCallback(
+   PWSTR ValueName,
+   ULONG ValueType,
+   PVOID ValueData,
+   ULONG ValueLength,
+   PVOID Context,
+   PVOID EntryContext)
+{
+   PDEVICE_NODE DeviceNode = Context;
+   UNICODE_STRING ServiceName;
+   PWCHAR Filters;
+   PMODULE_OBJECT ModuleObject;
+   PDRIVER_OBJECT DriverObject;
+   NTSTATUS Status;
+
+   for (Filters = ValueData;
+        ((ULONG_PTR)Filters - (ULONG_PTR)ValueData) < ValueLength &&
+        *Filters != 0;
+        Filters += (ServiceName.Length / sizeof(WCHAR)) + 1)
+   {
+      DPRINT("Filter Driver: %S (%wZ)\n", Filters, &DeviceNode->InstancePath);
+      ServiceName.Buffer = Filters;
+      ServiceName.MaximumLength =
+      ServiceName.Length = wcslen(Filters) * sizeof(WCHAR);
+
+      /* Load and initialize the filter driver */
+      Status = IopLoadServiceModule(&ServiceName, &ModuleObject);
+      if (Status != STATUS_IMAGE_ALREADY_LOADED)
+      {
+         if (!NT_SUCCESS(Status))
+            continue;
+
+         Status = IopInitializeDriverModule(DeviceNode, ModuleObject, &ServiceName,
+                                            FALSE, &DriverObject);
+         if (!NT_SUCCESS(Status))
+            continue;
+      }
+      else
+      {
+         /* get existing DriverObject pointer */
+         Status = IopGetDriverObject(
+            &DriverObject,
+            &ServiceName,
+            FALSE);
+         if (!NT_SUCCESS(Status))
+            continue;
+      }
+
+      Status = IopInitializeDevice(DeviceNode, DriverObject);
+      if (!NT_SUCCESS(Status))
+         continue;
+   }
+
+   return STATUS_SUCCESS;
+}
+
+/*
+ * IopAttachFilterDrivers
+ *
+ * Load filter drivers for specified device node.
+ *
+ * Parameters
+ *    Lower
+ *       Set to TRUE for loading lower level filters or FALSE for upper
+ *       level filters.
+ */
+
+NTSTATUS FASTCALL
+IopAttachFilterDrivers(
+   PDEVICE_NODE DeviceNode,
+   BOOLEAN Lower)
+{
+   RTL_QUERY_REGISTRY_TABLE QueryTable[2];
+   PWCHAR KeyBuffer;
+   UNICODE_STRING Class;
+   WCHAR ClassBuffer[40];
+   NTSTATUS Status;
+
+   /*
+    * First load the device filters
+    */
+
+   QueryTable[0].QueryRoutine = IopAttachFilterDriversCallback;
+   if (Lower)
+     QueryTable[0].Name = L"LowerFilters";
+   else
+     QueryTable[0].Name = L"UpperFilters";
+   QueryTable[0].EntryContext = NULL;
+   QueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED;
+   QueryTable[1].QueryRoutine = NULL;
+   QueryTable[1].Name = NULL;
+
+   KeyBuffer = ExAllocatePool(
+      PagedPool,
+      (49 * sizeof(WCHAR)) + DeviceNode->InstancePath.Length);
+   wcscpy(KeyBuffer, L"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
+   wcscat(KeyBuffer, DeviceNode->InstancePath.Buffer);
+
+   RtlQueryRegistryValues(
+      RTL_REGISTRY_ABSOLUTE,
+      KeyBuffer,
+      QueryTable,
+      DeviceNode,
+      NULL);
+
+   /*
+    * Now get the class GUID
+    */
+
+   Class.Length = 0;
+   Class.MaximumLength = 40 * sizeof(WCHAR);
+   Class.Buffer = ClassBuffer;
+   QueryTable[0].QueryRoutine = NULL;
+   QueryTable[0].Name = L"ClassGUID";
+   QueryTable[0].EntryContext = &Class;
+   QueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_DIRECT;
+
+   Status = RtlQueryRegistryValues(
+      RTL_REGISTRY_ABSOLUTE,
+      KeyBuffer,
+      QueryTable,
+      DeviceNode,
+      NULL);
 
-#define TAG_DRIVER             TAG('D', 'R', 'V', 'R')
-#define TAG_DRIVER_EXTENSION   TAG('D', 'R', 'V', 'E')
+   ExFreePool(KeyBuffer);
 
-/* PRIVATE FUNCTIONS **********************************************************/
+   /*
+    * Load the class filter driver
+    */
 
-NTSTATUS STDCALL
-IopCreateDriver(PVOID ObjectBody,
-               PVOID Parent,
-               PWSTR RemainingPath,
-               POBJECT_ATTRIBUTES ObjectAttributes)
-{
-  DPRINT("LdrCreateModule(ObjectBody %x, Parent %x, RemainingPath %S)\n",
-        ObjectBody,
-        Parent,
-        RemainingPath);
-  if (RemainingPath != NULL && wcschr(RemainingPath + 1, '\\') != NULL)
-    {
-      return(STATUS_UNSUCCESSFUL);
-    }
+   if (NT_SUCCESS(Status))
+   {
+      QueryTable[0].QueryRoutine = IopAttachFilterDriversCallback;
+      if (Lower)
+         QueryTable[0].Name = L"LowerFilters";
+      else
+         QueryTable[0].Name = L"UpperFilters";
+      QueryTable[0].EntryContext = NULL;
+      QueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED;
+
+      KeyBuffer = ExAllocatePool(PagedPool, (58 * sizeof(WCHAR)) + Class.Length);
+      wcscpy(KeyBuffer, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class\\");
+      wcscat(KeyBuffer, ClassBuffer);
+
+      RtlQueryRegistryValues(
+         RTL_REGISTRY_ABSOLUTE,
+         KeyBuffer,
+         QueryTable,
+         DeviceNode,
+         NULL);
+
+      ExFreePool(KeyBuffer);
+   }
 
-  return(STATUS_SUCCESS);
+   return STATUS_SUCCESS;
 }
 
-
-VOID INIT_FUNCTION
-IopInitDriverImplementation(VOID)
+static NTSTATUS STDCALL
+IopGetGroupOrderList(PWSTR ValueName,
+                    ULONG ValueType,
+                    PVOID ValueData,
+                    ULONG ValueLength,
+                    PVOID Context,
+                    PVOID EntryContext)
 {
-  /*  Register the process object type  */
-  IoDriverObjectType = ExAllocatePool(NonPagedPool, sizeof(OBJECT_TYPE));
-  IoDriverObjectType->Tag = TAG('D', 'R', 'V', 'R');
-  IoDriverObjectType->TotalObjects = 0;
-  IoDriverObjectType->TotalHandles = 0;
-  IoDriverObjectType->MaxObjects = ULONG_MAX;
-  IoDriverObjectType->MaxHandles = ULONG_MAX;
-  IoDriverObjectType->PagedPoolCharge = 0;
-  IoDriverObjectType->NonpagedPoolCharge = sizeof(DRIVER_OBJECT);
-  IoDriverObjectType->Dump = NULL;
-  IoDriverObjectType->Open = NULL;
-  IoDriverObjectType->Close = NULL;
-  IoDriverObjectType->Delete = NULL;
-  IoDriverObjectType->Parse = NULL;
-  IoDriverObjectType->Security = NULL;
-  IoDriverObjectType->QueryName = NULL;
-  IoDriverObjectType->OkayToClose = NULL;
-  IoDriverObjectType->Create = IopCreateDriver;
-  IoDriverObjectType->DuplicationNotify = NULL;
-  RtlRosInitUnicodeStringFromLiteral(&IoDriverObjectType->TypeName, L"Driver");
-
-  ObpCreateTypeObject(IoDriverObjectType);
-
-  InitializeListHead(&DriverReinitListHead);
-  KeInitializeSpinLock(&DriverReinitListLock);
-  DriverReinitTailEntry = NULL;
+  PSERVICE_GROUP Group;
+
+  DPRINT("IopGetGroupOrderList(%S, %x, %x, %x, %x, %x)\n",
+         ValueName, ValueType, ValueData, ValueLength, Context, EntryContext);
+
+  if (ValueType == REG_BINARY &&
+      ValueData != NULL &&
+      ValueLength >= sizeof(DWORD) &&
+      ValueLength >= (*(PULONG)ValueData + 1) * sizeof(DWORD))
+    {
+      Group = (PSERVICE_GROUP)Context;
+      Group->TagCount = ((PULONG)ValueData)[0];
+      if (Group->TagCount > 0)
+        {
+         if (ValueLength >= (Group->TagCount + 1) * sizeof(DWORD))
+            {
+              Group->TagArray = ExAllocatePool(NonPagedPool, Group->TagCount * sizeof(DWORD));
+             if (Group->TagArray == NULL)
+               {
+                 Group->TagCount = 0;
+                 return STATUS_INSUFFICIENT_RESOURCES;
+               }
+             memcpy(Group->TagArray, (PULONG)ValueData + 1, Group->TagCount * sizeof(DWORD));
+           }
+         else
+           {
+             Group->TagCount = 0;
+             return STATUS_UNSUCCESSFUL;
+           }
+       }
+    }
+  return STATUS_SUCCESS;
 }
 
 static NTSTATUS STDCALL
@@ -149,6 +865,9 @@ IopCreateGroupListEntry(PWSTR ValueName,
                        PVOID EntryContext)
 {
   PSERVICE_GROUP Group;
+  RTL_QUERY_REGISTRY_TABLE QueryTable[2];
+  NTSTATUS Status;
+
 
   if (ValueType == REG_SZ)
     {
@@ -163,13 +882,22 @@ IopCreateGroupListEntry(PWSTR ValueName,
 
       RtlZeroMemory(Group, sizeof(SERVICE_GROUP));
 
-      if (!RtlCreateUnicodeString(&Group->GroupName,
-                                 (PWSTR)ValueData))
+      if (!RtlpCreateUnicodeString(&Group->GroupName, (PWSTR)ValueData, NonPagedPool))
        {
          ExFreePool(Group);
          return(STATUS_INSUFFICIENT_RESOURCES);
        }
 
+      RtlZeroMemory(&QueryTable, sizeof(QueryTable));
+      QueryTable[0].Name = (PWSTR)ValueData;
+      QueryTable[0].QueryRoutine = IopGetGroupOrderList;
+
+      Status = RtlQueryRegistryValues(RTL_REGISTRY_CONTROL,
+                                     L"GroupOrderList",
+                                     QueryTable,
+                                     (PVOID)Group,
+                                     NULL);
+      DPRINT("%x %d %S\n", Status, Group->TagCount, (PWSTR)ValueData);
 
       InsertTailList(&GroupListHead,
                     &Group->GroupListEntry);
@@ -182,7 +910,7 @@ IopCreateGroupListEntry(PWSTR ValueName,
 static NTSTATUS STDCALL
 IopCreateServiceListEntry(PUNICODE_STRING ServiceName)
 {
-  RTL_QUERY_REGISTRY_TABLE QueryTable[6];
+  RTL_QUERY_REGISTRY_TABLE QueryTable[7];
   PSERVICE Service;
   NTSTATUS Status;
 
@@ -221,6 +949,10 @@ IopCreateServiceListEntry(PUNICODE_STRING ServiceName)
   QueryTable[4].Flags = RTL_QUERY_REGISTRY_DIRECT;
   QueryTable[4].EntryContext = &Service->ImagePath;
 
+  QueryTable[5].Name = L"Tag";
+  QueryTable[5].Flags = RTL_QUERY_REGISTRY_DIRECT;
+  QueryTable[5].EntryContext = &Service->Tag;
+
   Status = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES,
                                  ServiceName->Buffer,
                                  QueryTable,
@@ -228,8 +960,20 @@ IopCreateServiceListEntry(PUNICODE_STRING ServiceName)
                                  NULL);
   if (!NT_SUCCESS(Status) || Service->Start > 1)
     {
-      RtlFreeUnicodeString(&Service->ServiceGroup);
-      RtlFreeUnicodeString(&Service->ImagePath);
+      /*
+       * If something goes wrong during RtlQueryRegistryValues
+       * it'll just drop everything on the floor and return,
+       * so you have to check if the buffers were filled.
+       * Luckily we zerofilled the Service.
+       */
+      if (Service->ServiceGroup.Buffer)
+        {
+          ExFreePool(Service->ServiceGroup.Buffer);
+        }
+      if (Service->ImagePath.Buffer)
+        {
+          ExFreePool(Service->ImagePath.Buffer);
+        }
       ExFreePool(Service);
       return(Status);
     }
@@ -258,8 +1002,8 @@ IopCreateServiceListEntry(PUNICODE_STRING ServiceName)
   DPRINT("RegistryPath: '%wZ'\n", &Service->RegistryPath);
   DPRINT("ServiceGroup: '%wZ'\n", &Service->ServiceGroup);
   DPRINT("ImagePath: '%wZ'\n", &Service->ImagePath);
-  DPRINT("Start %lx  Type %lx  ErrorControl %lx\n",
-        Service->Start, Service->Type, Service->ErrorControl);
+  DPRINT("Start %lx  Type %lx  Tag %lx ErrorControl %lx\n",
+        Service->Start, Service->Type, Service->Tag, Service->ErrorControl);
 
   /* Append service entry */
   InsertTailList(&ServiceListHead,
@@ -315,8 +1059,8 @@ IoCreateDriverList(VOID)
                             NULL,
                             NULL);
 
-  Status = NtOpenKey(&KeyHandle,
-                    0x10001,
+  Status = ZwOpenKey(&KeyHandle,
+                    KEY_ENUMERATE_SUB_KEYS,
                     &ObjectAttributes);
   if (!NT_SUCCESS(Status))
     {
@@ -327,14 +1071,14 @@ IoCreateDriverList(VOID)
   KeyInfo = ExAllocatePool(NonPagedPool, KeyInfoLength);
   if (KeyInfo == NULL)
     {
-      NtClose(KeyHandle);
+      ZwClose(KeyHandle);
       return(STATUS_INSUFFICIENT_RESOURCES);
     }
 
   Index = 0;
   while (TRUE)
     {
-      Status = NtEnumerateKey(KeyHandle,
+      Status = ZwEnumerateKey(KeyHandle,
                              Index,
                              KeyBasicInformation,
                              KeyInfo,
@@ -362,7 +1106,7 @@ IoCreateDriverList(VOID)
     }
 
   ExFreePool(KeyInfo);
-  NtClose(KeyHandle);
+  ZwClose(KeyHandle);
 
   DPRINT("IoCreateDriverList() done\n");
 
@@ -385,8 +1129,12 @@ IoDestroyDriverList(VOID)
     {
       CurrentGroup = CONTAINING_RECORD(GroupEntry, SERVICE_GROUP, GroupListEntry);
 
-      RtlFreeUnicodeString(&CurrentGroup->GroupName);
+      ExFreePool(CurrentGroup->GroupName.Buffer);
       RemoveEntryList(GroupEntry);
+      if (CurrentGroup->TagArray)
+        {
+         ExFreePool(CurrentGroup->TagArray);
+       }
       ExFreePool(CurrentGroup);
 
       GroupEntry = GroupListHead.Flink;
@@ -398,10 +1146,10 @@ IoDestroyDriverList(VOID)
     {
       CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
 
-      RtlFreeUnicodeString(&CurrentService->ServiceName);
-      RtlFreeUnicodeString(&CurrentService->RegistryPath);
-      RtlFreeUnicodeString(&CurrentService->ServiceGroup);
-      RtlFreeUnicodeString(&CurrentService->ImagePath);
+      ExFreePool(CurrentService->ServiceName.Buffer);
+      ExFreePool(CurrentService->RegistryPath.Buffer);
+      ExFreePool(CurrentService->ServiceGroup.Buffer);
+      ExFreePool(CurrentService->ImagePath.Buffer);
       RemoveEntryList(ServiceEntry);
       ExFreePool(CurrentService);
 
@@ -413,29 +1161,15 @@ IoDestroyDriverList(VOID)
   return(STATUS_SUCCESS);
 }
 
-VOID STATIC
+VOID STATIC INIT_FUNCTION
 MiFreeBootDriverMemory(PVOID StartAddress, ULONG Length)
 {
-  ULONG i;
-
-  for (i = 0; i < PAGE_ROUND_UP(Length)/PAGE_SIZE; i++)
-  {
-     MmDeleteVirtualMapping(NULL, (char*)StartAddress + i * PAGE_SIZE, TRUE, NULL, NULL);
-  }
-}
-
-/*
- * IopDisplayLoadingMessage
- *
- * Display 'Loading XXX...' message.
- */
+   ULONG i;
 
-VOID
-IopDisplayLoadingMessage(PWCHAR ServiceName)
-{
-   CHAR TextBuffer[256];
-   sprintf(TextBuffer, "Loading %S...\n", ServiceName);
-   HalDisplayString(TextBuffer);
+   for (i = 0; i < PAGE_ROUND_UP(Length) / PAGE_SIZE; i++)
+   {
+      MmDeleteVirtualMapping(NULL, (char*)StartAddress + i * PAGE_SIZE, TRUE, NULL, NULL);
+   }
 }
 
 /*
@@ -444,7 +1178,7 @@ IopDisplayLoadingMessage(PWCHAR ServiceName)
  * Initialize a driver that is already loaded in memory.
  */
 
-NTSTATUS INIT_FUNCTION
+NTSTATUS FASTCALL INIT_FUNCTION
 IopInitializeBuiltinDriver(
    PDEVICE_NODE ModuleDeviceNode,
    PVOID ModuleLoadBase,
@@ -453,8 +1187,8 @@ IopInitializeBuiltinDriver(
 {
    PMODULE_OBJECT ModuleObject;
    PDEVICE_NODE DeviceNode;
+   PDRIVER_OBJECT DriverObject;
    NTSTATUS Status;
-   CHAR TextBuffer[256];
    PCHAR FileNameWithoutPath;
    LPWSTR FileExtension;
 
@@ -462,14 +1196,14 @@ IopInitializeBuiltinDriver(
       FileName, ModuleLoadBase, ModuleLength);
 
    /*
-    * Display 'Initializing XXX...' message
+    * Display 'Loading XXX...' message
     */
-   sprintf(TextBuffer, "Initializing %s...\n", FileName);
-   HalDisplayString(TextBuffer);
+   IopDisplayLoadingMessage(FileName, FALSE);
 
    /*
     * Determine the right device object
     */
+
    if (ModuleDeviceNode == NULL)
    {
       /* Use IopRootDeviceNode for now */
@@ -487,6 +1221,7 @@ IopInitializeBuiltinDriver(
    /*
     * Generate filename without path (not needed by freeldr)
     */
+
    FileNameWithoutPath = strrchr(FileName, '\\');
    if (FileNameWithoutPath == NULL)
    {
@@ -496,38 +1231,52 @@ IopInitializeBuiltinDriver(
    /*
     * Load the module
     */
+
    RtlCreateUnicodeStringFromAsciiz(&DeviceNode->ServiceName,
       FileNameWithoutPath);
    Status = LdrProcessModule(ModuleLoadBase, &DeviceNode->ServiceName,
       &ModuleObject);
-   if (ModuleObject == NULL)
+   if (!NT_SUCCESS(Status))
    {
       if (ModuleDeviceNode == NULL)
          IopFreeDeviceNode(DeviceNode);
       CPRINT("Driver load failed, status (%x)\n", Status);
-      return STATUS_UNSUCCESSFUL;
+      return Status;
    }
 
+   /* Load symbols */
+   KDB_SYMBOLFILE_HOOK(FileName);
+
    /*
     * Strip the file extension from ServiceName
     */
+
    FileExtension = wcsrchr(DeviceNode->ServiceName.Buffer, '.');
    if (FileExtension != NULL)
    {
-      DeviceNode->ServiceName.Length -= wcslen(DeviceNode->ServiceName.Buffer);
+      DeviceNode->ServiceName.Length -= wcslen(FileExtension) * sizeof(WCHAR);
       FileExtension[0] = 0;
    }
 
    /*
     * Initialize the driver
     */
-   Status = IopInitializeDriver(ModuleObject->EntryPoint, DeviceNode,
-      FALSE, ModuleObject->Base, ModuleObject->Length, TRUE);
+
+   Status = IopInitializeDriverModule(DeviceNode, ModuleObject,
+      &DeviceNode->ServiceName, FALSE, &DriverObject);
+
    if (!NT_SUCCESS(Status))
    {
       if (ModuleDeviceNode == NULL)
          IopFreeDeviceNode(DeviceNode);
       CPRINT("Driver load failed, status (%x)\n", Status);
+      return Status;
+   }
+
+   Status = IopInitializeDevice(DeviceNode, DriverObject);
+   if (NT_SUCCESS(Status))
+   {
+      Status = IopStartDevice(DeviceNode);
    }
 
    return Status;
@@ -540,12 +1289,12 @@ IopInitializeBuiltinDriver(
  *
  * Parameters
  *    None
- *             
+ *
  * Return Value
  *    None
  */
 
-VOID INIT_FUNCTION
+VOID FASTCALL
 IopInitializeBootDrivers(VOID)
 {
    ULONG BootDriverCount;
@@ -556,11 +1305,13 @@ IopInitializeBootDrivers(VOID)
    PCHAR Extension;
    PLOADER_MODULE KeLoaderModules = (PLOADER_MODULE)KeLoaderBlock.ModsAddr;
    ULONG i;
+   UNICODE_STRING DriverName;
+   NTSTATUS Status;
 
    DPRINT("IopInitializeBootDrivers()\n");
 
    BootDriverCount = 0;
-   for (i = 2; i < KeLoaderBlock.ModsCount; i++)
+   for (i = 0; i < KeLoaderBlock.ModsCount; i++)
    {
       ModuleStart = KeLoaderModules[i].ModStart;
       ModuleSize = KeLoaderModules[i].ModEnd - ModuleStart;
@@ -570,43 +1321,44 @@ IopInitializeBootDrivers(VOID)
       if (Extension == NULL)
          Extension = "";
 
-      /*
-       * Pass symbol files to kernel debugger
-       */
-      if (!_stricmp(Extension, ".sym"))
+      if (!_stricmp(Extension, ".sym") || !_stricmp(Extension, ".dll"))
       {
-         KDB_SYMBOLFILE_HOOK((PVOID)ModuleStart, ModuleName, ModuleSize);
-      } else
+        /* Process symbols for *.exe and *.dll */
+        KDB_SYMBOLFILE_HOOK(ModuleName);
 
-      /*
-       * Load builtin driver
-       */
-      if (!_stricmp(Extension, ".sys"))
+        /* Log *.exe and *.dll files */
+        RtlCreateUnicodeStringFromAsciiz(&DriverName, ModuleName);
+        IopBootLog(&DriverName, TRUE);
+        RtlFreeUnicodeString(&DriverName);
+      }
+      else if (!_stricmp(Extension, ".sys"))
       {
+         /* Initialize and log boot start driver */
          if (!ModuleLoaded)
          {
-            IopInitializeBuiltinDriver(NULL, (PVOID)ModuleStart, ModuleName,
-               ModuleSize);
+            Status = IopInitializeBuiltinDriver(NULL,
+                                                (PVOID)ModuleStart,
+                                                ModuleName,
+                                                ModuleSize);
+            RtlCreateUnicodeStringFromAsciiz(&DriverName, ModuleName);
+            IopBootLog(&DriverName, NT_SUCCESS(Status) ? TRUE : FALSE);
+            RtlFreeUnicodeString(&DriverName);
          }
-         ++BootDriverCount;
+         BootDriverCount++;
       }
+   }
 
-      /*
-       * Free memory for all boot files, except ntoskrnl.exe and hal.dll
-       */
-#ifdef KDBG
-      /*
-       * Do not free the memory from symbol files, if the kernel debugger
-       * is active
-       */
-      if (_stricmp(Extension, ".sym"))
-#endif
-      {
-         MiFreeBootDriverMemory((PVOID)KeLoaderModules[i].ModStart,
-            KeLoaderModules[i].ModEnd - KeLoaderModules[i].ModStart);
-      }
+   /*
+    * Free memory for all boot files, except ntoskrnl.exe.
+    */
+   for (i = 1; i < KeLoaderBlock.ModsCount; i++)
+   {
+       MiFreeBootDriverMemory((PVOID)KeLoaderModules[i].ModStart,
+                              KeLoaderModules[i].ModEnd - KeLoaderModules[i].ModStart);
    }
 
+   KeLoaderBlock.ModsCount = 0;
+
    if (BootDriverCount == 0)
    {
       DbgPrint("No boot drivers available.\n");
@@ -614,6 +1366,46 @@ IopInitializeBootDrivers(VOID)
    }
 }
 
+static INIT_FUNCTION NTSTATUS
+IopLoadDriver(PSERVICE Service)
+{
+   NTSTATUS Status = STATUS_UNSUCCESSFUL;
+
+   IopDisplayLoadingMessage(Service->ServiceName.Buffer, TRUE);
+   Status = ZwLoadDriver(&Service->RegistryPath);
+   IopBootLog(&Service->ImagePath, NT_SUCCESS(Status) ? TRUE : FALSE);
+   if (!NT_SUCCESS(Status))
+   {
+      DPRINT("IopLoadDriver() failed (Status %lx)\n", Status);
+#if 0
+      if (Service->ErrorControl == 1)
+      {
+         /* Log error */
+      }
+      else if (Service->ErrorControl == 2)
+      {
+         if (IsLastKnownGood == FALSE)
+         {
+            /* Boot last known good configuration */
+         }
+      }
+      else if (Service->ErrorControl == 3)
+      {
+         if (IsLastKnownGood == FALSE)
+         {
+            /* Boot last known good configuration */
+         }
+         else
+         {
+            /* BSOD! */
+         }
+      }
+#endif
+   }
+   return Status;
+}
+
+
 /*
  * IopInitializeSystemDrivers
  *
@@ -621,12 +1413,12 @@ IopInitializeBootDrivers(VOID)
  *
  * Parameters
  *    None
- *             
+ *
  * Return Value
  *    None
  */
 
-VOID INIT_FUNCTION
+VOID FASTCALL
 IopInitializeSystemDrivers(VOID)
 {
    PLIST_ENTRY GroupEntry;
@@ -634,6 +1426,7 @@ IopInitializeSystemDrivers(VOID)
    PSERVICE_GROUP CurrentGroup;
    PSERVICE CurrentService;
    NTSTATUS Status;
+   ULONG i;
 
    DPRINT("IopInitializeSystemDrivers()\n");
 
@@ -644,257 +1437,55 @@ IopInitializeSystemDrivers(VOID)
 
       DPRINT("Group: %wZ\n", &CurrentGroup->GroupName);
 
+      /* Load all drivers with a valid tag */
+      for (i = 0; i < CurrentGroup->TagCount; i++)
+      {
+         ServiceEntry = ServiceListHead.Flink;
+         while (ServiceEntry != &ServiceListHead)
+         {
+            CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
+
+            if ((RtlCompareUnicodeString(&CurrentGroup->GroupName,
+                                         &CurrentService->ServiceGroup, TRUE) == 0) &&
+               (CurrentService->Start == 1 /*SERVICE_SYSTEM_START*/) &&
+               (CurrentService->Tag == CurrentGroup->TagArray[i]))
+           {
+              DPRINT("  Path: %wZ\n", &CurrentService->RegistryPath);
+               Status = IopLoadDriver(CurrentService);
+           }
+            ServiceEntry = ServiceEntry->Flink;
+         }
+      }
+
+      /* Load all drivers without a tag or with an invalid tag */
       ServiceEntry = ServiceListHead.Flink;
       while (ServiceEntry != &ServiceListHead)
       {
          CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
-
          if ((RtlCompareUnicodeString(&CurrentGroup->GroupName,
-              &CurrentService->ServiceGroup, TRUE) == 0) &&
+                                      &CurrentService->ServiceGroup, TRUE) == 0) &&
             (CurrentService->Start == 1 /*SERVICE_SYSTEM_START*/))
         {
-            DPRINT("  Path: %wZ\n", &CurrentService->RegistryPath);
-            IopDisplayLoadingMessage(CurrentService->ServiceName.Buffer);
-            Status = NtLoadDriver(&CurrentService->RegistryPath);
-            if (!NT_SUCCESS(Status))
-            {
-               DPRINT("NtLoadDriver() failed (Status %lx)\n", Status);
-#if 0
-               if (CurrentService->ErrorControl == 1)
-               {
-                  /* Log error */
-               } else
-               if (CurrentService->ErrorControl == 2)
-               {
-                  if (IsLastKnownGood == FALSE)
-                  {
-                     /* Boot last known good configuration */
-                  }
-               } else
-               if (CurrentService->ErrorControl == 3)
-               {
-                  if (IsLastKnownGood == FALSE)
-                  {
-                     /* Boot last known good configuration */
-                  } else
-                  {
-                     /* BSOD! */
-                  }
-               }
-#endif
-            }
+           for (i = 0; i < CurrentGroup->TagCount; i++)
+           {
+              if (CurrentGroup->TagArray[i] == CurrentService->Tag)
+              {
+                 break;
+              }
+           }
+           if (i >= CurrentGroup->TagCount)
+           {
+               DPRINT("  Path: %wZ\n", &CurrentService->RegistryPath);
+               Status = IopLoadDriver(CurrentService);
+           }
         }
          ServiceEntry = ServiceEntry->Flink;
       }
 
-      GroupEntry = GroupEntry->Flink;
-   }
-
-   DPRINT("IopInitializeSystemDrivers() done\n");
-}
-
-/*
- * IopGetDriverNameFromServiceKey
- *
- * Returns a module path from service registry key.
- *
- * Parameters
- *    RelativeTo
- *       Relative path identifier.
- *    PathName
- *       Relative key path name.
- *    ImagePath
- *       The result path.
- *
- * Return Value
- *    Status
- */
-
-NTSTATUS STDCALL
-IopGetDriverNameFromServiceKey(
-  ULONG RelativeTo,
-  PWSTR PathName,
-  PUNICODE_STRING ImagePath)
-{
-   RTL_QUERY_REGISTRY_TABLE QueryTable[2];
-   UNICODE_STRING RegistryImagePath;
-   NTSTATUS Status;
-   PWSTR ServiceName;
-
-   RtlZeroMemory(&QueryTable, sizeof(QueryTable));
-   RtlInitUnicodeString(&RegistryImagePath, NULL);
-
-   QueryTable[0].Name = L"ImagePath";
-   QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
-   QueryTable[0].EntryContext = &RegistryImagePath;
-
-   Status = RtlQueryRegistryValues(RelativeTo,
-      PathName, QueryTable, NULL, NULL);
-   if (!NT_SUCCESS(Status))
-   {
-      DPRINT("RtlQueryRegistryValues() failed (Status %lx)\n", Status);
-      RtlFreeUnicodeString(&RegistryImagePath);
-      return STATUS_UNSUCCESSFUL;
-   }
-
-   if (RegistryImagePath.Length == 0)
-   {
-      ServiceName = wcsrchr(PathName, L'\\');
-      if (ServiceName == NULL)
-      {
-         ServiceName = PathName;
-      }
-      else
-      {
-         ServiceName++;
-      }
-      
-      ImagePath->Length = (33 + wcslen(ServiceName)) * sizeof(WCHAR);
-      ImagePath->MaximumLength = ImagePath->Length + sizeof(UNICODE_NULL);
-      ImagePath->Buffer = ExAllocatePool(NonPagedPool, ImagePath->MaximumLength);
-      if (ImagePath->Buffer == NULL)
-      {
-         return STATUS_UNSUCCESSFUL;
-      }
-      wcscpy(ImagePath->Buffer, L"\\SystemRoot\\system32\\drivers\\");
-      wcscat(ImagePath->Buffer, ServiceName);
-      wcscat(ImagePath->Buffer, L".sys");
-   } else
-   if (RegistryImagePath.Buffer[0] != L'\\')
-   {
-      ImagePath->Length = (12 + wcslen(RegistryImagePath.Buffer)) * sizeof(WCHAR);
-      ImagePath->MaximumLength = ImagePath->Length + sizeof(UNICODE_NULL);
-      ImagePath->Buffer = ExAllocatePool(NonPagedPool, ImagePath->MaximumLength);
-      if (ImagePath->Buffer == NULL)
-      {
-         RtlFreeUnicodeString(&RegistryImagePath);
-         return STATUS_UNSUCCESSFUL;
-      }
-      wcscpy(ImagePath->Buffer, L"\\SystemRoot\\");
-      wcscat(ImagePath->Buffer, RegistryImagePath.Buffer);
-      RtlFreeUnicodeString(&RegistryImagePath);
-   } else
-   {
-      ImagePath->Length = RegistryImagePath.Length;
-      ImagePath->MaximumLength = RegistryImagePath.MaximumLength;
-      ImagePath->Buffer = RegistryImagePath.Buffer;
-   }
-
-   return STATUS_SUCCESS;
-}
-
-/*
- * IopInitializeDeviceNodeService
- *
- * Initialize service for given device node.
- *
- * Parameters
- *    DeviceNode
- *       The device node to initialize service for.
- *    BootDriverOnly
- *       Initialize driver only if it's marked as boot start.
- *
- * Return Value
- *    Status
- */
-
-NTSTATUS
-IopInitializeDeviceNodeService(PDEVICE_NODE DeviceNode, BOOLEAN BootDriverOnly)
-{
-   NTSTATUS Status;
-   ULONG ServiceStart;
-   RTL_QUERY_REGISTRY_TABLE QueryTable[2];
-
-   if (DeviceNode->ServiceName.Buffer == NULL)
-   {
-      return STATUS_UNSUCCESSFUL;
-   }
-
-   /*
-    * Get service start value
-    */
-
-   RtlZeroMemory(QueryTable, sizeof(QueryTable));
-   QueryTable[0].Name = L"Start";
-   QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
-   QueryTable[0].EntryContext = &ServiceStart;
-   Status = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES,
-      DeviceNode->ServiceName.Buffer, QueryTable, NULL, NULL);
-   if (!NT_SUCCESS(Status))
-   {
-      DPRINT("RtlQueryRegistryValues() failed (Status %x)\n", Status);
-      return Status;
-   }
-
-   if (BootDriverOnly)
-   {
-      PLOADER_MODULE KeLoaderModules = (PLOADER_MODULE)KeLoaderBlock.ModsAddr;
-
-      /*
-       * Find and initialize boot driver
-       */
-      if (ServiceStart == 0 /*SERVICE_BOOT_START*/)
-      {
-         ULONG i;
-         CHAR SearchName[256];
-         ULONG ModuleStart, ModuleSize;
-         PCHAR ModuleName;
-
-         /* FIXME: Guard for buffer overflow */
-         sprintf(SearchName, "%S.sys", DeviceNode->ServiceName.Buffer);
-         for (i = 1; i < KeLoaderBlock.ModsCount; i++)
-         {
-            ModuleStart = KeLoaderModules[i].ModStart;
-            ModuleSize = KeLoaderModules[i].ModEnd - ModuleStart;
-            ModuleName = (PCHAR)KeLoaderModules[i].String;
-            if (!strcmp(ModuleName, SearchName))
-            {
-               IopInitializeBuiltinDriver(DeviceNode,
-                  (PVOID)ModuleStart, ModuleName, ModuleSize);
-               /* Tell, that the module is already loaded */
-               KeLoaderModules[i].Reserved = 1;
-            }
-         }
-         return STATUS_SUCCESS;
-      } else
-      {
-         return STATUS_UNSUCCESSFUL;
-      }
-   } else
-   if (ServiceStart < 4)
-   {
-      UNICODE_STRING ImagePath;
-
-      /*
-       * Get service path
-       */
-      Status = IopGetDriverNameFromServiceKey(RTL_REGISTRY_SERVICES,
-          DeviceNode->ServiceName.Buffer, &ImagePath);
-      if (!NT_SUCCESS(Status))
-      {
-         DPRINT("IopGetDriverNameFromKeyNode() failed (Status %x)\n", Status);
-         return Status;
-      }
-
-      /*
-       * Display loading message
-       */
-      IopDisplayLoadingMessage(DeviceNode->ServiceName.Buffer);
-
-      /*
-       * Load the service
-       */
-      Status = IopInitializeService(DeviceNode, &ImagePath);
-
-      /*
-       * Free the service path
-       */
-      RtlFreeUnicodeString(&ImagePath);
+      GroupEntry = GroupEntry->Flink;
    }
-   else
-      Status = STATUS_UNSUCCESSFUL;
 
-   return Status;
+   DPRINT("IopInitializeSystemDrivers() done\n");
 }
 
 /*
@@ -905,11 +1496,12 @@ IopInitializeDeviceNodeService(PDEVICE_NODE DeviceNode, BOOLEAN BootDriverOnly)
  * Parameters
  *    DriverServiceName
  *       Name of the service to unload (registry key).
+ *
  *    UnloadPnpDrivers
  *       Whether to unload Plug & Plug or only legacy drivers. If this
  *       parameter is set to FALSE, the routine will unload only legacy
  *       drivers.
- *             
+ *
  * Return Value
  *    Status
  *
@@ -920,7 +1512,9 @@ IopInitializeDeviceNodeService(PDEVICE_NODE DeviceNode, BOOLEAN BootDriverOnly)
 NTSTATUS STDCALL
 IopUnloadDriver(PUNICODE_STRING DriverServiceName, BOOLEAN UnloadPnpDrivers)
 {
+   RTL_QUERY_REGISTRY_TABLE QueryTable[2];
    UNICODE_STRING ImagePath;
+   UNICODE_STRING ServiceName;
    UNICODE_STRING ObjectName;
    PDRIVER_OBJECT DriverObject;
    PMODULE_OBJECT ModuleObject;
@@ -930,17 +1524,21 @@ IopUnloadDriver(PUNICODE_STRING DriverServiceName, BOOLEAN UnloadPnpDrivers)
    DPRINT("IopUnloadDriver('%wZ', %d)\n", DriverServiceName, UnloadPnpDrivers);
 
    /*
-    * Get the service name from the module name
+    * Get the service name from the registry key name
     */
+
    Start = wcsrchr(DriverServiceName->Buffer, L'\\');
    if (Start == NULL)
       Start = DriverServiceName->Buffer;
    else
       Start++;
 
+   RtlInitUnicodeString(&ServiceName, Start);
+
    /*
     * Construct the driver object name
     */
+
    ObjectName.Length = (wcslen(Start) + 8) * sizeof(WCHAR);
    ObjectName.MaximumLength = ObjectName.Length + sizeof(WCHAR);
    ObjectName.Buffer = ExAllocatePool(NonPagedPool, ObjectName.MaximumLength);
@@ -951,8 +1549,10 @@ IopUnloadDriver(PUNICODE_STRING DriverServiceName, BOOLEAN UnloadPnpDrivers)
    /*
     * Find the driver object
     */
+
    Status = ObReferenceObjectByName(&ObjectName, 0, 0, 0, IoDriverObjectType,
       KernelMode, 0, (PVOID*)&DriverObject);
+
    if (!NT_SUCCESS(Status))
    {
       DPRINT("Can't locate driver object for %wZ\n", ObjectName);
@@ -962,22 +1562,46 @@ IopUnloadDriver(PUNICODE_STRING DriverServiceName, BOOLEAN UnloadPnpDrivers)
    /*
     * Free the buffer for driver object name
     */
+
    ExFreePool(ObjectName.Buffer);
 
    /*
     * Get path of service...
     */
-   Status = IopGetDriverNameFromServiceKey(RTL_REGISTRY_ABSOLUTE,
-       DriverServiceName->Buffer, &ImagePath);
+
+   RtlZeroMemory(QueryTable, sizeof(QueryTable));
+
+   RtlInitUnicodeString(&ImagePath, NULL);
+
+   QueryTable[0].Name = L"ImagePath";
+   QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
+   QueryTable[0].EntryContext = &ImagePath;
+
+   Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
+       DriverServiceName->Buffer, QueryTable, NULL, NULL);
+
+   if (!NT_SUCCESS(Status))
+   {
+      DPRINT("RtlQueryRegistryValues() failed (Status %x)\n", Status);
+      return Status;
+   }
+
+   /*
+    * Normalize the image path for all later processing.
+    */
+
+   Status = IopNormalizeImagePath(&ImagePath, &ServiceName);
+
    if (!NT_SUCCESS(Status))
    {
-      DPRINT("IopGetDriverNameFromKeyNode() failed (Status %x)\n", Status);
+      DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status);
       return Status;
    }
 
    /*
     * ... and check if it's loaded
     */
+
    ModuleObject = LdrGetModuleObject(&ImagePath);
    if (ModuleObject == NULL)
    {
@@ -987,11 +1611,13 @@ IopUnloadDriver(PUNICODE_STRING DriverServiceName, BOOLEAN UnloadPnpDrivers)
    /*
     * Free the service path
     */
-   RtlFreeUnicodeString(&ImagePath);
+
+   ExFreePool(ImagePath.Buffer);
 
    /*
     * Unload the module and release the references to the device object
     */
+
    if (DriverObject->DriverUnload)
       (*DriverObject->DriverUnload)(DriverObject);
    ObDereferenceObject(DriverObject);
@@ -1001,7 +1627,204 @@ IopUnloadDriver(PUNICODE_STRING DriverServiceName, BOOLEAN UnloadPnpDrivers)
    return STATUS_SUCCESS;
 }
 
-/* FUNCTIONS ******************************************************************/
+VOID FASTCALL
+IopMarkLastReinitializeDriver(VOID)
+{
+  KIRQL Irql;
+
+  KeAcquireSpinLock(&DriverReinitListLock,
+                   &Irql);
+
+  if (IsListEmpty(&DriverReinitListHead))
+  {
+    DriverReinitTailEntry = NULL;
+  }
+  else
+  {
+    DriverReinitTailEntry = DriverReinitListHead.Blink;
+  }
+
+  KeReleaseSpinLock(&DriverReinitListLock,
+                   Irql);
+}
+
+
+VOID FASTCALL
+IopReinitializeDrivers(VOID)
+{
+  PDRIVER_REINIT_ITEM ReinitItem;
+  PLIST_ENTRY Entry;
+  KIRQL Irql;
+
+  KeAcquireSpinLock(&DriverReinitListLock,
+                   &Irql);
+
+  if (DriverReinitTailEntry == NULL)
+  {
+    KeReleaseSpinLock(&DriverReinitListLock,
+                     Irql);
+    return;
+  }
+
+  KeReleaseSpinLock(&DriverReinitListLock,
+                   Irql);
+
+  for (;;)
+  {
+    Entry = ExInterlockedRemoveHeadList(&DriverReinitListHead,
+                                       &DriverReinitListLock);
+    if (Entry == NULL)
+      return;
+
+    ReinitItem = (PDRIVER_REINIT_ITEM)CONTAINING_RECORD(Entry, DRIVER_REINIT_ITEM, ItemEntry);
+
+    /* Increment reinitialization counter */
+    ReinitItem->DriverObject->DriverExtension->Count++;
+
+    ReinitItem->ReinitRoutine(ReinitItem->DriverObject,
+                             ReinitItem->Context,
+                             ReinitItem->DriverObject->DriverExtension->Count);
+
+    ExFreePool(Entry);
+
+    if (Entry == DriverReinitTailEntry)
+      return;
+  }
+}
+
+/* PUBLIC FUNCTIONS ***********************************************************/
+
+
+/*
+ * @implemented
+ */
+NTSTATUS
+STDCALL
+IoCreateDriver (
+       IN PUNICODE_STRING DriverName,   OPTIONAL
+       IN PDRIVER_INITIALIZE InitializationFunction
+       )
+{
+    WCHAR NameBuffer[100];
+    USHORT NameLength;
+    UNICODE_STRING LocalDriverName; /* To reduce code if no name given */
+    NTSTATUS Status;
+    OBJECT_ATTRIBUTES ObjectAttributes;
+    ULONG ObjectSize;
+    PDRIVER_OBJECT DriverObject;
+    UNICODE_STRING ServiceKeyName;
+    HANDLE hDriver;
+    ULONG i;
+
+    /* First, create a unique name for the driver if we don't have one */
+    if (!DriverName) {
+
+        /* Create a random name and set up the string*/
+        NameLength = swprintf(NameBuffer, L"\\Driver\\%08u", KeTickCount);
+        LocalDriverName.Length = NameLength * sizeof(WCHAR);
+        LocalDriverName.MaximumLength = LocalDriverName.Length + sizeof(UNICODE_NULL);
+        LocalDriverName.Buffer = NameBuffer;
+
+    } else {
+
+        /* So we can avoid another code path, use a local var */
+        LocalDriverName = *DriverName;
+    }
+
+    /* Initialize the Attributes */
+    ObjectSize = sizeof(DRIVER_OBJECT) + sizeof(DRIVER_EXTENSION);
+    InitializeObjectAttributes(&ObjectAttributes,
+                               &LocalDriverName,
+                               OBJ_PERMANENT | OBJ_CASE_INSENSITIVE,
+                               NULL,
+                               NULL);
+
+    /* Create the Object */
+    Status = ObCreateObject(KernelMode,
+                            IoDriverObjectType,
+                            &ObjectAttributes,
+                            KernelMode,
+                            NULL,
+                            ObjectSize,
+                            0,
+                            0,
+                            (PVOID*)&DriverObject);
+
+    /* Return on failure */
+    if (!NT_SUCCESS(Status)) return Status;
+
+    /* Set up the Object */
+    RtlZeroMemory(DriverObject, ObjectSize);
+    DriverObject->Type = IO_TYPE_DRIVER;
+    DriverObject->Size = sizeof(DRIVER_OBJECT);
+    DriverObject->Flags = DRVO_BUILTIN_DRIVER;
+    DriverObject->DriverExtension = (PDRIVER_EXTENSION)(DriverObject + 1);
+    DriverObject->DriverExtension->DriverObject = DriverObject;
+    DriverObject->DriverInit = InitializationFunction;
+
+    /* Invalidate all Major Functions */
+    for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
+    {
+        DriverObject->MajorFunction[i] = IopInvalidDeviceRequest;
+    }
+
+    /* Set up the Service Key Name */
+    ServiceKeyName.Buffer = ExAllocatePool(PagedPool, LocalDriverName.Length + sizeof(WCHAR));
+    ServiceKeyName.Length = LocalDriverName.Length;
+    ServiceKeyName.MaximumLength = LocalDriverName.MaximumLength;
+    RtlMoveMemory(ServiceKeyName.Buffer, LocalDriverName.Buffer, LocalDriverName.Length);
+    ServiceKeyName.Buffer[ServiceKeyName.Length / sizeof(WCHAR)] = L'\0';
+    DriverObject->DriverExtension->ServiceKeyName =  ServiceKeyName;
+
+    /* Also store it in the Driver Object. This is a bit of a hack. */
+    RtlMoveMemory(&DriverObject->DriverName, &ServiceKeyName, sizeof(UNICODE_STRING));
+
+    /* Add the Object and get its handle */
+    Status = ObInsertObject(DriverObject,
+                            NULL,
+                            FILE_READ_DATA,
+                            0,
+                            NULL,
+                            &hDriver);
+
+    /* Return on Failure */
+    if (!NT_SUCCESS(Status)) return Status;
+
+    /* Now reference it */
+    Status = ObReferenceObjectByHandle(hDriver,
+                                       0,
+                                       IoDriverObjectType,
+                                       KernelMode,
+                                       (PVOID*)&DriverObject,
+                                       NULL);
+    ZwClose(hDriver);
+
+    /* Finally, call its init function */
+    Status = (*InitializationFunction)(DriverObject, NULL);
+
+    if (!NT_SUCCESS(Status)) {
+        /* If it didn't work, then kill the object */
+        ObMakeTemporaryObject(DriverObject);
+        ObDereferenceObject(DriverObject);
+    }
+
+    /* Return the Status */
+    return Status;
+}
+
+/*
+ * @implemented
+ */
+VOID
+STDCALL
+IoDeleteDriver (
+       IN PDRIVER_OBJECT DriverObject
+       )
+{
+       /* Simply derefence the Object */
+    ObDereferenceObject(DriverObject);
+}
+
 
 /*
  * NtLoadDriver
@@ -1011,123 +1834,193 @@ IopUnloadDriver(PUNICODE_STRING DriverServiceName, BOOLEAN UnloadPnpDrivers)
  * Parameters
  *    DriverServiceName
  *       Name of the service to load (registry key).
- *             
+ *
  * Return Value
  *    Status
+ *
+ * Status
+ *    implemented
  */
 
 NTSTATUS STDCALL
 NtLoadDriver(IN PUNICODE_STRING DriverServiceName)
 {
-   RTL_QUERY_REGISTRY_TABLE QueryTable[2];
+   RTL_QUERY_REGISTRY_TABLE QueryTable[3];
    UNICODE_STRING ImagePath;
+   UNICODE_STRING ServiceName;
+   UNICODE_STRING CapturedDriverServiceName;
+   KPROCESSOR_MODE PreviousMode;
    NTSTATUS Status;
    ULONG Type;
    PDEVICE_NODE DeviceNode;
    PMODULE_OBJECT ModuleObject;
-   LPWSTR Start;
+   PDRIVER_OBJECT DriverObject;
+   WCHAR *cur;
 
-   DPRINT("NtLoadDriver('%wZ')\n", DriverServiceName);
+   PAGED_CODE();
+
+   PreviousMode = KeGetPreviousMode();
 
    /*
     * Check security privileges
     */
+
+/* FIXME: Uncomment when privileges will be correctly implemented. */
 #if 0
-   if (!SeSinglePrivilegeCheck(SeLoadDriverPrivilege, KeGetPreviousMode()))
+   if (!SeSinglePrivilegeCheck(SeLoadDriverPrivilege, PreviousMode))
+   {
+      DPRINT("Privilege not held\n");
       return STATUS_PRIVILEGE_NOT_HELD;
+   }
 #endif
 
+   Status = RtlCaptureUnicodeString(&CapturedDriverServiceName,
+                                    PreviousMode,
+                                    PagedPool,
+                                    FALSE,
+                                    DriverServiceName);
+   if (!NT_SUCCESS(Status))
+   {
+      return Status;
+   }
+
+   DPRINT("NtLoadDriver('%wZ')\n", &CapturedDriverServiceName);
+
    RtlInitUnicodeString(&ImagePath, NULL);
 
    /*
-    * Get service type
+    * Get the service name from the registry key name.
+    */
+   ASSERT(CapturedDriverServiceName.Length >= sizeof(WCHAR));
+
+   ServiceName = CapturedDriverServiceName;
+   cur = CapturedDriverServiceName.Buffer + (CapturedDriverServiceName.Length / sizeof(WCHAR)) - 1;
+   while (CapturedDriverServiceName.Buffer != cur)
+   {
+      if(*cur == L'\\')
+      {
+         ServiceName.Buffer = cur + 1;
+         ServiceName.Length = CapturedDriverServiceName.Length -
+                              (USHORT)((ULONG_PTR)ServiceName.Buffer -
+                                       (ULONG_PTR)CapturedDriverServiceName.Buffer);
+         break;
+      }
+      cur--;
+   }
+
+   /*
+    * Get service type.
     */
+
    RtlZeroMemory(&QueryTable, sizeof(QueryTable));
+
+   RtlInitUnicodeString(&ImagePath, NULL);
+
    QueryTable[0].Name = L"Type";
    QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
    QueryTable[0].EntryContext = &Type;
+
+   QueryTable[1].Name = L"ImagePath";
+   QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
+   QueryTable[1].EntryContext = &ImagePath;
+
    Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
-      DriverServiceName->Buffer, QueryTable, NULL, NULL);
+      CapturedDriverServiceName.Buffer, QueryTable, NULL, NULL);
+
    if (!NT_SUCCESS(Status))
    {
       DPRINT("RtlQueryRegistryValues() failed (Status %lx)\n", Status);
-      RtlFreeUnicodeString(&ImagePath);
-      return Status;
+      ExFreePool(ImagePath.Buffer);
+      goto ReleaseCapturedString;
    }
 
    /*
-    * Get module path
+    * Normalize the image path for all later processing.
     */
-   Status = IopGetDriverNameFromServiceKey(RTL_REGISTRY_ABSOLUTE,
-      DriverServiceName->Buffer, &ImagePath);
+
+   Status = IopNormalizeImagePath(&ImagePath, &ServiceName);
+
    if (!NT_SUCCESS(Status))
    {
-      DPRINT("IopGetDriverNameFromKeyNode() failed (Status %x)\n", Status);
-      return Status;
+      DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status);
+      goto ReleaseCapturedString;
    }
 
-   DPRINT("FullImagePath: '%S'\n", ImagePath.Buffer);
+   DPRINT("FullImagePath: '%wZ'\n", &ImagePath);
    DPRINT("Type: %lx\n", Type);
 
    /*
     * See, if the driver module isn't already loaded
     */
+
    ModuleObject = LdrGetModuleObject(&ImagePath);
    if (ModuleObject != NULL)
    {
-      return STATUS_IMAGE_ALREADY_LOADED;
+      DPRINT("Image already loaded\n");
+      Status = STATUS_IMAGE_ALREADY_LOADED;
+      goto ReleaseCapturedString;
    }
 
    /*
     * Create device node
     */
+
    /* Use IopRootDeviceNode for now */
    Status = IopCreateDeviceNode(IopRootDeviceNode, NULL, &DeviceNode);
+
    if (!NT_SUCCESS(Status))
    {
       DPRINT("IopCreateDeviceNode() failed (Status %lx)\n", Status);
-      return Status;
+      goto ReleaseCapturedString;
    }
 
    /*
     * Load the driver module
     */
+
    Status = LdrLoadModule(&ImagePath, &ModuleObject);
+
    if (!NT_SUCCESS(Status))
    {
       DPRINT("LdrLoadModule() failed (Status %lx)\n", Status);
       IopFreeDeviceNode(DeviceNode);
-      return Status;
+      goto ReleaseCapturedString;
    }
 
    /*
     * Set a service name for the device node
     */
-   Start = wcsrchr(DriverServiceName->Buffer, L'\\');
-   if (Start == NULL)
-      Start = DriverServiceName->Buffer;
-   else
-      Start++;
-   RtlCreateUnicodeString(&DeviceNode->ServiceName, Start);
+
+   RtlpCreateUnicodeString(&DeviceNode->ServiceName, ServiceName.Buffer, NonPagedPool);
 
    /*
     * Initialize the driver module
     */
-   Status = IopInitializeDriver(
-      ModuleObject->EntryPoint,
+
+   Status = IopInitializeDriverModule(
       DeviceNode,
-      (Type == 2 /*SERVICE_FILE_SYSTEM_DRIVER*/ ||
-       Type == 8 /*SERVICE_RECOGNIZER_DRIVER*/),
-      ModuleObject->Base,
-      ModuleObject->Length,
-      FALSE);
+      ModuleObject,
+      &DeviceNode->ServiceName,
+      (Type == 2 /* SERVICE_FILE_SYSTEM_DRIVER */ ||
+       Type == 8 /* SERVICE_RECOGNIZER_DRIVER */),
+      &DriverObject);
+
    if (!NT_SUCCESS(Status))
    {
-      DPRINT1("IopInitializeDriver() failed (Status %lx)\n", Status);
+      DPRINT("IopInitializeDriver() failed (Status %lx)\n", Status);
       LdrUnloadModule(ModuleObject);
       IopFreeDeviceNode(DeviceNode);
+      goto ReleaseCapturedString;
    }
 
+   IopInitializeDevice(DeviceNode, DriverObject);
+   Status = IopStartDevice(DeviceNode);
+
+ReleaseCapturedString:
+   RtlReleaseCapturedUnicodeString(&CapturedDriverServiceName,
+                                   PreviousMode,
+                                   FALSE);
+
    return Status;
 }
 
@@ -1139,9 +2032,12 @@ NtLoadDriver(IN PUNICODE_STRING DriverServiceName)
  * Parameters
  *    DriverServiceName
  *       Name of the service to unload (registry key).
- *             
+ *
  * Return Value
  *    Status
+ *
+ * Status
+ *    implemented
  */
 
 NTSTATUS STDCALL
@@ -1150,102 +2046,72 @@ NtUnloadDriver(IN PUNICODE_STRING DriverServiceName)
    return IopUnloadDriver(DriverServiceName, FALSE);
 }
 
-
 /*
- * @implemented
+ * IoRegisterDriverReinitialization
+ *
+ * Status
+ *    @implemented
  */
+
 VOID STDCALL
-IoRegisterDriverReinitialization(PDRIVER_OBJECT DriverObject,
-                                PDRIVER_REINITIALIZE ReinitRoutine,
-                                PVOID Context)
+IoRegisterDriverReinitialization(
+   PDRIVER_OBJECT DriverObject,
+   PDRIVER_REINITIALIZE ReinitRoutine,
+   PVOID Context)
 {
-  PDRIVER_REINIT_ITEM ReinitItem;
-
-  ReinitItem = ExAllocatePool(NonPagedPool,
-                             sizeof(DRIVER_REINIT_ITEM));
-  if (ReinitItem == NULL)
-    return;
-
-  ReinitItem->DriverObject = DriverObject;
-  ReinitItem->ReinitRoutine = ReinitRoutine;
-  ReinitItem->Context = Context;
-
-  ExInterlockedInsertTailList(&DriverReinitListHead,
-                             &ReinitItem->ItemEntry,
-                             &DriverReinitListLock);
-}
+   PDRIVER_REINIT_ITEM ReinitItem;
 
+   ReinitItem = ExAllocatePool(NonPagedPool, sizeof(DRIVER_REINIT_ITEM));
+   if (ReinitItem == NULL)
+      return;
 
-VOID
-IopMarkLastReinitializeDriver(VOID)
-{
-  KIRQL Irql;
-
-  KeAcquireSpinLock(&DriverReinitListLock,
-                   &Irql);
+   ReinitItem->DriverObject = DriverObject;
+   ReinitItem->ReinitRoutine = ReinitRoutine;
+   ReinitItem->Context = Context;
 
-  if (IsListEmpty(&DriverReinitListHead))
-  {
-    DriverReinitTailEntry = NULL;
-  }
-  else
-  {
-    DriverReinitTailEntry = DriverReinitListHead.Blink;
-  }
+   DriverObject->Flags |= DRVO_REINIT_REGISTERED;
 
-  KeReleaseSpinLock(&DriverReinitListLock,
-                   Irql);
+   ExInterlockedInsertTailList(
+      &DriverReinitListHead,
+      &ReinitItem->ItemEntry,
+      &DriverReinitListLock);
 }
 
-
+/*
+ * @implemented
+ */
 VOID
-IopReinitializeDrivers(VOID)
+STDCALL
+IoRegisterBootDriverReinitialization(
+    IN PDRIVER_OBJECT DriverObject,
+    IN PDRIVER_REINITIALIZE DriverReinitializationRoutine,
+    IN PVOID Context
+    )
 {
-  PDRIVER_REINIT_ITEM ReinitItem;
-  PLIST_ENTRY Entry;
-  KIRQL Irql;
-
-  KeAcquireSpinLock(&DriverReinitListLock,
-                   &Irql);
-
-  if (DriverReinitTailEntry == NULL)
-  {
-    KeReleaseSpinLock(&DriverReinitListLock,
-                     Irql);
-    return;
-  }
+   PDRIVER_REINIT_ITEM ReinitItem;
 
-  KeReleaseSpinLock(&DriverReinitListLock,
-                   Irql);
-
-  for (;;)
-  {
-    Entry = ExInterlockedRemoveHeadList(&DriverReinitListHead,
-                                       &DriverReinitListLock);
-    if (Entry == NULL)
+   ReinitItem = ExAllocatePool(NonPagedPool, sizeof(DRIVER_REINIT_ITEM));
+   if (ReinitItem == NULL)
       return;
 
-    ReinitItem = (PDRIVER_REINIT_ITEM)CONTAINING_RECORD(Entry, DRIVER_REINIT_ITEM, ItemEntry);
-
-    /* Increment reinitialization counter */
-    ReinitItem->DriverObject->DriverExtension->Count++;
-
-    ReinitItem->ReinitRoutine(ReinitItem->DriverObject,
-                             ReinitItem->Context,
-                             ReinitItem->DriverObject->DriverExtension->Count);
+   ReinitItem->DriverObject = DriverObject;
+   ReinitItem->ReinitRoutine = DriverReinitializationRoutine;
+   ReinitItem->Context = Context;
 
-    ExFreePool(Entry);
+   DriverObject->Flags |= DRVO_BOOTREINIT_REGISTERED;
 
-    if (Entry == DriverReinitTailEntry)
-      return;
-  }
+   ExInterlockedInsertTailList(
+      &DriverBootReinitListHead,
+      &ReinitItem->ItemEntry,
+      &DriverReinitListLock);
 }
 
-typedef struct _PRIVATE_DRIVER_EXTENSIONS {
-   struct _PRIVATE_DRIVER_EXTENSIONS *Link;
-   PVOID ClientIdentificationAddress;
-   CHAR Extension[1];
-} PRIVATE_DRIVER_EXTENSIONS, *PPRIVATE_DRIVER_EXTENSIONS;
+/*
+ * IoAllocateDriverObjectExtension
+ *
+ * Status
+ *    @implemented
+ */
 
 NTSTATUS STDCALL
 IoAllocateDriverObjectExtension(
@@ -1266,9 +2132,9 @@ IoAllocateDriverObjectExtension(
 
    if (NewDriverExtension == NULL)
    {
-      return STATUS_INSUFFICIENT_RESOURCES;             
+      return STATUS_INSUFFICIENT_RESOURCES;
    }
-   
+
    OldIrql = KeRaiseIrqlToDpcLevel();
 
    NewDriverExtension->Link = DriverObject->DriverSection;
@@ -1280,7 +2146,10 @@ IoAllocateDriverObjectExtension(
    {
       if (DriverExtensions->ClientIdentificationAddress ==
           ClientIdentificationAddress)
+      {
+         KfLowerIrql(OldIrql);
          return STATUS_OBJECT_NAME_COLLISION;
+      }
    }
 
    DriverObject->DriverSection = NewDriverExtension;
@@ -1289,9 +2158,16 @@ IoAllocateDriverObjectExtension(
 
    *DriverObjectExtension = &NewDriverExtension->Extension;
 
-   return STATUS_SUCCESS;      
+   return STATUS_SUCCESS;
 }
 
+/*
+ * IoGetDriverObjectExtension
+ *
+ * Status
+ *    @implemented
+ */
+
 PVOID STDCALL
 IoGetDriverObjectExtension(
    PDRIVER_OBJECT DriverObject,