started moving tags to a private internal header
[reactos.git] / reactos / ntoskrnl / io / driver.c
index c28b3c5..a95a142 100644 (file)
@@ -1,13 +1,12 @@
-/* $Id: driver.c,v 1.56 2004/12/09 14:20:06 royce 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 *******************************************************************/
@@ -18,6 +17,8 @@
 
 /* ke/main.c */
 extern LOADER_PARAMETER_BLOCK EXPORTED KeLoaderBlock;
+extern ULONG KeTickCount;
+extern BOOLEAN SetupMode;
 
 NTSTATUS
 LdrProcessModule(PVOID ModuleLoadBase,
@@ -60,8 +61,12 @@ 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};
@@ -71,52 +76,40 @@ static UNICODE_STRING IopHardwareDatabaseKey =
 
 POBJECT_TYPE EXPORTED IoDriverObjectType = NULL;
 
-#define TAG_DRIVER             TAG('D', 'R', 'V', 'R')
-#define TAG_DRIVER_EXTENSION   TAG('D', 'R', 'V', 'E')
-
 /* DECLARATIONS ***************************************************************/
 
-NTSTATUS STDCALL
-IopCreateDriver(
-   PVOID ObjectBody,
-   PVOID Parent,
-   PWSTR RemainingPath,
-   POBJECT_ATTRIBUTES ObjectAttributes);
-
 VOID STDCALL
 IopDeleteDriver(PVOID ObjectBody);
 
 /* PRIVATE FUNCTIONS **********************************************************/
 
-VOID INIT_FUNCTION
+VOID 
+INIT_FUNCTION
 IopInitDriverImplementation(VOID)
 {
-   /* 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 = IopDeleteDriver;
-   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);
+   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
@@ -130,46 +123,6 @@ IopInvalidDeviceRequest(
    return STATUS_INVALID_DEVICE_REQUEST;
 }
 
-NTSTATUS STDCALL
-IopCreateDriver(
-   PVOID ObjectBody,
-   PVOID Parent,
-   PWSTR RemainingPath,
-   POBJECT_ATTRIBUTES ObjectAttributes)
-{
-   PDRIVER_OBJECT Object = ObjectBody;
-   ULONG i;
-
-   DPRINT("IopCreateDriver(ObjectBody %x, Parent %x, RemainingPath %S)\n",
-      ObjectBody, Parent, RemainingPath);
-
-   if (RemainingPath != NULL && wcschr(RemainingPath + 1, '\\') != NULL)
-      return STATUS_UNSUCCESSFUL;
-
-   /* 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 = InternalDriverType;
-
-   for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
-      Object->MajorFunction[i] = IopInvalidDeviceRequest;
-
-   Object->HardwareDatabase = &IopHardwareDatabaseKey;
-
-   return STATUS_SUCCESS;
-}
-
 VOID STDCALL
 IopDeleteDriver(PVOID ObjectBody)
 {
@@ -180,6 +133,7 @@ IopDeleteDriver(PVOID ObjectBody)
    DPRINT("IopDeleteDriver(ObjectBody %x)\n", ObjectBody);
 
    ExFreePool(Object->DriverExtension);
+   ExFreePool(Object->DriverName.Buffer);
 
    OldIrql = KeRaiseIrqlToDpcLevel();
 
@@ -188,16 +142,75 @@ IopDeleteDriver(PVOID ObjectBody)
         DriverExtension = NextDriverExtension)
    {
       NextDriverExtension = DriverExtension->Link;
-      ExFreePool(DriverExtension);
+      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)
@@ -207,6 +220,8 @@ IopCreateDriverObject(
    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);
@@ -224,6 +239,10 @@ IopCreateDriverObject(
 
       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
    {
@@ -234,7 +253,7 @@ IopCreateDriverObject(
    InitializeObjectAttributes(
       &ObjectAttributes,
       &DriverName,
-      OBJ_PERMANENT,
+      CreateAttributes | OBJ_PERMANENT,
       NULL,
       NULL);
 
@@ -255,8 +274,51 @@ IopCreateDriverObject(
       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;
 
@@ -269,12 +331,23 @@ IopCreateDriverObject(
  * Display 'Loading XXX...' message.
  */
 
-VOID FASTCALL
-IopDisplayLoadingMessage(PWCHAR ServiceName)
+VOID 
+FASTCALL
+INIT_FUNCTION
+IopDisplayLoadingMessage(PVOID ServiceName, 
+                         BOOLEAN Unicode)
 {
-   CHAR TextBuffer[256];
-   sprintf(TextBuffer, "Loading %S...\n", ServiceName);
-   HalDisplayString(TextBuffer);
+    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);
 }
 
 /*
@@ -332,7 +405,7 @@ IopNormalizeImagePath(
 
       wcscpy(ImagePath->Buffer, L"\\SystemRoot\\");
       wcscat(ImagePath->Buffer, InputImagePath.Buffer);
-      RtlFreeUnicodeString(&InputImagePath);
+      ExFreePool(InputImagePath.Buffer);
    }
 
    return STATUS_SUCCESS;
@@ -387,8 +460,8 @@ IopLoadServiceModule(
       DPRINT("RtlQueryRegistryValues() failed (Status %x)\n", Status);
       return Status;
    }
-
-   IopDisplayLoadingMessage(ServiceName->Buffer);
+   
+   IopDisplayLoadingMessage(ServiceName->Buffer, TRUE);
 
    /*
     * Normalize the image path for all later processing.
@@ -447,6 +520,8 @@ IopLoadServiceModule(
                   &ServiceImagePath,
                   ModuleObject);
 
+              KDB_SYMBOLFILE_HOOK(SearchName);
+
                break;
             }
          }
@@ -465,10 +540,10 @@ IopLoadServiceModule(
    else
    {
       DPRINT("Module already loaded\n");
-      Status = STATUS_SUCCESS;
+      Status = STATUS_IMAGE_ALREADY_LOADED;
    }
 
-   RtlFreeUnicodeString(&ServiceImagePath);
+   ExFreePool(ServiceImagePath.Buffer);
 
    /*
     * Now check if the module was loaded successfully.
@@ -497,6 +572,9 @@ IopLoadServiceModule(
  *       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.
  *
@@ -509,17 +587,38 @@ 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 = ModuleObject->EntryPoint;
+   PDRIVER_INITIALIZE DriverEntry;
    NTSTATUS Status;
-   WCHAR ServicesKeyName[] = L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\";
+
+   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,
-      &DeviceNode->ServiceName,
+      ServiceName,
+      0,
       FileSystemDriver,
       ModuleObject->Base,
       ModuleObject->Length);
@@ -530,26 +629,15 @@ IopInitializeDriverModule(
       return Status;
    }
 
-   if (DeviceNode->ServiceName.Buffer)
-   {
-      RegistryKey.Length = DeviceNode->ServiceName.Length +
-         sizeof(ServicesKeyName);
-      RegistryKey.MaximumLength = RegistryKey.Length + sizeof(UNICODE_NULL);
-      RegistryKey.Buffer = ExAllocatePool(PagedPool, RegistryKey.MaximumLength);
-      wcscpy(RegistryKey.Buffer, ServicesKeyName);
-      wcscat(RegistryKey.Buffer, DeviceNode->ServiceName.Buffer);
-   }
-   else
-   {
-      RtlInitUnicodeString(&RegistryKey, NULL);
-   }
-
    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);
@@ -583,7 +671,7 @@ IopAttachFilterDriversCallback(
    PMODULE_OBJECT ModuleObject;
    PDRIVER_OBJECT DriverObject;
    NTSTATUS Status;
-   
+
    for (Filters = ValueData;
         ((ULONG_PTR)Filters - (ULONG_PTR)ValueData) < ValueLength &&
         *Filters != 0;
@@ -591,17 +679,31 @@ IopAttachFilterDriversCallback(
    {
       DPRINT("Filter Driver: %S (%wZ)\n", Filters, &DeviceNode->InstancePath);
       ServiceName.Buffer = Filters;
-      ServiceName.MaximumLength = 
+      ServiceName.MaximumLength =
       ServiceName.Length = wcslen(Filters) * sizeof(WCHAR);
 
       /* Load and initialize the filter driver */
       Status = IopLoadServiceModule(&ServiceName, &ModuleObject);
-      if (!NT_SUCCESS(Status))
-         continue;
+      if (Status != STATUS_IMAGE_ALREADY_LOADED)
+      {
+         if (!NT_SUCCESS(Status))
+            continue;
 
-      Status = IopInitializeDriverModule(DeviceNode, ModuleObject, FALSE, &DriverObject);
-      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))
@@ -636,7 +738,7 @@ IopAttachFilterDrivers(
    /*
     * First load the device filters
     */
-   
+
    QueryTable[0].QueryRoutine = IopAttachFilterDriversCallback;
    if (Lower)
      QueryTable[0].Name = L"LowerFilters";
@@ -648,10 +750,10 @@ IopAttachFilterDrivers(
    QueryTable[1].Name = NULL;
 
    KeyBuffer = ExAllocatePool(
-      PagedPool, 
+      PagedPool,
       (49 * sizeof(WCHAR)) + DeviceNode->InstancePath.Length);
    wcscpy(KeyBuffer, L"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
-   wcscat(KeyBuffer, DeviceNode->InstancePath.Buffer);  
+   wcscat(KeyBuffer, DeviceNode->InstancePath.Buffer);
 
    RtlQueryRegistryValues(
       RTL_REGISTRY_ABSOLUTE,
@@ -708,11 +810,11 @@ IopAttachFilterDrivers(
 
       ExFreePool(KeyBuffer);
    }
-   
+
    return STATUS_SUCCESS;
 }
 
-static NTSTATUS STDCALL 
+static NTSTATUS STDCALL
 IopGetGroupOrderList(PWSTR ValueName,
                     ULONG ValueType,
                     PVOID ValueData,
@@ -780,8 +882,7 @@ 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);
@@ -859,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);
     }
@@ -946,8 +1059,8 @@ IoCreateDriverList(VOID)
                             NULL,
                             NULL);
 
-  Status = NtOpenKey(&KeyHandle,
-                    0x10001,
+  Status = ZwOpenKey(&KeyHandle,
+                    KEY_ENUMERATE_SUB_KEYS,
                     &ObjectAttributes);
   if (!NT_SUCCESS(Status))
     {
@@ -958,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,
@@ -993,7 +1106,7 @@ IoCreateDriverList(VOID)
     }
 
   ExFreePool(KeyInfo);
-  NtClose(KeyHandle);
+  ZwClose(KeyHandle);
 
   DPRINT("IoCreateDriverList() done\n");
 
@@ -1016,7 +1129,7 @@ IoDestroyDriverList(VOID)
     {
       CurrentGroup = CONTAINING_RECORD(GroupEntry, SERVICE_GROUP, GroupListEntry);
 
-      RtlFreeUnicodeString(&CurrentGroup->GroupName);
+      ExFreePool(CurrentGroup->GroupName.Buffer);
       RemoveEntryList(GroupEntry);
       if (CurrentGroup->TagArray)
         {
@@ -1033,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);
 
@@ -1076,7 +1189,6 @@ IopInitializeBuiltinDriver(
    PDEVICE_NODE DeviceNode;
    PDRIVER_OBJECT DriverObject;
    NTSTATUS Status;
-   CHAR TextBuffer[256];
    PCHAR FileNameWithoutPath;
    LPWSTR FileExtension;
 
@@ -1084,11 +1196,9 @@ 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
@@ -1126,14 +1236,17 @@ IopInitializeBuiltinDriver(
       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
     */
@@ -1149,9 +1262,9 @@ IopInitializeBuiltinDriver(
     * Initialize the driver
     */
 
-   Status = IopInitializeDriverModule(DeviceNode, ModuleObject, FALSE,
-      &DriverObject);
-   
+   Status = IopInitializeDriverModule(DeviceNode, ModuleObject,
+      &DeviceNode->ServiceName, FALSE, &DriverObject);
+
    if (!NT_SUCCESS(Status))
    {
       if (ModuleDeviceNode == NULL)
@@ -1161,6 +1274,10 @@ IopInitializeBuiltinDriver(
    }
 
    Status = IopInitializeDevice(DeviceNode, DriverObject);
+   if (NT_SUCCESS(Status))
+   {
+      Status = IopStartDevice(DeviceNode);
+   }
 
    return Status;
 }
@@ -1172,7 +1289,7 @@ IopInitializeBuiltinDriver(
  *
  * Parameters
  *    None
- *             
+ *
  * Return Value
  *    None
  */
@@ -1204,13 +1321,11 @@ IopInitializeBootDrivers(VOID)
       if (Extension == NULL)
          Extension = "";
 
-      if (!_stricmp(Extension, ".sym"))
-      {
-         /* Pass symbol files to kernel debugger */
-         KDB_SYMBOLFILE_HOOK((PVOID)ModuleStart, ModuleName, ModuleSize);
-      }
-      else if (!_stricmp(Extension, ".exe") || !_stricmp(Extension, ".dll"))
+      if (!_stricmp(Extension, ".sym") || !_stricmp(Extension, ".dll"))
       {
+        /* Process symbols for *.exe and *.dll */
+        KDB_SYMBOLFILE_HOOK(ModuleName);
+
         /* Log *.exe and *.dll files */
         RtlCreateUnicodeStringFromAsciiz(&DriverName, ModuleName);
         IopBootLog(&DriverName, TRUE);
@@ -1231,22 +1346,19 @@ IopInitializeBootDrivers(VOID)
          }
          BootDriverCount++;
       }
+   }
 
-      /*
-       * Free memory for all boot files, except ntoskrnl.exe, hal.dll
-       * and symbol files, if the kernel debugger is active
-       */
-      if (_stricmp(Extension, ".exe") && _stricmp(Extension, ".dll")
-#if defined(DBG) || defined(KDBG)
-          && _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");
@@ -1259,30 +1371,30 @@ IopLoadDriver(PSERVICE Service)
 {
    NTSTATUS Status = STATUS_UNSUCCESSFUL;
 
-   IopDisplayLoadingMessage(Service->ServiceName.Buffer);
-   Status = NtLoadDriver(&Service->RegistryPath);
+   IopDisplayLoadingMessage(Service->ServiceName.Buffer, TRUE);
+   Status = ZwLoadDriver(&Service->RegistryPath);
    IopBootLog(&Service->ImagePath, NT_SUCCESS(Status) ? TRUE : FALSE);
    if (!NT_SUCCESS(Status))
    {
-      DPRINT("NtLoadDriver() failed (Status %lx)\n", 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! */
@@ -1301,7 +1413,7 @@ IopLoadDriver(PSERVICE Service)
  *
  * Parameters
  *    None
- *             
+ *
  * Return Value
  *    None
  */
@@ -1325,7 +1437,7 @@ IopInitializeSystemDrivers(VOID)
 
       DPRINT("Group: %wZ\n", &CurrentGroup->GroupName);
 
-      /* Load all drivers with a valid tag */ 
+      /* Load all drivers with a valid tag */
       for (i = 0; i < CurrentGroup->TagCount; i++)
       {
          ServiceEntry = ServiceListHead.Flink;
@@ -1389,7 +1501,7 @@ IopInitializeSystemDrivers(VOID)
  *       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
  *
@@ -1500,7 +1612,7 @@ 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
@@ -1584,7 +1696,7 @@ IopReinitializeDrivers(VOID)
 
 
 /*
- * @unimplemented
+ * @implemented
  */
 NTSTATUS
 STDCALL
@@ -1593,12 +1705,115 @@ IoCreateDriver (
        IN PDRIVER_INITIALIZE InitializationFunction
        )
 {
-       UNIMPLEMENTED;
-       return STATUS_NOT_IMPLEMENTED;
+    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;
 }
 
 /*
- * @unimplemented
+ * @implemented
  */
 VOID
 STDCALL
@@ -1606,7 +1821,8 @@ IoDeleteDriver (
        IN PDRIVER_OBJECT DriverObject
        )
 {
-       UNIMPLEMENTED;
+       /* Simply derefence the Object */
+    ObDereferenceObject(DriverObject);
 }
 
 
@@ -1618,7 +1834,7 @@ IoDeleteDriver (
  * Parameters
  *    DriverServiceName
  *       Name of the service to load (registry key).
- *             
+ *
  * Return Value
  *    Status
  *
@@ -1632,14 +1848,18 @@ NtLoadDriver(IN PUNICODE_STRING DriverServiceName)
    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;
    PDRIVER_OBJECT DriverObject;
-   LPWSTR Start;
+   WCHAR *cur;
+
+   PAGED_CODE();
 
-   DPRINT("NtLoadDriver('%wZ')\n", DriverServiceName);
+   PreviousMode = KeGetPreviousMode();
 
    /*
     * Check security privileges
@@ -1647,26 +1867,46 @@ NtLoadDriver(IN PUNICODE_STRING DriverServiceName)
 
 /* 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 the service name from the registry key name.
     */
+   ASSERT(CapturedDriverServiceName.Length >= sizeof(WCHAR));
 
-   Start = wcsrchr(DriverServiceName->Buffer, L'\\');
-   if (Start == NULL)
-      Start = DriverServiceName->Buffer;
-   else
-      Start++;
-
-   RtlInitUnicodeString(&ServiceName, Start);
+   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.
@@ -1685,13 +1925,13 @@ NtLoadDriver(IN PUNICODE_STRING DriverServiceName)
    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;
    }
 
    /*
@@ -1703,10 +1943,10 @@ NtLoadDriver(IN PUNICODE_STRING DriverServiceName)
    if (!NT_SUCCESS(Status))
    {
       DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status);
-      return Status;
+      goto ReleaseCapturedString;
    }
 
-   DPRINT("FullImagePath: '%S'\n", ImagePath.Buffer);
+   DPRINT("FullImagePath: '%wZ'\n", &ImagePath);
    DPRINT("Type: %lx\n", Type);
 
    /*
@@ -1717,7 +1957,8 @@ NtLoadDriver(IN PUNICODE_STRING DriverServiceName)
    if (ModuleObject != NULL)
    {
       DPRINT("Image already loaded\n");
-      return STATUS_IMAGE_ALREADY_LOADED;
+      Status = STATUS_IMAGE_ALREADY_LOADED;
+      goto ReleaseCapturedString;
    }
 
    /*
@@ -1730,7 +1971,7 @@ NtLoadDriver(IN PUNICODE_STRING DriverServiceName)
    if (!NT_SUCCESS(Status))
    {
       DPRINT("IopCreateDeviceNode() failed (Status %lx)\n", Status);
-      return Status;
+      goto ReleaseCapturedString;
    }
 
    /*
@@ -1743,19 +1984,14 @@ NtLoadDriver(IN PUNICODE_STRING DriverServiceName)
    {
       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
@@ -1764,6 +2000,7 @@ NtLoadDriver(IN PUNICODE_STRING DriverServiceName)
    Status = IopInitializeDriverModule(
       DeviceNode,
       ModuleObject,
+      &DeviceNode->ServiceName,
       (Type == 2 /* SERVICE_FILE_SYSTEM_DRIVER */ ||
        Type == 8 /* SERVICE_RECOGNIZER_DRIVER */),
       &DriverObject);
@@ -1773,10 +2010,16 @@ NtLoadDriver(IN PUNICODE_STRING DriverServiceName)
       DPRINT("IopInitializeDriver() failed (Status %lx)\n", Status);
       LdrUnloadModule(ModuleObject);
       IopFreeDeviceNode(DeviceNode);
-      return Status;
+      goto ReleaseCapturedString;
    }
 
    IopInitializeDevice(DeviceNode, DriverObject);
+   Status = IopStartDevice(DeviceNode);
+
+ReleaseCapturedString:
+   RtlReleaseCapturedUnicodeString(&CapturedDriverServiceName,
+                                   PreviousMode,
+                                   FALSE);
 
    return Status;
 }
@@ -1789,7 +2032,7 @@ NtLoadDriver(IN PUNICODE_STRING DriverServiceName)
  * Parameters
  *    DriverServiceName
  *       Name of the service to unload (registry key).
- *             
+ *
  * Return Value
  *    Status
  *
@@ -1826,12 +2069,43 @@ IoRegisterDriverReinitialization(
    ReinitItem->ReinitRoutine = ReinitRoutine;
    ReinitItem->Context = Context;
 
+   DriverObject->Flags |= DRVO_REINIT_REGISTERED;
+
    ExInterlockedInsertTailList(
       &DriverReinitListHead,
       &ReinitItem->ItemEntry,
       &DriverReinitListLock);
 }
 
+/*
+ * @implemented
+ */
+VOID
+STDCALL
+IoRegisterBootDriverReinitialization(
+    IN PDRIVER_OBJECT DriverObject,
+    IN PDRIVER_REINITIALIZE DriverReinitializationRoutine,
+    IN PVOID Context
+    )
+{
+   PDRIVER_REINIT_ITEM ReinitItem;
+
+   ReinitItem = ExAllocatePool(NonPagedPool, sizeof(DRIVER_REINIT_ITEM));
+   if (ReinitItem == NULL)
+      return;
+
+   ReinitItem->DriverObject = DriverObject;
+   ReinitItem->ReinitRoutine = DriverReinitializationRoutine;
+   ReinitItem->Context = Context;
+
+   DriverObject->Flags |= DRVO_BOOTREINIT_REGISTERED;
+
+   ExInterlockedInsertTailList(
+      &DriverBootReinitListHead,
+      &ReinitItem->ItemEntry,
+      &DriverReinitListLock);
+}
+
 /*
  * IoAllocateDriverObjectExtension
  *
@@ -1858,9 +2132,9 @@ IoAllocateDriverObjectExtension(
 
    if (NewDriverExtension == NULL)
    {
-      return STATUS_INSUFFICIENT_RESOURCES;             
+      return STATUS_INSUFFICIENT_RESOURCES;
    }
-   
+
    OldIrql = KeRaiseIrqlToDpcLevel();
 
    NewDriverExtension->Link = DriverObject->DriverSection;
@@ -1884,7 +2158,7 @@ IoAllocateDriverObjectExtension(
 
    *DriverObjectExtension = &NewDriverExtension->Extension;
 
-   return STATUS_SUCCESS;      
+   return STATUS_SUCCESS;
 }
 
 /*