[NTOSKRNL]
[reactos.git] / ntoskrnl / io / iomgr / driver.c
index 4dc022f..f33a22f 100644 (file)
@@ -34,6 +34,9 @@ POBJECT_TYPE IoDriverObjectType = NULL;
 extern BOOLEAN ExpInTextModeSetup;
 extern BOOLEAN PnpSystemInit;
 
+USHORT IopGroupIndex;
+PLIST_ENTRY IopGroupTable;
+
 /* PRIVATE FUNCTIONS **********************************************************/
 
 NTSTATUS NTAPI
@@ -149,44 +152,62 @@ IopGetDriverObject(
    return STATUS_SUCCESS;
 }
 
+/*
+ * RETURNS
+ *  TRUE if String2 contains String1 as a suffix.
+ */
+BOOLEAN
+NTAPI
+IopSuffixUnicodeString(
+    IN PCUNICODE_STRING String1,
+    IN PCUNICODE_STRING String2)
+{
+    PWCHAR pc1;
+    PWCHAR pc2;
+    ULONG Length;
+
+    if (String2->Length < String1->Length)
+        return FALSE;
+
+    Length = String1->Length / 2;
+    pc1 = String1->Buffer;
+    pc2 = &String2->Buffer[String2->Length / sizeof(WCHAR) - Length];
+
+    if (pc1 && pc2)
+    {
+        while (Length--)
+        {
+            if( *pc1++ != *pc2++ )
+                return FALSE;
+        }
+        return TRUE;
+    }
+    return FALSE;
+}
+
 /*
  * IopDisplayLoadingMessage
  *
  * Display 'Loading XXX...' message.
  */
 
-VOID 
+VOID
 FASTCALL
 INIT_FUNCTION
-IopDisplayLoadingMessage(PVOID ServiceName, 
-                         BOOLEAN Unicode)
+IopDisplayLoadingMessage(PUNICODE_STRING ServiceName)
 {
     CHAR TextBuffer[256];
-    PCHAR Extra = ".sys";
+    UNICODE_STRING DotSys = RTL_CONSTANT_STRING(L".SYS");
 
     if (ExpInTextModeSetup) return;
-    if (Unicode)
-    {
-        if (wcsstr(_wcsupr(ServiceName), L".SYS")) Extra = "";
-        sprintf(TextBuffer,
-                "%s%s%s\\%S%s\n",
-                KeLoaderBlock->ArcBootDeviceName,
-                KeLoaderBlock->NtBootPathName,
-                "System32\\Drivers",
-                (PWCHAR)ServiceName,
-                Extra);
-    }
-    else
-    {
-        if (strstr(_strupr(ServiceName), ".SYS")) Extra = "";
-        sprintf(TextBuffer,
-                "%s%s%s\\%s%s\n",
-                KeLoaderBlock->ArcBootDeviceName,
-                KeLoaderBlock->NtBootPathName,
-                "System32\\Drivers",
-                (PCHAR)ServiceName,
-                Extra);
-    }
+    if (!KeLoaderBlock) return;
+    RtlUpcaseUnicodeString(ServiceName, ServiceName, FALSE);
+    snprintf(TextBuffer, sizeof(TextBuffer),
+            "%s%sSystem32\\Drivers\\%wZ%s\n",
+            KeLoaderBlock->ArcBootDeviceName,
+            KeLoaderBlock->NtBootPathName,
+            ServiceName,
+            IopSuffixUnicodeString(&DotSys, ServiceName) ? "" : ".SYS");
     HalDisplayString(TextBuffer);
 }
 
@@ -218,6 +239,8 @@ IopNormalizeImagePath(
 {
    UNICODE_STRING InputImagePath;
 
+   DPRINT("Normalizing image path '%wZ' for service '%wZ'\n", ImagePath, ServiceName);
+
    RtlCopyMemory(
       &InputImagePath,
       ImagePath,
@@ -251,6 +274,8 @@ IopNormalizeImagePath(
       /* Free caller's string */
       ExFreePoolWithTag(InputImagePath.Buffer, TAG_RTLREGISTRY);
    }
+   DPRINT("Normalized image path is '%wZ' for service '%wZ'\n", ImagePath, ServiceName);
 
    return STATUS_SUCCESS;
 }
@@ -289,51 +314,65 @@ IopLoadServiceModule(
       return STATUS_UNSUCCESSFUL;
    }
 
-   /* Open CurrentControlSet */
-   RtlInitUnicodeString(&CCSName,
-                        L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Services");
-   Status = IopOpenRegistryKeyEx(&CCSKey, NULL, &CCSName, KEY_READ);
-   if (!NT_SUCCESS(Status))
+   if (ExpInTextModeSetup)
    {
-       DPRINT1("ZwOpenKey() failed with Status %08X\n", Status);
-       return Status;
-   }
+       /* We have no registry, but luckily we know where all the drivers are */
 
-   /* Open service key */
-   Status = IopOpenRegistryKeyEx(&ServiceKey, CCSKey, ServiceName, KEY_READ);
-   if (!NT_SUCCESS(Status))
-   {
-       DPRINT1("ZwOpenKey() failed with Status %08X\n", Status);
-       ZwClose(CCSKey);
-       return Status;
+       /* ServiceStart < 4 is all that matters */
+       ServiceStart = 0;
+
+       /* IopNormalizeImagePath will do all of the work for us if we give it an empty string */
+       ServiceImagePath.Length = ServiceImagePath.MaximumLength = 0;
+       ServiceImagePath.Buffer = NULL;
    }
+   else
+   {
+       /* Open CurrentControlSet */
+       RtlInitUnicodeString(&CCSName,
+                            L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Services");
+       Status = IopOpenRegistryKeyEx(&CCSKey, NULL, &CCSName, KEY_READ);
+       if (!NT_SUCCESS(Status))
+       {
+           DPRINT1("ZwOpenKey() failed with Status %08X\n", Status);
+           return Status;
+       }
 
-   /*
-    * Get information about the service.
-    */
+       /* Open service key */
+       Status = IopOpenRegistryKeyEx(&ServiceKey, CCSKey, ServiceName, KEY_READ);
+       if (!NT_SUCCESS(Status))
+       {
+           DPRINT1("ZwOpenKey() failed with Status %08X\n", Status);
+           ZwClose(CCSKey);
+           return Status;
+       }
 
-   RtlZeroMemory(QueryTable, sizeof(QueryTable));
+       /*
+        * Get information about the service.
+        */
 
-   RtlInitUnicodeString(&ServiceImagePath, NULL);
+       RtlZeroMemory(QueryTable, sizeof(QueryTable));
 
-   QueryTable[0].Name = L"Start";
-   QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
-   QueryTable[0].EntryContext = &ServiceStart;
+       RtlInitUnicodeString(&ServiceImagePath, NULL);
 
-   QueryTable[1].Name = L"ImagePath";
-   QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
-   QueryTable[1].EntryContext = &ServiceImagePath;
+       QueryTable[0].Name = L"Start";
+       QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
+       QueryTable[0].EntryContext = &ServiceStart;
 
-   Status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,
-      (PWSTR)ServiceKey, QueryTable, NULL, NULL);
+       QueryTable[1].Name = L"ImagePath";
+       QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
+       QueryTable[1].EntryContext = &ServiceImagePath;
 
-   ZwClose(ServiceKey);
-   ZwClose(CCSKey);
+       Status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,
+          (PWSTR)ServiceKey, QueryTable, NULL, NULL);
 
-   if (!NT_SUCCESS(Status))
-   {
-      DPRINT1("RtlQueryRegistryValues() failed (Status %x)\n", Status);
-      return Status;
+       ZwClose(ServiceKey);
+       ZwClose(CCSKey);
+
+       if (!NT_SUCCESS(Status))
+       {
+          DPRINT1("RtlQueryRegistryValues() failed (Status %x)\n", Status);
+          return Status;
+       }
    }
 
    /*
@@ -348,20 +387,24 @@ IopLoadServiceModule(
       return Status;
    }
 
-      /*
-       * Case for disabled drivers
-       */
-
-  if (ServiceStart >= 4)
-  {
-     /* FIXME: Check if it is the right status code */
-     Status = STATUS_PLUGPLAY_NO_DEVICE;
-  }
-  else
-  {
-     DPRINT("Loading module\n");
-     Status = MmLoadSystemImage(&ServiceImagePath, NULL, NULL, 0, (PVOID)ModuleObject, &BaseAddress);
-  }
+   /*
+    * Case for disabled drivers
+    */
+
+   if (ServiceStart >= 4)
+   {
+      /* FIXME: Check if it is the right status code */
+      Status = STATUS_PLUGPLAY_NO_DEVICE;
+   }
+   else
+   {
+      DPRINT("Loading module from %wZ\n", &ServiceImagePath);
+      Status = MmLoadSystemImage(&ServiceImagePath, NULL, NULL, 0, (PVOID)ModuleObject, &BaseAddress);
+      if (NT_SUCCESS(Status))
+      {
+          IopDisplayLoadingMessage(ServiceName);
+      }
+   }
 
    ExFreePool(ServiceImagePath.Buffer);
 
@@ -417,7 +460,6 @@ IopInitializeDriverModule(
    UNICODE_STRING RegistryKey;
    PDRIVER_INITIALIZE DriverEntry;
    PDRIVER_OBJECT Driver;
-   PDEVICE_OBJECT DeviceObject;
    NTSTATUS Status;
 
    DriverEntry = ModuleObject->EntryPoint;
@@ -461,8 +503,7 @@ IopInitializeDriverModule(
        DriverName.Length > 0 ? &DriverName : NULL,
        DriverEntry,
        &RegistryKey,
-       ModuleObject->DllBase,
-       ModuleObject->SizeOfImage,
+       ModuleObject,
        &Driver);
    RtlFreeUnicodeString(&RegistryKey);
 
@@ -474,14 +515,7 @@ IopInitializeDriverModule(
    }
 
    /* Set the driver as initialized */
-   Driver->Flags |= DRVO_INITIALIZED;
-   DeviceObject = Driver->DeviceObject;
-   while (DeviceObject)
-   {
-       /* Set every device as initialized too */
-       DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
-       DeviceObject = DeviceObject->NextDevice;
-   }
+   IopReadyDeviceObjects(Driver);
 
    if (PnpSystemInit) IopReinitializeDrivers();
 
@@ -518,7 +552,7 @@ IopAttachFilterDriversCallback(
       DPRINT("Filter Driver: %S (%wZ)\n", Filters, &DeviceNode->InstancePath);
       ServiceName.Buffer = Filters;
       ServiceName.MaximumLength =
-      ServiceName.Length = wcslen(Filters) * sizeof(WCHAR);
+      ServiceName.Length = (USHORT)wcslen(Filters) * sizeof(WCHAR);
 
       /* Load and initialize the filter driver */
       Status = IopLoadServiceModule(&ServiceName, &ModuleObject);
@@ -697,12 +731,12 @@ MiResolveImageReferences(IN PVOID ImageBase,
 //
 NTSTATUS
 NTAPI
+INIT_FUNCTION
 LdrProcessDriverModule(PLDR_DATA_TABLE_ENTRY LdrEntry,
                        PUNICODE_STRING FileName,
                        PLDR_DATA_TABLE_ENTRY *ModuleObject)
 {
     NTSTATUS Status;
-    PLDR_DATA_TABLE_ENTRY NewEntry;
     UNICODE_STRING BaseName, BaseDirectory;
     PLOAD_IMPORTS LoadedImports = (PVOID)-2;
     PCHAR MissingApiName, Buffer;
@@ -750,8 +784,6 @@ LdrProcessDriverModule(PLDR_DATA_TABLE_ENTRY LdrEntry,
     BaseDirectory.Length -= BaseName.Length;
     BaseDirectory.MaximumLength = BaseDirectory.Length;
 
-    NewEntry = LdrEntry;
-
     /* Resolve imports */
     MissingApiName = Buffer;
     Status = MiResolveImageReferences(DriverBase,
@@ -775,6 +807,7 @@ LdrProcessDriverModule(PLDR_DATA_TABLE_ENTRY LdrEntry,
 
 NTSTATUS
 NTAPI
+INIT_FUNCTION
 IopInitializeBuiltinDriver(IN PLDR_DATA_TABLE_ENTRY LdrEntry)
 {
     PDEVICE_NODE DeviceNode;
@@ -788,7 +821,8 @@ IopInitializeBuiltinDriver(IN PLDR_DATA_TABLE_ENTRY LdrEntry)
    /*
     * Display 'Loading XXX...' message
     */
-   IopDisplayLoadingMessage(ModuleName->Buffer, TRUE);
+   IopDisplayLoadingMessage(ModuleName);
+   InbvIndicateProgress();
 
    /*
     * Generate filename without path (not needed by freeldr)
@@ -810,7 +844,7 @@ IopInitializeBuiltinDriver(IN PLDR_DATA_TABLE_ENTRY LdrEntry)
    FileExtension = wcsrchr(ServiceName.Buffer, '.');
    if (FileExtension != NULL)
    {
-      ServiceName.Length -= wcslen(FileExtension) * sizeof(WCHAR);
+      ServiceName.Length -= (USHORT)wcslen(FileExtension) * sizeof(WCHAR);
       FileExtension[0] = 0;
    }
 
@@ -824,7 +858,6 @@ IopInitializeBuiltinDriver(IN PLDR_DATA_TABLE_ENTRY LdrEntry)
       DPRINT1("Driver '%wZ' load failed, status (%x)\n", ModuleName, Status);
       return(Status);
    }
-   DeviceNode->ServiceName = ServiceName;
 
    /*
     * Initialize the driver
@@ -860,16 +893,20 @@ IopInitializeBuiltinDriver(IN PLDR_DATA_TABLE_ENTRY LdrEntry)
  */
 VOID
 FASTCALL
+INIT_FUNCTION
 IopInitializeBootDrivers(VOID)
 {
-    PLIST_ENTRY ListHead, NextEntry;
+    PLIST_ENTRY ListHead, NextEntry, NextEntry2;
     PLDR_DATA_TABLE_ENTRY LdrEntry;
     PDEVICE_NODE DeviceNode;
     PDRIVER_OBJECT DriverObject;
     LDR_DATA_TABLE_ENTRY ModuleObject;
     NTSTATUS Status;
     UNICODE_STRING DriverName;
-
+    ULONG i, Index;
+    PDRIVER_INFORMATION DriverInfo, DriverInfoTag;
+    HANDLE KeyHandle;
+    PBOOT_DRIVER_LIST_ENTRY BootEntry;
     DPRINT("IopInitializeBootDrivers()\n");
 
     /* Use IopRootDeviceNode for now */
@@ -913,6 +950,19 @@ IopInitializeBootDrivers(VOID)
         return;
     }
 
+    /* Get highest group order index */
+    IopGroupIndex = PpInitGetGroupOrderIndex(NULL);
+    if (IopGroupIndex == 0xFFFF) ASSERT(FALSE);
+
+    /* Allocate the group table */
+    IopGroupTable = ExAllocatePoolWithTag(PagedPool,
+                                          IopGroupIndex * sizeof(LIST_ENTRY),
+                                          TAG_IO);
+    if (IopGroupTable == NULL) ASSERT(FALSE);
+
+    /* Initialize the group table lists */
+    for (i = 0; i < IopGroupIndex; i++) InitializeListHead(&IopGroupTable[i]);
+
     /* Loop the boot modules */
     ListHead = &KeLoaderBlock->LoadOrderListHead;
     NextEntry = ListHead->Flink;
@@ -923,18 +973,82 @@ IopInitializeBootDrivers(VOID)
                                      LDR_DATA_TABLE_ENTRY,
                                      InLoadOrderLinks);
 
-        /*
-         * HACK: Make sure we're loading a driver
-         * (we should be using BootDriverListHead!)
-         */
-        if (wcsstr(_wcsupr(LdrEntry->BaseDllName.Buffer), L".SYS"))
+        /* Check if the DLL needs to be initialized */
+        if (LdrEntry->Flags & LDRP_DRIVER_DEPENDENT_DLL)
         {
-            /* Make sure we didn't load this driver already */
-            if (!(LdrEntry->Flags & LDRP_ENTRY_INSERTED))
+            /* Call its entrypoint */
+            MmCallDllInitialize(LdrEntry, NULL);
+        }
+
+        /* Go to the next driver */
+        NextEntry = NextEntry->Flink;
+    }
+
+    /* Loop the boot drivers */
+    ListHead = &KeLoaderBlock->BootDriverListHead;
+    NextEntry = ListHead->Flink;
+    while (ListHead != NextEntry)
+    {
+        /* Get the entry */
+        BootEntry = CONTAINING_RECORD(NextEntry,
+                                      BOOT_DRIVER_LIST_ENTRY,
+                                      Link);
+
+        /* Get the driver loader entry */
+        LdrEntry = BootEntry->LdrEntry;
+
+        /* Allocate our internal accounting structure */
+        DriverInfo = ExAllocatePoolWithTag(PagedPool,
+                                           sizeof(DRIVER_INFORMATION),
+                                           TAG_IO);
+        if (DriverInfo)
+        {
+            /* Zero it and initialize it */
+            RtlZeroMemory(DriverInfo, sizeof(DRIVER_INFORMATION));
+            InitializeListHead(&DriverInfo->Link);
+            DriverInfo->DataTableEntry = BootEntry;
+
+            /* Open the registry key */
+            Status = IopOpenRegistryKeyEx(&KeyHandle,
+                                          NULL,
+                                          &BootEntry->RegistryPath,
+                                          KEY_READ);
+            if ((NT_SUCCESS(Status)) || /* ReactOS HACK for SETUPLDR */
+                ((KeLoaderBlock->SetupLdrBlock) && ((KeyHandle = (PVOID)1)))) // yes, it's an assignment!
             {
-                DPRINT("Initializing bootdriver %wZ\n", &LdrEntry->BaseDllName);
-                /* Initialize it */
-                IopInitializeBuiltinDriver(LdrEntry);
+                /* Save the handle */
+                DriverInfo->ServiceHandle = KeyHandle;
+
+                /* Get the group oder index */
+                Index = PpInitGetGroupOrderIndex(KeyHandle);
+
+                /* Get the tag position */
+                DriverInfo->TagPosition = PipGetDriverTagPriority(KeyHandle);
+
+                /* Insert it into the list, at the right place */
+                ASSERT(Index < IopGroupIndex);
+                NextEntry2 = IopGroupTable[Index].Flink;
+                while (NextEntry2 != &IopGroupTable[Index])
+                {
+                    /* Get the driver info */
+                    DriverInfoTag = CONTAINING_RECORD(NextEntry2,
+                                                      DRIVER_INFORMATION,
+                                                      Link);
+
+                    /* Check if we found the right tag position */
+                    if (DriverInfoTag->TagPosition > DriverInfo->TagPosition)
+                    {
+                        /* We're done */
+                        break;
+                    }
+
+                    /* Next entry */
+                    NextEntry2 = NextEntry2->Flink;
+                }
+
+                /* Insert us right before the next entry */
+                NextEntry2 = NextEntry2->Blink;
+                InsertHeadList(NextEntry2, &DriverInfo->Link);
             }
         }
 
@@ -942,10 +1056,66 @@ IopInitializeBootDrivers(VOID)
         NextEntry = NextEntry->Flink;
     }
 
+    /* Loop each group index */
+    for (i = 0; i < IopGroupIndex; i++)
+    {
+        /* Loop each group table */
+        NextEntry = IopGroupTable[i].Flink;
+        while (NextEntry != &IopGroupTable[i])
+        {
+            /* Get the entry */
+            DriverInfo = CONTAINING_RECORD(NextEntry,
+                                           DRIVER_INFORMATION,
+                                           Link);
+
+            /* Get the driver loader entry */
+            LdrEntry = DriverInfo->DataTableEntry->LdrEntry;
+
+            /* Initialize it */
+            IopInitializeBuiltinDriver(LdrEntry);
+
+            /* Next entry */
+            NextEntry = NextEntry->Flink;
+        }
+    }
+
     /* In old ROS, the loader list became empty after this point. Simulate. */
     InitializeListHead(&KeLoaderBlock->LoadOrderListHead);
 }
 
+VOID
+FASTCALL
+INIT_FUNCTION
+IopInitializeSystemDrivers(VOID)
+{
+    PUNICODE_STRING *DriverList, *SavedList;
+
+    /* No system drivers on the boot cd */
+    if (KeLoaderBlock->SetupLdrBlock) return;
+
+    /* Get the driver list */
+    SavedList = DriverList = CmGetSystemDriverList();
+    ASSERT(DriverList);
+
+    /* Loop it */
+    while (*DriverList)
+    {
+        /* Load the driver */
+        ZwLoadDriver(*DriverList);
+
+        /* Free the entry */
+        RtlFreeUnicodeString(*DriverList);
+        ExFreePool(*DriverList);
+
+        /* Next entry */
+        InbvIndicateProgress();
+        DriverList++;
+    }
+
+    /* Free the list */
+    ExFreePool(SavedList);
+}
+
 /*
  * IopUnloadDriver
  *
@@ -1002,7 +1172,7 @@ IopUnloadDriver(PUNICODE_STRING DriverServiceName, BOOLEAN UnloadPnpDrivers)
     * Construct the driver object name
     */
 
-   ObjectName.Length = (wcslen(Start) + 8) * sizeof(WCHAR);
+   ObjectName.Length = ((USHORT)wcslen(Start) + 8) * sizeof(WCHAR);
    ObjectName.MaximumLength = ObjectName.Length + sizeof(WCHAR);
    ObjectName.Buffer = ExAllocatePool(PagedPool, ObjectName.MaximumLength);
    if (!ObjectName.Buffer) return STATUS_INSUFFICIENT_RESOURCES;
@@ -1022,17 +1192,18 @@ IopUnloadDriver(PUNICODE_STRING DriverServiceName, BOOLEAN UnloadPnpDrivers)
                                     0,
                                     (PVOID*)&DriverObject);
 
-   /*
-    * Free the buffer for driver object name
-    */
-   ExFreePool(ObjectName.Buffer);
-
    if (!NT_SUCCESS(Status))
    {
       DPRINT1("Can't locate driver object for %wZ\n", &ObjectName);
+      ExFreePool(ObjectName.Buffer);
       return Status;
    }
 
+   /*
+    * Free the buffer for driver object name
+    */
+   ExFreePool(ObjectName.Buffer);
+
    /* Check that driver is not already unloading */
    if (DriverObject->Flags & DRVO_UNLOAD_INVOKED)
    {
@@ -1241,8 +1412,7 @@ NTAPI
 IopCreateDriver(IN PUNICODE_STRING DriverName OPTIONAL,
                 IN PDRIVER_INITIALIZE InitializationFunction,
                 IN PUNICODE_STRING RegistryPath,
-                IN PVOID DllBase,
-                IN ULONG SizeOfImage,
+                PLDR_DATA_TABLE_ENTRY ModuleObject,
                 OUT PDRIVER_OBJECT *pDriverObject)
 {
     WCHAR NameBuffer[100];
@@ -1304,7 +1474,7 @@ try_again:
     DriverObject->DriverExtension = (PDRIVER_EXTENSION)(DriverObject + 1);
     DriverObject->DriverExtension->DriverObject = DriverObject;
     DriverObject->DriverInit = InitializationFunction;
-
+    DriverObject->DriverSection = ModuleObject;
     /* Loop all Major Functions */
     for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
     {
@@ -1378,8 +1548,8 @@ try_again:
     ZwClose(hDriver);
 
     DriverObject->HardwareDatabase = &IopHardwareDatabaseKey;
-    DriverObject->DriverStart = DllBase;
-    DriverObject->DriverSize = SizeOfImage;
+    DriverObject->DriverStart = ModuleObject ? ModuleObject->DllBase : 0;
+    DriverObject->DriverSize = ModuleObject ? ModuleObject->SizeOfImage : 0;
 
     /* Finally, call its init function */
     DPRINT("RegistryKey: %wZ\n", RegistryPath);
@@ -1389,6 +1559,7 @@ try_again:
     {
         /* If it didn't work, then kill the object */
         DPRINT1("'%wZ' initialization failed, status (0x%08lx)\n", DriverName, Status);
+        DriverObject->DriverSection = NULL;
         ObMakeTemporaryObject(DriverObject);
         ObDereferenceObject(DriverObject);
     }
@@ -1406,11 +1577,14 @@ try_again:
          * Doing so is illegal; drivers shouldn't touch entry points they
          * do not implement.
          */
-        ASSERT(DriverObject->MajorFunction[i] != NULL);
 
         /* Check if it did so anyway */
-               if (!DriverObject->MajorFunction[i])
+        if (!DriverObject->MajorFunction[i])
         {
+            /* Print a warning in the debug log */
+            DPRINT1("Driver <%wZ> set DriverObject->MajorFunction[%d] to NULL!\n",
+                    &DriverObject->DriverName, i);
+
             /* Fix it up */
             DriverObject->MajorFunction[i] = IopInvalidDeviceRequest;
         }
@@ -1431,7 +1605,7 @@ IoCreateDriver(IN PUNICODE_STRING DriverName OPTIONAL,
                IN PDRIVER_INITIALIZE InitializationFunction)
 {
    PDRIVER_OBJECT DriverObject;
-   return IopCreateDriver(DriverName, InitializationFunction, NULL, 0, 0, &DriverObject);
+   return IopCreateDriver(DriverName, InitializationFunction, NULL, NULL, &DriverObject);
 }
 
 /*
@@ -1713,21 +1887,6 @@ IopLoadUnloadDriver(PLOAD_UNLOAD_PARAMS LoadParams)
    DPRINT("FullImagePath: '%wZ'\n", &ImagePath);
    DPRINT("Type: %lx\n", Type);
 
-   /*
-    * Create device node
-    */
-
-   /* Use IopRootDeviceNode for now */
-   Status = IopCreateDeviceNode(IopRootDeviceNode, NULL, &ServiceName, &DeviceNode);
-
-   if (!NT_SUCCESS(Status))
-   {
-      DPRINT("IopCreateDeviceNode() failed (Status %lx)\n", Status);
-      LoadParams->Status = Status;
-      (VOID)KeSetEvent(&LoadParams->Event, 0, FALSE);
-      return;
-   }
-
    /* Get existing DriverObject pointer (in case the driver has
       already been loaded and initialized) */
    Status = IopGetDriverObject(
@@ -1742,27 +1901,35 @@ IopLoadUnloadDriver(PLOAD_UNLOAD_PARAMS LoadParams)
         * Load the driver module
         */
 
+       DPRINT("Loading module from %wZ\n", &ImagePath);
        Status = MmLoadSystemImage(&ImagePath, NULL, NULL, 0, (PVOID)&ModuleObject, &BaseAddress);
+
        if (!NT_SUCCESS(Status) && Status != STATUS_IMAGE_ALREADY_LOADED)
        {
            DPRINT("MmLoadSystemImage() failed (Status %lx)\n", Status);
-           IopFreeDeviceNode(DeviceNode);
            LoadParams->Status = Status;
            (VOID)KeSetEvent(&LoadParams->Event, 0, FALSE);
            return;
        }
 
-       /*
-        * Set a service name for the device node
-        */
-
-       RtlCreateUnicodeString(&DeviceNode->ServiceName, ServiceName.Buffer);
-
        /*
         * Initialize the driver module if it's loaded for the first time
         */
        if (Status != STATUS_IMAGE_ALREADY_LOADED)
        {
+           Status = IopCreateDeviceNode(IopRootDeviceNode, NULL, &ServiceName, &DeviceNode);
+
+           if (!NT_SUCCESS(Status))
+           {
+               DPRINT("IopCreateDeviceNode() failed (Status %lx)\n", Status);
+               MmUnloadSystemImage(ModuleObject);
+               LoadParams->Status = Status;
+               (VOID)KeSetEvent(&LoadParams->Event, 0, FALSE);
+               return;
+           }
+
+           IopDisplayLoadingMessage(&DeviceNode->ServiceName);
+
            Status = IopInitializeDriverModule(
                DeviceNode,
                ModuleObject,
@@ -1780,14 +1947,11 @@ IopLoadUnloadDriver(PLOAD_UNLOAD_PARAMS LoadParams)
                (VOID)KeSetEvent(&LoadParams->Event, 0, FALSE);
                return;
            }
-       }
-
-       /* Store its DriverSection, so that it could be unloaded */
-       DriverObject->DriverSection = ModuleObject;
 
-       /* Initialize and start device */
-       IopInitializeDevice(DeviceNode, DriverObject);
-       Status = IopStartDevice(DeviceNode);
+           /* Initialize and start device */
+           IopInitializeDevice(DeviceNode, DriverObject);
+           Status = IopStartDevice(DeviceNode);
+       }
    }
    else
    {
@@ -1795,9 +1959,6 @@ IopLoadUnloadDriver(PLOAD_UNLOAD_PARAMS LoadParams)
 
       /* IopGetDriverObject references the DriverObject, so dereference it */
       ObDereferenceObject(DriverObject);
-
-      /* Free device node since driver loading failed */
-      IopFreeDeviceNode(DeviceNode);
    }
 
    /* Pass status to the caller and signal the event */