[NTOS]: Implement and call MiBuildImportsForBootDrivers. We now have full dependency...
[reactos.git] / reactos / ntoskrnl / mm / sysldr.c
index 27dcee3..1fb86f9 100644 (file)
@@ -47,6 +47,10 @@ PVOID MmLastUnloadedDrivers;
 BOOLEAN MmMakeLowMemory;
 BOOLEAN MmEnforceWriteProtection = TRUE;
 
+PMMPTE MiKernelResourceStartPte, MiKernelResourceEndPte;
+ULONG_PTR ExPoolCodeStart, ExPoolCodeEnd, MmPoolCodeStart, MmPoolCodeEnd;
+ULONG_PTR MmPteCodeStart, MmPteCodeEnd;
+
 /* FUNCTIONS ******************************************************************/
 
 PVOID
@@ -1508,6 +1512,331 @@ MiReloadBootLoadedDrivers(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
     }
 }
 
+NTSTATUS
+NTAPI
+MiBuildImportsForBootDrivers(VOID)
+{
+    PLIST_ENTRY NextEntry, NextEntry2;
+    PLDR_DATA_TABLE_ENTRY LdrEntry, KernelEntry, HalEntry, LdrEntry2, LastEntry;
+    PLDR_DATA_TABLE_ENTRY* EntryArray;
+    UNICODE_STRING KernelName = RTL_CONSTANT_STRING(L"ntoskrnl.exe");
+    UNICODE_STRING HalName = RTL_CONSTANT_STRING(L"hal.dll");
+    PLOAD_IMPORTS LoadedImports;
+    ULONG LoadedImportsSize, ImportSize;
+    PULONG_PTR ImageThunk;
+    ULONG_PTR DllBase, DllEnd;
+    ULONG Modules = 0, i, j = 0;
+    PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor;
+    
+    /* Initialize variables */
+    KernelEntry = HalEntry = LastEntry = NULL;
+
+    /* Loop the loaded module list... we are early enough that no lock is needed */
+    NextEntry = PsLoadedModuleList.Flink;
+    while (NextEntry != &PsLoadedModuleList)
+    {
+        /* Get the entry */
+        LdrEntry = CONTAINING_RECORD(NextEntry,
+                                     LDR_DATA_TABLE_ENTRY,
+                                     InLoadOrderLinks);
+
+        /* Check if it's the kernel or HAL */
+        if (RtlEqualUnicodeString(&KernelName, &LdrEntry->BaseDllName, TRUE))
+        {
+            /* Found it */
+            KernelEntry = LdrEntry;
+        }
+        else if (RtlEqualUnicodeString(&HalName, &LdrEntry->BaseDllName, TRUE))
+        {
+            /* Found it */
+            HalEntry = LdrEntry;
+        }
+        
+        /* Check if this is a driver DLL */
+        if (LdrEntry->Flags & LDRP_DRIVER_DEPENDENT_DLL)
+        {
+            /* Check if this is the HAL or kernel */
+            if ((LdrEntry == HalEntry) || (LdrEntry == KernelEntry))
+            {
+                /* Add a reference */
+                LdrEntry->LoadCount = 1;
+            }
+            else
+            {
+                /* No referencing needed */
+                LdrEntry->LoadCount = 0;
+            }
+        }
+        else
+        {
+            /* No referencing needed */
+            LdrEntry->LoadCount = 0;    
+        }
+        
+        /* Remember this came from the loader */
+        LdrEntry->LoadedImports = MM_SYSLDR_BOOT_LOADED;
+
+        /* Keep looping */
+        NextEntry = NextEntry->Flink;
+        Modules++;
+    }
+    
+    /* We must have at least found the kernel and HAL */
+    if (!(HalEntry) || (!KernelEntry)) return STATUS_NOT_FOUND;
+    
+    /* Allocate the list */
+    EntryArray = ExAllocatePoolWithTag(PagedPool, Modules * sizeof(PVOID), 'TDmM');
+    if (!EntryArray) return STATUS_INSUFFICIENT_RESOURCES;
+
+    /* Loop the loaded module list again */
+    NextEntry = PsLoadedModuleList.Flink;
+    while (NextEntry != &PsLoadedModuleList)
+    {
+        /* Get the entry */
+        LdrEntry = CONTAINING_RECORD(NextEntry,
+                                     LDR_DATA_TABLE_ENTRY,
+                                     InLoadOrderLinks);
+#ifdef _WORKING_LOADER_
+        /* Get its imports */
+        ImageThunk = RtlImageDirectoryEntryToData(LdrEntry->DllBase,
+                                                  TRUE,
+                                                  IMAGE_DIRECTORY_ENTRY_IAT,
+                                                  &ImportSize);
+        if (!ImageThunk)                                                
+#else
+        /* Get its imports */
+        ImportDescriptor = RtlImageDirectoryEntryToData(LdrEntry->DllBase,
+                                                        TRUE,
+                                                        IMAGE_DIRECTORY_ENTRY_IMPORT,
+                                                        &ImportSize);
+        if (!ImportDescriptor)
+#endif
+        {
+            /* None present */
+            LdrEntry->LoadedImports = MM_SYSLDR_NO_IMPORTS;
+            NextEntry = NextEntry->Flink;
+            continue;
+        }
+        
+        /* Clear the list and count the number of IAT thunks */
+        RtlZeroMemory(EntryArray, Modules * sizeof(PVOID));
+#ifdef _WORKING_LOADER_
+        ImportSize /= sizeof(ULONG_PTR);
+        
+        /* Scan the thunks */
+        for (i = 0, DllBase = 0, DllEnd = 0; i < ImportSize; i++, ImageThunk++)
+#else
+        i = DllBase = DllEnd = 0;
+        while ((ImportDescriptor->Name) &&
+               (ImportDescriptor->OriginalFirstThunk))
+        {
+            /* Get the image thunk */
+            ImageThunk = (PVOID)((ULONG_PTR)LdrEntry->DllBase +
+                                 ImportDescriptor->FirstThunk);
+            while (*ImageThunk)
+#endif
+            {
+            /* Do we already have an address? */
+            if (DllBase)
+            {
+                /* Is the thunk in the same address? */
+                if ((*ImageThunk >= DllBase) && (*ImageThunk < DllEnd))
+                {
+                    /* Skip it, we already have a reference for it */
+                    ASSERT(EntryArray[j]);
+                    ImageThunk++;
+                    continue;
+                }
+            }
+            
+            /* Loop the loaded module list to locate this address owner */
+            j = 0;
+            NextEntry2 = PsLoadedModuleList.Flink;
+            while (NextEntry2 != &PsLoadedModuleList)
+            {
+                /* Get the entry */
+                LdrEntry2 = CONTAINING_RECORD(NextEntry2,
+                                              LDR_DATA_TABLE_ENTRY,
+                                              InLoadOrderLinks);
+                                              
+                /* Get the address range for this module */
+                DllBase = (ULONG_PTR)LdrEntry2->DllBase;
+                DllEnd = DllBase + LdrEntry2->SizeOfImage;
+                
+                /* Check if this IAT entry matches it */
+                if ((*ImageThunk >= DllBase) && (*ImageThunk < DllEnd))
+                {
+                    /* Save it */
+                    //DPRINT1("Found imported dll: %wZ\n", &LdrEntry2->BaseDllName);
+                    EntryArray[j] = LdrEntry2;
+                    break;
+                }
+                
+                /* Keep searching */
+                NextEntry2 = NextEntry2->Flink;
+                j++;
+            }
+            
+            /* Do we have a thunk outside the range? */
+            if ((*ImageThunk < DllBase) || (*ImageThunk >= DllEnd))
+            {
+                /* Could be 0... */
+                if (*ImageThunk)
+                {
+                    /* Should not be happening */
+                    DPRINT1("Broken IAT entry for %p at %p (%lx)\n",
+                            LdrEntry, ImageThunk, *ImageThunk);
+                    ASSERT(FALSE);
+                }
+                
+                /* Reset if we hit this */
+                DllBase = 0;
+            }
+#ifndef _WORKING_LOADER_
+            ImageThunk++;
+            }
+        
+            i++;
+            ImportDescriptor++;
+#endif
+        }
+        
+        /* Now scan how many imports we really have */
+        for (i = 0, ImportSize = 0; i < Modules; i++)
+        {
+            /* Skip HAL and kernel */
+            if ((EntryArray[i]) &&
+                (EntryArray[i] != HalEntry) &&
+                (EntryArray[i] != KernelEntry))
+            {
+                /* A valid reference */
+                LastEntry = EntryArray[i];
+                ImportSize++;
+            }
+        }
+        
+        /* Do we have any imports after all? */
+        if (!ImportSize)
+        {
+            /* No */
+            LdrEntry->LoadedImports = MM_SYSLDR_NO_IMPORTS;
+        }
+        else if (ImportSize == 1)
+        {
+            /* A single entry import */
+            LdrEntry->LoadedImports = (PVOID)((ULONG_PTR)LastEntry | MM_SYSLDR_SINGLE_ENTRY);
+            LastEntry->LoadCount++;
+        }
+        else
+        {
+            /* We need an import table */
+            LoadedImportsSize = ImportSize * sizeof(PVOID) + sizeof(SIZE_T);
+            LoadedImports = ExAllocatePoolWithTag(PagedPool,
+                                                  LoadedImportsSize,
+                                                  'TDmM');
+            ASSERT(LoadedImports);
+            
+            /* Save the count */
+            LoadedImports->Count = ImportSize;
+            
+            /* Now copy all imports */
+            for (i = 0, j = 0; i < Modules; i++)
+            {
+                /* Skip HAL and kernel */
+                if ((EntryArray[i]) &&
+                    (EntryArray[i] != HalEntry) &&
+                    (EntryArray[i] != KernelEntry))
+                {
+                    /* A valid reference */
+                    //DPRINT1("Found valid entry: %p\n", EntryArray[i]);
+                    LoadedImports->Entry[j] = EntryArray[i];
+                    EntryArray[i]->LoadCount++;
+                    j++;
+                }
+            }
+            
+            /* Should had as many entries as we expected */
+            ASSERT(j == ImportSize);
+            LdrEntry->LoadedImports = LoadedImports;
+        }
+        
+        /* Next */
+        NextEntry = NextEntry->Flink;
+    }
+    
+    /* Free the initial array */
+    ExFreePool(EntryArray);
+    
+    /* FIXME: Might not need to keep the HAL/Kernel imports around */
+    
+    /* Kernel and HAL are loaded at boot */
+    KernelEntry->LoadedImports = MM_SYSLDR_BOOT_LOADED;
+    HalEntry->LoadedImports = MM_SYSLDR_BOOT_LOADED;
+    
+    /* All worked well */
+    return STATUS_SUCCESS;
+}
+
+VOID
+NTAPI
+MiLocateKernelSections(IN PLDR_DATA_TABLE_ENTRY LdrEntry)
+{
+    ULONG_PTR DllBase;
+    PIMAGE_NT_HEADERS NtHeaders;
+    PIMAGE_SECTION_HEADER SectionHeader;
+    ULONG Sections, Size;
+    
+    /* Get the kernel section header */
+    DllBase = (ULONG_PTR)LdrEntry->DllBase;
+    NtHeaders = RtlImageNtHeader((PVOID)DllBase);
+    SectionHeader = IMAGE_FIRST_SECTION(NtHeaders);
+
+    /* Loop all the sections */
+    Sections = NtHeaders->FileHeader.NumberOfSections;
+    while (Sections)
+    {
+        /* Grab the size of the section */
+        Size = max(SectionHeader->SizeOfRawData, SectionHeader->Misc.VirtualSize);
+        
+        /* Check for .RSRC section */
+        if (*(PULONG)SectionHeader->Name == 'rsr.')
+        {
+            /* Remember the PTEs so we can modify them later */
+            MiKernelResourceStartPte = MiAddressToPte(DllBase +
+                                                      SectionHeader->VirtualAddress);
+            MiKernelResourceEndPte = MiKernelResourceStartPte +
+                                     BYTES_TO_PAGES(SectionHeader->VirtualAddress + Size);
+        }
+        else if (*(PULONG)SectionHeader->Name == 'LOOP')
+        {
+            /* POOLCODE vs. POOLMI */
+            if (*(PULONG)&SectionHeader->Name[4] == 'EDOC')
+            {
+                /* Found Ex* Pool code */
+                ExPoolCodeStart = DllBase + SectionHeader->VirtualAddress;
+                ExPoolCodeEnd = ExPoolCodeStart + Size;
+            }
+            else if (*(PUSHORT)&SectionHeader->Name[4] == 'MI')
+            {
+                /* Found Mm* Pool code */
+                MmPoolCodeStart = DllBase + SectionHeader->VirtualAddress;
+                MmPoolCodeEnd = ExPoolCodeStart + Size;                
+            }
+        }
+        else if ((*(PULONG)SectionHeader->Name == 'YSIM') &&
+                 (*(PULONG)&SectionHeader->Name[4] == 'ETPS'))
+        {
+            /* Found MISYSPTE (Mm System PTE code)*/
+            MmPteCodeStart = DllBase + SectionHeader->VirtualAddress;
+            MmPteCodeEnd = ExPoolCodeStart + Size;
+        }
+        
+        /* Keep going */
+        Sections--;
+        SectionHeader++;
+    }
+}
+
 BOOLEAN
 NTAPI
 MiInitializeLoadedModuleList(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
@@ -1528,6 +1857,9 @@ MiInitializeLoadedModuleList(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
                                  LDR_DATA_TABLE_ENTRY,
                                  InLoadOrderLinks);
     PsNtosImageBase = (ULONG_PTR)LdrEntry->DllBase;
+    
+    /* Locate resource section, pool code, and system pte code */
+    MiLocateKernelSections(LdrEntry);
 
     /* Loop the loader block */
     while (NextEntry != ListHead)
@@ -1541,7 +1873,7 @@ MiInitializeLoadedModuleList(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
         if (!RtlImageNtHeader(LdrEntry->DllBase))
         {
             /* Skip this entry */
-            NextEntry= NextEntry->Flink;
+            NextEntry = NextEntry->Flink;
             continue;
         }
 
@@ -1584,7 +1916,7 @@ MiInitializeLoadedModuleList(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
     }
 
     /* Build the import lists for the boot drivers */
-    //MiBuildImportsForBootDrivers();
+    MiBuildImportsForBootDrivers();
 
     /* We're done */
     return TRUE;