[NTOSKRNL]
[reactos.git] / reactos / ntoskrnl / io / iomgr / driver.c
index 3353bcb..7dcb035 100644 (file)
@@ -12,7 +12,7 @@
 
 #include <ntoskrnl.h>
 #define NDEBUG
-#include <internal/debug.h>
+#include <debug.h>
 
 /* GLOBALS ********************************************************************/
 
@@ -29,11 +29,17 @@ UNICODE_STRING IopHardwareDatabaseKey =
 
 POBJECT_TYPE IoDriverObjectType = NULL;
 
+#define TAG_RTLREGISTRY 'vrqR'
+
 extern BOOLEAN ExpInTextModeSetup;
+extern BOOLEAN PnpSystemInit;
+
+USHORT IopGroupIndex;
+PLIST_ENTRY IopGroupTable;
 
 /* PRIVATE FUNCTIONS **********************************************************/
 
-NTSTATUS STDCALL
+NTSTATUS NTAPI
 IopInvalidDeviceRequest(
    PDEVICE_OBJECT DeviceObject,
    PIRP Irp)
@@ -69,7 +75,7 @@ IopDeleteDriver(IN PVOID ObjectBody)
     if (DriverObject->DriverSection)
     {
         /* Unload it */
-        //LdrpUnloadImage(DriverObject->DriverSection);
+        MmUnloadSystemImage(DriverObject->DriverSection);
     }
 
     /* Check if it has a name */
@@ -135,7 +141,7 @@ IopGetDriverObject(
 
    if (!NT_SUCCESS(Status))
    {
-      DPRINT1("Failed to reference driver object, status=0x%08x\n", Status);
+      DPRINT("Failed to reference driver object, status=0x%08x\n", Status);
       return Status;
    }
 
@@ -146,6 +152,39 @@ 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
  *
@@ -155,35 +194,20 @@ IopGetDriverObject(
 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);
 }
 
@@ -222,27 +246,31 @@ IopNormalizeImagePath(
 
    if (InputImagePath.Length == 0)
    {
-      ImagePath->Length = (33 * sizeof(WCHAR)) + ServiceName->Length;
-      ImagePath->MaximumLength = ImagePath->Length + sizeof(UNICODE_NULL);
+      ImagePath->Length = 0;
+      ImagePath->MaximumLength =
+          (33 * sizeof(WCHAR)) + ServiceName->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");
+      RtlAppendUnicodeToString(ImagePath, L"\\SystemRoot\\system32\\drivers\\");
+      RtlAppendUnicodeStringToString(ImagePath, ServiceName);
+      RtlAppendUnicodeToString(ImagePath, L".sys");
    } else
    if (InputImagePath.Buffer[0] != L'\\')
    {
-      ImagePath->Length = (12 * sizeof(WCHAR)) + InputImagePath.Length;
-      ImagePath->MaximumLength = ImagePath->Length + sizeof(UNICODE_NULL);
+      ImagePath->Length = 0;
+      ImagePath->MaximumLength =
+          12 * sizeof(WCHAR) + InputImagePath.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);
+      RtlAppendUnicodeToString(ImagePath, L"\\SystemRoot\\");
+      RtlAppendUnicodeStringToString(ImagePath, &InputImagePath);
+
+      /* Free caller's string */
+      ExFreePoolWithTag(InputImagePath.Buffer, TAG_RTLREGISTRY);
    }
 
    return STATUS_SUCCESS;
@@ -268,14 +296,38 @@ IopLoadServiceModule(
 {
    RTL_QUERY_REGISTRY_TABLE QueryTable[3];
    ULONG ServiceStart;
-   UNICODE_STRING ServiceImagePath;
+   UNICODE_STRING ServiceImagePath, CCSName;
    NTSTATUS Status;
+   HANDLE CCSKey, ServiceKey;
+   PVOID BaseAddress;
 
    DPRINT("IopLoadServiceModule(%wZ, 0x%p)\n", ServiceName, ModuleObject);
 
    /* FIXME: This check may be removed once the bug is fixed */
    if (ServiceName->Buffer == NULL)
+   {
+       DPRINT1("If you see this, please report to Fireball or hpoussin!\n");
       return STATUS_UNSUCCESSFUL;
+   }
+
+   /* 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;
+   }
+
+   /* 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;
+   }
 
    /*
     * Get information about the service.
@@ -293,12 +345,15 @@ IopLoadServiceModule(
    QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
    QueryTable[1].EntryContext = &ServiceImagePath;
 
-   Status = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES,
-      ServiceName->Buffer, QueryTable, NULL, NULL);
+   Status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,
+      (PWSTR)ServiceKey, QueryTable, NULL, NULL);
+
+   ZwClose(ServiceKey);
+   ZwClose(CCSKey);
 
    if (!NT_SUCCESS(Status))
    {
-      DPRINT("RtlQueryRegistryValues() failed (Status %x)\n", Status);
+      DPRINT1("RtlQueryRegistryValues() failed (Status %x)\n", Status);
       return Status;
    }
 
@@ -326,7 +381,7 @@ IopLoadServiceModule(
   else
   {
      DPRINT("Loading module\n");
-     Status = MmLoadSystemImage(&ServiceImagePath, NULL, NULL, 0, (PVOID)ModuleObject, NULL);
+     Status = MmLoadSystemImage(&ServiceImagePath, NULL, NULL, 0, (PVOID)ModuleObject, &BaseAddress);
   }
 
    ExFreePool(ServiceImagePath.Buffer);
@@ -383,7 +438,6 @@ IopInitializeDriverModule(
    UNICODE_STRING RegistryKey;
    PDRIVER_INITIALIZE DriverEntry;
    PDRIVER_OBJECT Driver;
-   PDEVICE_OBJECT DeviceObject;
    NTSTATUS Status;
 
    DriverEntry = ModuleObject->EntryPoint;
@@ -412,9 +466,12 @@ IopInitializeDriverModule(
          wcscpy(NameBuffer, FILESYSTEM_ROOT_NAME);
       else
          wcscpy(NameBuffer, DRIVER_ROOT_NAME);
-      wcscat(NameBuffer, ServiceName->Buffer);
 
       RtlInitUnicodeString(&DriverName, NameBuffer);
+      DriverName.MaximumLength = sizeof(NameBuffer);
+
+      RtlAppendUnicodeStringToString(&DriverName, ServiceName);
+
       DPRINT("Driver name: '%wZ'\n", &DriverName);
    }
    else
@@ -437,16 +494,9 @@ 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);
 
-   IopReinitializeDrivers();
+   if (PnpSystemInit) IopReinitializeDrivers();
 
    return STATUS_SUCCESS;
 }
@@ -457,7 +507,7 @@ IopInitializeDriverModule(
  * Internal routine used by IopAttachFilterDrivers.
  */
 
-NTSTATUS STDCALL
+NTSTATUS NTAPI
 IopAttachFilterDriversCallback(
    PWSTR ValueName,
    ULONG ValueType,
@@ -533,16 +583,35 @@ IopAttachFilterDrivers(
    PDEVICE_NODE DeviceNode,
    BOOLEAN Lower)
 {
-    RTL_QUERY_REGISTRY_TABLE QueryTable[2] = {{0}};
-   PWCHAR KeyBuffer;
+   RTL_QUERY_REGISTRY_TABLE QueryTable[2] = { { NULL, 0, NULL, NULL, 0, NULL, 0 }, };
    UNICODE_STRING Class;
    WCHAR ClassBuffer[40];
+   UNICODE_STRING EnumRoot = RTL_CONSTANT_STRING(ENUM_ROOT);
+   HANDLE EnumRootKey, SubKey;
    NTSTATUS Status;
 
+   /* Open enumeration root key */
+   Status = IopOpenRegistryKeyEx(&EnumRootKey, NULL,
+       &EnumRoot, KEY_READ);
+   if (!NT_SUCCESS(Status))
+   {
+       DPRINT1("ZwOpenKey() failed with Status %08X\n", Status);
+       return Status;
+   }
+
+   /* Open subkey */
+   Status = IopOpenRegistryKeyEx(&SubKey, EnumRootKey,
+       &DeviceNode->InstancePath, KEY_READ);
+   if (!NT_SUCCESS(Status))
+   {
+       DPRINT1("ZwOpenKey() failed with Status %08X\n", Status);
+       ZwClose(EnumRootKey);
+       return Status;
+   }
+
    /*
     * First load the device filters
     */
-
    QueryTable[0].QueryRoutine = IopAttachFilterDriversCallback;
    if (Lower)
      QueryTable[0].Name = L"LowerFilters";
@@ -550,15 +619,9 @@ IopAttachFilterDrivers(
      QueryTable[0].Name = L"UpperFilters";
    QueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED;
 
-   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,
+      RTL_REGISTRY_HANDLE,
+      (PWSTR)SubKey,
       QueryTable,
       DeviceNode,
       NULL);
@@ -566,7 +629,6 @@ IopAttachFilterDrivers(
    /*
     * Now get the class GUID
     */
-
    Class.Length = 0;
    Class.MaximumLength = 40 * sizeof(WCHAR);
    Class.Buffer = ClassBuffer;
@@ -576,20 +638,41 @@ IopAttachFilterDrivers(
    QueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_DIRECT;
 
    Status = RtlQueryRegistryValues(
-      RTL_REGISTRY_ABSOLUTE,
-      KeyBuffer,
+      RTL_REGISTRY_HANDLE,
+      (PWSTR)SubKey,
       QueryTable,
       DeviceNode,
       NULL);
 
-   ExFreePool(KeyBuffer);
+   /* Close handles */
+   ZwClose(SubKey);
+   ZwClose(EnumRootKey);
 
    /*
     * Load the class filter driver
     */
-
    if (NT_SUCCESS(Status))
    {
+       UNICODE_STRING ControlClass = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class");
+
+       Status = IopOpenRegistryKeyEx(&EnumRootKey, NULL,
+           &ControlClass, KEY_READ);
+       if (!NT_SUCCESS(Status))
+       {
+           DPRINT1("ZwOpenKey() failed with Status %08X\n", Status);
+           return Status;
+       }
+
+       /* Open subkey */
+       Status = IopOpenRegistryKeyEx(&SubKey, EnumRootKey,
+           &Class, KEY_READ);
+       if (!NT_SUCCESS(Status))
+       {
+           DPRINT1("ZwOpenKey() failed with Status %08X\n", Status);
+           ZwClose(EnumRootKey);
+           return Status;
+       }
+
       QueryTable[0].QueryRoutine = IopAttachFilterDriversCallback;
       if (Lower)
          QueryTable[0].Name = L"LowerFilters";
@@ -598,18 +681,16 @@ IopAttachFilterDrivers(
       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,
+         RTL_REGISTRY_HANDLE,
+         (PWSTR)SubKey,
          QueryTable,
          DeviceNode,
          NULL);
 
-      ExFreePool(KeyBuffer);
+      /* Clean up */
+      ZwClose(SubKey);
+      ZwClose(EnumRootKey);
    }
 
    return STATUS_SUCCESS;
@@ -624,8 +705,6 @@ MiResolveImageReferences(IN PVOID ImageBase,
                          OUT PWCHAR *MissingDriver,
                          OUT PLOAD_IMPORTS *LoadImports);
 
-extern KSPIN_LOCK PsLoadedModuleSpinLock;
-
 //
 // Used for images already loaded (boot drivers)
 //
@@ -718,15 +797,12 @@ IopInitializeBuiltinDriver(IN PLDR_DATA_TABLE_ENTRY LdrEntry)
     LPWSTR FileExtension;
     PUNICODE_STRING ModuleName = &LdrEntry->BaseDllName;
     UNICODE_STRING ServiceName;
-#if 1 // Disable for FreeLDR 2.5
-    UNICODE_STRING ServiceNameWithExtension;
-    PLDR_DATA_TABLE_ENTRY ModuleObject;
-#endif
 
    /*
     * Display 'Loading XXX...' message
     */
-   IopDisplayLoadingMessage(ModuleName->Buffer, TRUE);
+   IopDisplayLoadingMessage(ModuleName);
+   InbvIndicateProgress();
 
    /*
     * Generate filename without path (not needed by freeldr)
@@ -741,19 +817,6 @@ IopInitializeBuiltinDriver(IN PLDR_DATA_TABLE_ENTRY LdrEntry)
       FileNameWithoutPath++;
    }
 
-   /*
-    * Load the module. 
-    */
-#if 1 // Remove for FreeLDR 2.5.
-   RtlCreateUnicodeString(&ServiceNameWithExtension, FileNameWithoutPath);
-   Status = LdrProcessDriverModule(LdrEntry, &ServiceNameWithExtension, &ModuleObject);
-   if (!NT_SUCCESS(Status))
-   {
-       CPRINT("Driver '%wZ' load failed, status (%x)\n", ModuleName, Status);
-       return Status;
-   }
-#endif
-
    /*
     * Strip the file extension from ServiceName
     */
@@ -772,7 +835,7 @@ IopInitializeBuiltinDriver(IN PLDR_DATA_TABLE_ENTRY LdrEntry)
    Status = IopCreateDeviceNode(IopRootDeviceNode, NULL, &ServiceName, &DeviceNode);
    if (!NT_SUCCESS(Status))
    {
-      CPRINT("Driver '%wZ' load failed, status (%x)\n", ModuleName, Status);
+      DPRINT1("Driver '%wZ' load failed, status (%x)\n", ModuleName, Status);
       return(Status);
    }
    DeviceNode->ServiceName = ServiceName;
@@ -780,14 +843,12 @@ IopInitializeBuiltinDriver(IN PLDR_DATA_TABLE_ENTRY LdrEntry)
    /*
     * Initialize the driver
     */
-   DeviceNode->Flags |= DN_DRIVER_LOADED;
    Status = IopInitializeDriverModule(DeviceNode, LdrEntry,
       &DeviceNode->ServiceName, FALSE, &DriverObject);
 
    if (!NT_SUCCESS(Status))
    {
       IopFreeDeviceNode(DeviceNode);
-      CPRINT("Driver '%wZ' load failed, status (%x)\n", ModuleName, Status);
       return Status;
    }
 
@@ -815,15 +876,18 @@ VOID
 FASTCALL
 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;
-
-    DPRINT("IopInitializeBootDrivers()");
+    ULONG i, Index;
+    PDRIVER_INFORMATION DriverInfo, DriverInfoTag;
+    HANDLE KeyHandle;
+    PBOOT_DRIVER_LIST_ENTRY BootEntry;
+    DPRINT("IopInitializeBootDrivers()\n");
 
     /* Use IopRootDeviceNode for now */
     Status = IopCreateDeviceNode(IopRootDeviceNode, NULL, NULL, &DeviceNode);
@@ -866,6 +930,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;
@@ -875,19 +952,83 @@ IopInitializeBootDrivers(VOID)
         LdrEntry = CONTAINING_RECORD(NextEntry,
                                      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)
+        {
+            /* 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)
         {
-            /* Make sure we didn't load this driver already */
-            if (!(LdrEntry->Flags & LDRP_ENTRY_INSERTED))
+            /* 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)))
             {
-                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);
             }
         }
 
@@ -895,10 +1036,65 @@ 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
+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
  *
@@ -920,7 +1116,7 @@ IopInitializeBootDrivers(VOID)
  *    Guard the whole function by SEH.
  */
 
-NTSTATUS STDCALL
+NTSTATUS NTAPI
 IopUnloadDriver(PUNICODE_STRING DriverServiceName, BOOLEAN UnloadPnpDrivers)
 {
    RTL_QUERY_REGISTRY_TABLE QueryTable[2];
@@ -928,8 +1124,12 @@ IopUnloadDriver(PUNICODE_STRING DriverServiceName, BOOLEAN UnloadPnpDrivers)
    UNICODE_STRING ServiceName;
    UNICODE_STRING ObjectName;
    PDRIVER_OBJECT DriverObject;
+   PDEVICE_OBJECT DeviceObject;
+   PEXTENDED_DEVOBJ_EXTENSION DeviceExtension;
+   LOAD_UNLOAD_PARAMS LoadParams;
    NTSTATUS Status;
    LPWSTR Start;
+   BOOLEAN SafeToUnload = TRUE;
 
    DPRINT("IopUnloadDriver('%wZ', %d)\n", DriverServiceName, UnloadPnpDrivers);
 
@@ -954,29 +1154,43 @@ IopUnloadDriver(PUNICODE_STRING DriverServiceName, BOOLEAN UnloadPnpDrivers)
    ObjectName.Length = (wcslen(Start) + 8) * sizeof(WCHAR);
    ObjectName.MaximumLength = ObjectName.Length + sizeof(WCHAR);
    ObjectName.Buffer = ExAllocatePool(PagedPool, ObjectName.MaximumLength);
+   if (!ObjectName.Buffer) return STATUS_INSUFFICIENT_RESOURCES;
    wcscpy(ObjectName.Buffer, L"\\Driver\\");
-   memcpy(ObjectName.Buffer + 8, Start, (ObjectName.Length - 8) * sizeof(WCHAR));
+   memcpy(ObjectName.Buffer + 8, Start, ObjectName.Length - 8 * sizeof(WCHAR));
    ObjectName.Buffer[ObjectName.Length/sizeof(WCHAR)] = 0;
 
    /*
     * Find the driver object
     */
-
-   Status = ObReferenceObjectByName(&ObjectName, 0, 0, 0, IoDriverObjectType,
-      KernelMode, 0, (PVOID*)&DriverObject);
+   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);
+      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)
+   {
+       DPRINT1("Driver deletion pending\n");
+       ObDereferenceObject(DriverObject);
+       return STATUS_DELETE_PENDING;
+   }
+
    /*
     * Get path of service...
     */
@@ -994,7 +1208,8 @@ IopUnloadDriver(PUNICODE_STRING DriverServiceName, BOOLEAN UnloadPnpDrivers)
 
    if (!NT_SUCCESS(Status))
    {
-      DPRINT("RtlQueryRegistryValues() failed (Status %x)\n", Status);
+      DPRINT1("RtlQueryRegistryValues() failed (Status %x)\n", Status);
+      ObDereferenceObject(DriverObject);
       return Status;
    }
 
@@ -1006,7 +1221,8 @@ IopUnloadDriver(PUNICODE_STRING DriverServiceName, BOOLEAN UnloadPnpDrivers)
 
    if (!NT_SUCCESS(Status))
    {
-      DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status);
+      DPRINT1("IopNormalizeImagePath() failed (Status %x)\n", Status);
+      ObDereferenceObject(DriverObject);
       return Status;
    }
 
@@ -1020,13 +1236,82 @@ IopUnloadDriver(PUNICODE_STRING DriverServiceName, BOOLEAN UnloadPnpDrivers)
     * Unload the module and release the references to the device object
     */
 
-   if (DriverObject->DriverUnload)
-      (*DriverObject->DriverUnload)(DriverObject);
-   ObDereferenceObject(DriverObject);
-   ObDereferenceObject(DriverObject);
-   MmUnloadSystemImage(DriverObject->DriverSection);
+    /* Call the load/unload routine, depending on current process */
+   if (DriverObject->DriverUnload && DriverObject->DriverSection)
+   {
+      /* Loop through each device object of the driver
+         and set DOE_UNLOAD_PENDING flag */
+      DeviceObject = DriverObject->DeviceObject;
+      while (DeviceObject)
+      {
+         /* Set the unload pending flag for the device */
+         DeviceExtension = IoGetDevObjExtension(DeviceObject);
+         DeviceExtension->ExtensionFlags |= DOE_UNLOAD_PENDING;
 
-   return STATUS_SUCCESS;
+         /* Make sure there are no attached devices or no reference counts */
+         if ((DeviceObject->ReferenceCount) || (DeviceObject->AttachedDevice))
+         {
+            /* Not safe to unload */
+            DPRINT1("Drivers device object is referenced or has attached devices\n");
+
+            SafeToUnload = FALSE;
+         }
+
+         DeviceObject = DeviceObject->NextDevice;
+      }
+
+      /* If not safe to unload, then return success */
+      if (!SafeToUnload)
+      {
+         ObDereferenceObject(DriverObject);
+         return STATUS_SUCCESS;
+      }
+
+      /* Set the unload invoked flag */
+      DriverObject->Flags |= DRVO_UNLOAD_INVOKED;
+
+      if (PsGetCurrentProcess() == PsInitialSystemProcess)
+      {
+         /* Just call right away */
+         (*DriverObject->DriverUnload)(DriverObject);
+      }
+      else
+      {
+         /* Load/Unload must be called from system process */
+
+         /* Prepare parameters block */
+         LoadParams.DriverObject = DriverObject;
+         KeInitializeEvent(&LoadParams.Event, NotificationEvent, FALSE);
+
+         ExInitializeWorkItem(&LoadParams.WorkItem,
+             (PWORKER_THREAD_ROUTINE)IopLoadUnloadDriver,
+             (PVOID)&LoadParams);
+
+         /* Queue it */
+         ExQueueWorkItem(&LoadParams.WorkItem, DelayedWorkQueue);
+
+         /* And wait when it completes */
+         KeWaitForSingleObject(&LoadParams.Event, UserRequest, KernelMode,
+             FALSE, NULL);
+      }
+
+      /* Mark the driver object temporary, so it could be deleted later */
+      ObMakeTemporaryObject(DriverObject);
+
+      /* Dereference it 2 times */
+      ObDereferenceObject(DriverObject);
+      ObDereferenceObject(DriverObject);
+
+      return STATUS_SUCCESS;
+   }
+   else
+   {
+      /* Dereference one time (refd inside this function) */
+      ObDereferenceObject(DriverObject);
+
+      /* Return unloading failure */
+      return STATUS_INVALID_DEVICE_REQUEST;
+   }
 }
 
 VOID
@@ -1126,7 +1411,9 @@ try_again:
     if (!DriverName)
     {
         /* Create a random name and set up the string*/
-        NameLength = swprintf(NameBuffer, L"\\Driver\\%08u", KeTickCount);
+        NameLength = (USHORT)swprintf(NameBuffer,
+                                      L"\\Driver\\%08u",
+                                      KeTickCount);
         LocalDriverName.Length = NameLength * sizeof(WCHAR);
         LocalDriverName.MaximumLength = LocalDriverName.Length + sizeof(UNICODE_NULL);
         LocalDriverName.Buffer = NameBuffer;
@@ -1163,7 +1450,7 @@ try_again:
     RtlZeroMemory(DriverObject, ObjectSize);
     DriverObject->Type = IO_TYPE_DRIVER;
     DriverObject->Size = sizeof(DRIVER_OBJECT);
-    DriverObject->Flags = DRVO_BUILTIN_DRIVER;
+    DriverObject->Flags = DRVO_LEGACY_DRIVER;//DRVO_BUILTIN_DRIVER;
     DriverObject->DriverExtension = (PDRIVER_EXTENSION)(DriverObject + 1);
     DriverObject->DriverExtension->DriverObject = DriverObject;
     DriverObject->DriverInit = InitializationFunction;
@@ -1208,7 +1495,7 @@ try_again:
     Status = ObInsertObject(DriverObject,
                             NULL,
                             FILE_READ_DATA,
-                            OBJ_KERNEL_HANDLE,
+                            0,
                             NULL,
                             &hDriver);
 
@@ -1251,6 +1538,7 @@ try_again:
     if (!NT_SUCCESS(Status))
     {
         /* If it didn't work, then kill the object */
+        DPRINT1("'%wZ' initialization failed, status (0x%08lx)\n", DriverName, Status);
         ObMakeTemporaryObject(DriverObject);
         ObDereferenceObject(DriverObject);
     }
@@ -1260,6 +1548,27 @@ try_again:
         *pDriverObject = DriverObject;
     }
 
+    /* Loop all Major Functions */
+    for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
+    {
+        /*
+         * Make sure the driver didn't set any dispatch entry point to NULL!
+         * Doing so is illegal; drivers shouldn't touch entry points they
+         * do not implement.
+         */
+
+        /* Check if it did so anyway */
+        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;
+        }
+    }
+
     /* Return the Status */
     return Status;
 }
@@ -1285,7 +1594,7 @@ VOID
 NTAPI
 IoDeleteDriver(IN PDRIVER_OBJECT DriverObject)
 {
-    /* Simply derefence the Object */
+    /* Simply dereference the Object */
     ObDereferenceObject(DriverObject);
 }
 
@@ -1463,85 +1772,56 @@ IoGetDriverObjectExtension(IN PDRIVER_OBJECT DriverObject,
     return DriverExtensions + 1;
 }
 
-/*
- * NtLoadDriver
- *
- * Loads a device driver.
- *
- * Parameters
- *    DriverServiceName
- *       Name of the service to load (registry key).
- *
- * Return Value
- *    Status
- *
- * Status
- *    implemented
- */
-NTSTATUS STDCALL
-NtLoadDriver(IN PUNICODE_STRING DriverServiceName)
+VOID NTAPI
+IopLoadUnloadDriver(PLOAD_UNLOAD_PARAMS LoadParams)
 {
    RTL_QUERY_REGISTRY_TABLE QueryTable[3];
    UNICODE_STRING ImagePath;
    UNICODE_STRING ServiceName;
-   UNICODE_STRING CapturedDriverServiceName = {0};
-   KPROCESSOR_MODE PreviousMode;
    NTSTATUS Status;
    ULONG Type;
    PDEVICE_NODE DeviceNode;
-   PLDR_DATA_TABLE_ENTRY ModuleObject;
    PDRIVER_OBJECT DriverObject;
+   PLDR_DATA_TABLE_ENTRY ModuleObject;
+   PVOID BaseAddress;
    WCHAR *cur;
 
-   PAGED_CODE();
-
-   PreviousMode = KeGetPreviousMode();
-
-   /*
-    * Check security privileges
-    */
-
-/* FIXME: Uncomment when privileges will be correctly implemented. */
-#if 0
-   if (!SeSinglePrivilegeCheck(SeLoadDriverPrivilege, PreviousMode))
+   /* Check if it's an unload request */
+   if (LoadParams->DriverObject)
    {
-      DPRINT("Privilege not held\n");
-      return STATUS_PRIVILEGE_NOT_HELD;
-   }
-#endif
+       (*LoadParams->DriverObject->DriverUnload)(LoadParams->DriverObject);
 
-   Status = ProbeAndCaptureUnicodeString(&CapturedDriverServiceName,
-                                         PreviousMode,
-                                         DriverServiceName);
-   if (!NT_SUCCESS(Status))
-   {
-      return Status;
+       /* Return success and signal the event */
+       LoadParams->Status = STATUS_SUCCESS;
+      (VOID)KeSetEvent(&LoadParams->Event, 0, FALSE);
+       return;
    }
 
-   DPRINT("NtLoadDriver('%wZ')\n", &CapturedDriverServiceName);
-
    RtlInitUnicodeString(&ImagePath, NULL);
 
    /*
     * Get the service name from the registry key name.
     */
-   ASSERT(CapturedDriverServiceName.Length >= sizeof(WCHAR));
+   ASSERT(LoadParams->ServiceName->Length >= sizeof(WCHAR));
 
-   ServiceName = CapturedDriverServiceName;
-   cur = CapturedDriverServiceName.Buffer + (CapturedDriverServiceName.Length / sizeof(WCHAR)) - 1;
-   while (CapturedDriverServiceName.Buffer != cur)
+   ServiceName = *LoadParams->ServiceName;
+   cur = LoadParams->ServiceName->Buffer +
+       (LoadParams->ServiceName->Length / sizeof(WCHAR)) - 1;
+   while (LoadParams->ServiceName->Buffer != cur)
    {
       if(*cur == L'\\')
       {
          ServiceName.Buffer = cur + 1;
-         ServiceName.Length = CapturedDriverServiceName.Length -
+         ServiceName.Length = LoadParams->ServiceName->Length -
                               (USHORT)((ULONG_PTR)ServiceName.Buffer -
-                                       (ULONG_PTR)CapturedDriverServiceName.Buffer);
+                                       (ULONG_PTR)LoadParams->ServiceName->Buffer);
          break;
       }
       cur--;
    }
 
+   IopDisplayLoadingMessage(&ServiceName);
+
    /*
     * Get service type.
     */
@@ -1559,13 +1839,16 @@ NtLoadDriver(IN PUNICODE_STRING DriverServiceName)
    QueryTable[1].EntryContext = &ImagePath;
 
    Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
-      CapturedDriverServiceName.Buffer, QueryTable, NULL, NULL);
+      LoadParams->ServiceName->Buffer, QueryTable, NULL, NULL);
 
    if (!NT_SUCCESS(Status))
    {
       DPRINT("RtlQueryRegistryValues() failed (Status %lx)\n", Status);
-      ExFreePool(ImagePath.Buffer);
-      goto ReleaseCapturedString;
+      if (ImagePath.Buffer)
+         ExFreePool(ImagePath.Buffer);
+      LoadParams->Status = Status;
+      (VOID)KeSetEvent(&LoadParams->Event, 0, FALSE);
+      return;
    }
 
    /*
@@ -1577,7 +1860,9 @@ NtLoadDriver(IN PUNICODE_STRING DriverServiceName)
    if (!NT_SUCCESS(Status))
    {
       DPRINT("IopNormalizeImagePath() failed (Status %x)\n", Status);
-      goto ReleaseCapturedString;
+      LoadParams->Status = Status;
+      (VOID)KeSetEvent(&LoadParams->Event, 0, FALSE);
+      return;
    }
 
    DPRINT("FullImagePath: '%wZ'\n", &ImagePath);
@@ -1593,7 +1878,9 @@ NtLoadDriver(IN PUNICODE_STRING DriverServiceName)
    if (!NT_SUCCESS(Status))
    {
       DPRINT("IopCreateDeviceNode() failed (Status %lx)\n", Status);
-      goto ReleaseCapturedString;
+      LoadParams->Status = Status;
+      (VOID)KeSetEvent(&LoadParams->Event, 0, FALSE);
+      return;
    }
 
    /* Get existing DriverObject pointer (in case the driver has
@@ -1610,12 +1897,14 @@ NtLoadDriver(IN PUNICODE_STRING DriverServiceName)
         * Load the driver module
         */
 
-       Status = MmLoadSystemImage(&ImagePath, NULL, NULL, 0, (PVOID)&ModuleObject, NULL);
+       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);
-           goto ReleaseCapturedString;
+           LoadParams->Status = Status;
+           (VOID)KeSetEvent(&LoadParams->Event, 0, FALSE);
+           return;
        }
 
        /*
@@ -1642,19 +1931,114 @@ NtLoadDriver(IN PUNICODE_STRING DriverServiceName)
                DPRINT("IopInitializeDriver() failed (Status %lx)\n", Status);
                MmUnloadSystemImage(ModuleObject);
                IopFreeDeviceNode(DeviceNode);
-               goto ReleaseCapturedString;
+               LoadParams->Status = Status;
+               (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);
    }
+   else
+   {
+      DPRINT("DriverObject already exist in ObjectManager\n");
 
-   IopInitializeDevice(DeviceNode, DriverObject);
-   Status = IopStartDevice(DeviceNode);
+      /* IopGetDriverObject references the DriverObject, so dereference it */
+      ObDereferenceObject(DriverObject);
 
-ReleaseCapturedString:
-   ReleaseCapturedUnicodeString(&CapturedDriverServiceName,
-                                PreviousMode);
+      /* Free device node since driver loading failed */
+      IopFreeDeviceNode(DeviceNode);
+   }
 
-   return Status;
+   /* Pass status to the caller and signal the event */
+   LoadParams->Status = Status;
+   (VOID)KeSetEvent(&LoadParams->Event, 0, FALSE);
+}
+
+/*
+ * NtLoadDriver
+ *
+ * Loads a device driver.
+ *
+ * Parameters
+ *    DriverServiceName
+ *       Name of the service to load (registry key).
+ *
+ * Return Value
+ *    Status
+ *
+ * Status
+ *    implemented
+ */
+NTSTATUS NTAPI
+NtLoadDriver(IN PUNICODE_STRING DriverServiceName)
+{
+    UNICODE_STRING CapturedDriverServiceName = { 0, 0, NULL };
+    KPROCESSOR_MODE PreviousMode;
+    LOAD_UNLOAD_PARAMS LoadParams;
+    NTSTATUS Status;
+
+    PAGED_CODE();
+
+    PreviousMode = KeGetPreviousMode();
+
+    /*
+    * Check security privileges
+    */
+
+    /* FIXME: Uncomment when privileges will be correctly implemented. */
+#if 0
+    if (!SeSinglePrivilegeCheck(SeLoadDriverPrivilege, PreviousMode))
+    {
+        DPRINT("Privilege not held\n");
+        return STATUS_PRIVILEGE_NOT_HELD;
+    }
+#endif
+
+    Status = ProbeAndCaptureUnicodeString(&CapturedDriverServiceName,
+                                          PreviousMode,
+                                          DriverServiceName);
+    if (!NT_SUCCESS(Status))
+    {
+        return Status;
+    }
+
+    DPRINT("NtLoadDriver('%wZ')\n", &CapturedDriverServiceName);
+
+    LoadParams.ServiceName = &CapturedDriverServiceName;
+    LoadParams.DriverObject = NULL;
+    KeInitializeEvent(&LoadParams.Event, NotificationEvent, FALSE);
+
+    /* Call the load/unload routine, depending on current process */
+    if (PsGetCurrentProcess() == PsInitialSystemProcess)
+    {
+        /* Just call right away */
+        IopLoadUnloadDriver(&LoadParams);
+    }
+    else
+    {
+        /* Load/Unload must be called from system process */
+        ExInitializeWorkItem(&LoadParams.WorkItem,
+                             (PWORKER_THREAD_ROUTINE)IopLoadUnloadDriver,
+                             (PVOID)&LoadParams);
+
+        /* Queue it */
+        ExQueueWorkItem(&LoadParams.WorkItem, DelayedWorkQueue);
+
+        /* And wait when it completes */
+        KeWaitForSingleObject(&LoadParams.Event, UserRequest, KernelMode,
+            FALSE, NULL);
+    }
+
+    ReleaseCapturedUnicodeString(&CapturedDriverServiceName,
+                                 PreviousMode);
+
+    return LoadParams.Status;
 }
 
 /*
@@ -1673,7 +2057,7 @@ ReleaseCapturedString:
  *    implemented
  */
 
-NTSTATUS STDCALL
+NTSTATUS NTAPI
 NtUnloadDriver(IN PUNICODE_STRING DriverServiceName)
 {
    return IopUnloadDriver(DriverServiceName, FALSE);