[NTOSKRNL]
[reactos.git] / reactos / ntoskrnl / mm / ARM3 / sysldr.c
index e226766..b77bc90 100644 (file)
@@ -99,14 +99,15 @@ MiLoadImageSection(IN OUT PVOID *SectionPtr,
     PMMPTE PointerPte, LastPte;
     PVOID DriverBase;
     MMPTE TempPte;
+    KIRQL OldIrql;
+    PFN_NUMBER PageFrameIndex;
     PAGED_CODE();
 
     /* Detect session load */
     if (SessionLoad)
     {
         /* Fail */
-        DPRINT1("Session loading not yet supported!\n");
-        ASSERT(FALSE); // while (TRUE);
+        UNIMPLEMENTED_DBGBREAK("Session loading not yet supported!\n");
         return STATUS_NOT_IMPLEMENTED;
     }
 
@@ -157,7 +158,7 @@ MiLoadImageSection(IN OUT PVOID *SectionPtr,
     }
 
     /* Reserve system PTEs needed */
-    PteCount = ROUND_TO_PAGES(Section->ImageSection->ImageSize) >> PAGE_SHIFT;
+    PteCount = ROUND_TO_PAGES(Section->ImageSection->ImageInformation.ImageFileSize) >> PAGE_SHIFT;
     PointerPte = MiReserveSystemPtes(PteCount, SystemPteSpace);
     if (!PointerPte)
     {
@@ -174,31 +175,46 @@ MiLoadImageSection(IN OUT PVOID *SectionPtr,
     *ImageBase = DriverBase;
     DPRINT1("Loading: %wZ at %p with %lx pages\n", FileName, DriverBase, PteCount);
 
-    /* Loop the new driver PTEs */
-    TempPte = ValidKernelPte;
-    while (PointerPte < LastPte)
-    {
-        /* Allocate a page */
-        MI_SET_USAGE(MI_USAGE_DRIVER_PAGE);
+    /* Lock the PFN database */
+    OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
+
+    /* Some debug stuff */
+    MI_SET_USAGE(MI_USAGE_DRIVER_PAGE);
 #if MI_TRACE_PFNS
+    if (FileName->Buffer)
+    {
         PWCHAR pos = NULL;
         ULONG len = 0;
-        if (FileName->Buffer)
-        {
-            pos = wcsrchr(FileName->Buffer, '\\');
-            len = wcslen(pos) * sizeof(WCHAR);
-            if (pos) snprintf(MI_PFN_CURRENT_PROCESS_NAME, min(16, len), "%S", pos);
-        }
+        pos = wcsrchr(FileName->Buffer, '\\');
+        len = wcslen(pos) * sizeof(WCHAR);
+        if (pos) snprintf(MI_PFN_CURRENT_PROCESS_NAME, min(16, len), "%S", pos);
+    }
 #endif
-        TempPte.u.Hard.PageFrameNumber = MiAllocatePfn(PointerPte, MM_EXECUTE);
 
-        /* Write it */
+    /* Loop the new driver PTEs */
+    TempPte = ValidKernelPte;
+    while (PointerPte < LastPte)
+    {
+        /* Make sure the PTE is not valid for whatever reason */
+        ASSERT(PointerPte->u.Hard.Valid == 0);
+
+        /* Grab a page */
+        PageFrameIndex = MiRemoveAnyPage(MI_GET_NEXT_COLOR());
+
+        /* Initialize its PFN entry */
+        MiInitializePfn(PageFrameIndex, PointerPte, TRUE);
+
+        /* Write the PTE */
+        TempPte.u.Hard.PageFrameNumber = PageFrameIndex;
         MI_WRITE_VALID_PTE(PointerPte, TempPte);
 
         /* Move on */
         PointerPte++;
     }
 
+    /* Release the PFN lock */
+    KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
+
     /* Copy the image */
     RtlCopyMemory(DriverBase, Base, PteCount << PAGE_SHIFT);
 
@@ -558,8 +574,10 @@ MiProcessLoaderEntry(IN PLDR_DATA_TABLE_ENTRY LdrEntry,
     OldIrql = KeAcquireSpinLockRaiseToSynch(&PsLoadedModuleSpinLock);
 
     /* Insert or remove from the list */
-    Insert ? InsertTailList(&PsLoadedModuleList, &LdrEntry->InLoadOrderLinks) :
-             RemoveEntryList(&LdrEntry->InLoadOrderLinks);
+    if (Insert)
+        InsertTailList(&PsLoadedModuleList, &LdrEntry->InLoadOrderLinks);
+    else
+        RemoveEntryList(&LdrEntry->InLoadOrderLinks);
 
     /* Release locks */
     KeReleaseSpinLock(&PsLoadedModuleSpinLock, OldIrql);
@@ -828,9 +846,9 @@ MiSnapThunk(IN PVOID DllBase,
                                              InLoadOrderLinks);
 
                 /* Check if it matches */
-                if (RtlPrefixString((PSTRING)&ForwarderName,
-                                    (PSTRING)&LdrEntry->BaseDllName,
-                                    TRUE))
+                if (RtlPrefixUnicodeString(&ForwarderName,
+                                           &LdrEntry->BaseDllName,
+                                           TRUE))
                 {
                     /* Get the forwarder export directory */
                     ForwardExportDirectory =
@@ -927,7 +945,7 @@ MmUnloadSystemImage(IN PVOID ImageHandle)
             /* Unload the symbols */
             DbgUnLoadImageSymbols(&TempName,
                                   BaseAddress,
-                                  (ULONG_PTR)ZwCurrentProcess());
+                                  (ULONG_PTR)PsGetCurrentProcessId());
             RtlFreeAnsiString(&TempName);
         }
     }
@@ -985,6 +1003,7 @@ MiResolveImageReferences(IN PVOID ImageBase,
                          OUT PWCHAR *MissingDriver,
                          OUT PLOAD_IMPORTS *LoadImports)
 {
+    static UNICODE_STRING DriversFolderName = RTL_CONSTANT_STRING(L"drivers\\");
     PCHAR MissingApiBuffer = *MissingApi, ImportName;
     PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor, CurrentImport;
     ULONG ImportSize, ImportCount = 0, LoadedImportsSize, ExportSize;
@@ -1003,6 +1022,9 @@ MiResolveImageReferences(IN PVOID ImageBase,
     DPRINT("%s - ImageBase: %p. ImageFileDirectory: %wZ\n",
            __FUNCTION__, ImageBase, ImageFileDirectory);
 
+    /* No name string buffer yet */
+    NameString.Buffer = NULL;
+
     /* Assume no imports */
     *LoadImports = MM_SYSLDR_NO_IMPORTS;
 
@@ -1065,9 +1087,8 @@ MiResolveImageReferences(IN PVOID ImageBase,
         if ((GdiLink) && (NormalLink))
         {
             /* It's not, it's importing stuff it shouldn't be! */
-            MiDereferenceImports(LoadedImports);
-            if (LoadedImports) ExFreePoolWithTag(LoadedImports, TAG_LDR_IMPORTS);
-            return STATUS_PROCEDURE_NOT_FOUND;
+            Status = STATUS_PROCEDURE_NOT_FOUND;
+            goto Failure;
         }
 
         /* Check for user-mode printer or video card drivers, which don't belong */
@@ -1079,9 +1100,8 @@ MiResolveImageReferences(IN PVOID ImageBase,
             !(_strnicmp(ImportName, "gdi32", sizeof("gdi32") - 1)))
         {
             /* This is not kernel code */
-            MiDereferenceImports(LoadedImports);
-            if (LoadedImports) ExFreePoolWithTag(LoadedImports, TAG_LDR_IMPORTS);
-            return STATUS_PROCEDURE_NOT_FOUND;
+            Status = STATUS_PROCEDURE_NOT_FOUND;
+            goto Failure;
         }
 
         /* Check if this is a "core" import, which doesn't get referenced */
@@ -1104,9 +1124,7 @@ MiResolveImageReferences(IN PVOID ImageBase,
         if (!NT_SUCCESS(Status))
         {
             /* Failed */
-            MiDereferenceImports(LoadedImports);
-            if (LoadedImports) ExFreePoolWithTag(LoadedImports, TAG_LDR_IMPORTS);
-            return Status;
+            goto Failure;
         }
 
         /* We don't support name prefixes yet */
@@ -1161,76 +1179,97 @@ CheckDllState:
             DllName.Buffer = ExAllocatePoolWithTag(NonPagedPool,
                                                    DllName.MaximumLength,
                                                    TAG_LDR_WSTR);
-            if (DllName.Buffer)
-            {
-                /* Setup the base length and copy it */
-                DllName.Length = ImageFileDirectory->Length;
-                RtlCopyMemory(DllName.Buffer,
-                              ImageFileDirectory->Buffer,
-                              ImageFileDirectory->Length);
-
-                /* Now add the import name and null-terminate it */
-                RtlAppendUnicodeStringToString(&DllName,
-                                               &NameString);
-                DllName.Buffer[DllName.Length / sizeof(WCHAR)] = UNICODE_NULL;
-
-                /* Load the image */
-                Status = MmLoadSystemImage(&DllName,
-                                           NamePrefix,
-                                           NULL,
-                                           FALSE,
-                                           (PVOID)&DllEntry,
-                                           &DllBase);
-                if (NT_SUCCESS(Status))
-                {
-                    /* We can free the DLL Name */
-                    ExFreePoolWithTag(DllName.Buffer, TAG_LDR_WSTR);
-                }
-                else
-                {
-                    /* Fill out the information for the error */
-                    *MissingDriver = DllName.Buffer;
-                    *(PULONG)MissingDriver |= 1;
-                    *MissingApi = NULL;
-
-                    DPRINT1("Failed to load dependency: %wZ\n", &DllName);
-                }
-            }
-            else
+            if (!DllName.Buffer)
             {
                 /* We're out of resources */
                 Status = STATUS_INSUFFICIENT_RESOURCES;
+                goto Failure;
             }
 
-            /* Check if we're OK until now */
-            if (NT_SUCCESS(Status))
+            /* Add the import name to the base directory */
+            RtlCopyUnicodeString(&DllName, ImageFileDirectory);
+            RtlAppendUnicodeStringToString(&DllName,
+                                           &NameString);
+
+            /* Load the image */
+            Status = MmLoadSystemImage(&DllName,
+                                       NamePrefix,
+                                       NULL,
+                                       FALSE,
+                                       (PVOID *)&DllEntry,
+                                       &DllBase);
+
+            /* win32k / GDI drivers can also import from system32 folder */
+            if ((Status == STATUS_OBJECT_NAME_NOT_FOUND) &&
+                (MI_IS_SESSION_ADDRESS(ImageBase) || 1)) // HACK
             {
-                /* We're now loaded */
-                Loaded = TRUE;
+                /* Free the old name buffer */
+                ExFreePoolWithTag(DllName.Buffer, TAG_LDR_WSTR);
 
-                /* Sanity check */
-                ASSERT(DllBase == DllEntry->DllBase);
+                /* Calculate size for a string the adds 'drivers\' */
+                DllName.MaximumLength += DriversFolderName.Length;
 
-                /* Call the initialization routines */
-                Status = MmCallDllInitialize(DllEntry, &PsLoadedModuleList);
-                if (!NT_SUCCESS(Status))
+                /* Allocate the new buffer */
+                DllName.Buffer = ExAllocatePoolWithTag(NonPagedPool,
+                                                       DllName.MaximumLength,
+                                                       TAG_LDR_WSTR);
+                if (!DllName.Buffer)
                 {
-                    /* We failed, unload the image */
-                    MmUnloadSystemImage(DllEntry);
-                    DPRINT1("MmCallDllInitialize failed with status 0x%x\n", Status);
-                    ASSERT(FALSE); // while (TRUE);
-                    Loaded = FALSE;
+                    /* We're out of resources */
+                    Status = STATUS_INSUFFICIENT_RESOURCES;
+                    goto Failure;
                 }
+
+                /* Copy image directory and append 'drivers\' folder name */
+                RtlCopyUnicodeString(&DllName, ImageFileDirectory);
+                RtlAppendUnicodeStringToString(&DllName, &DriversFolderName);
+
+                /* Now add the import name */
+                RtlAppendUnicodeStringToString(&DllName, &NameString);
+
+                /* Try once again to load the image */
+                Status = MmLoadSystemImage(&DllName,
+                                           NamePrefix,
+                                           NULL,
+                                           FALSE,
+                                           (PVOID *)&DllEntry,
+                                           &DllBase);
             }
 
-            /* Check if we failed by here */
             if (!NT_SUCCESS(Status))
             {
+                /* Fill out the information for the error */
+                *MissingDriver = DllName.Buffer;
+                *(PULONG)MissingDriver |= 1;
+                *MissingApi = NULL;
+
+                DPRINT1("Failed to load dependency: %wZ\n", &DllName);
+
+                /* Don't free the name */
+                DllName.Buffer = NULL;
+
                 /* Cleanup and return */
-                RtlFreeUnicodeString(&NameString);
-                MiDereferenceImports(LoadedImports);
-                if (LoadedImports) ExFreePoolWithTag(LoadedImports, TAG_LDR_IMPORTS);
-                return Status;
+                goto Failure;
+            }
+
+            /* We can free the DLL Name */
+            ExFreePoolWithTag(DllName.Buffer, TAG_LDR_WSTR);
+            DllName.Buffer = NULL;
+
+            /* We're now loaded */
+            Loaded = TRUE;
+
+            /* Sanity check */
+            ASSERT(DllBase == DllEntry->DllBase);
+
+            /* Call the initialization routines */
+            Status = MmCallDllInitialize(DllEntry, &PsLoadedModuleList);
+            if (!NT_SUCCESS(Status))
+            {
+                /* We failed, unload the image */
+                MmUnloadSystemImage(DllEntry);
+                ERROR_DBGBREAK("MmCallDllInitialize failed with status 0x%x\n", Status);
+                Loaded = FALSE;
             }
 
             /* Loop again to make sure that everything is OK */
@@ -1261,10 +1300,9 @@ CheckDllState:
         if (!ExportDirectory)
         {
             /* Cleanup and return */
-            MiDereferenceImports(LoadedImports);
-            if (LoadedImports) ExFreePoolWithTag(LoadedImports, TAG_LDR_IMPORTS);
             DPRINT1("Warning: Driver failed to load, %S not found\n", *MissingDriver);
-            return STATUS_DRIVER_ENTRYPOINT_NOT_FOUND;
+            Status = STATUS_DRIVER_ENTRYPOINT_NOT_FOUND;
+            goto Failure;
         }
 
         /* Make sure we have an IAT */
@@ -1291,9 +1329,7 @@ CheckDllState:
                 if (!NT_SUCCESS(Status))
                 {
                     /* Cleanup and return */
-                    MiDereferenceImports(LoadedImports);
-                    if (LoadedImports) ExFreePoolWithTag(LoadedImports, TAG_LDR_IMPORTS);
-                    return Status;
+                    goto Failure;
                 }
 
                 /* Reset the buffer */
@@ -1370,6 +1406,19 @@ CheckDllState:
 
     /* Return success */
     return STATUS_SUCCESS;
+
+Failure:
+
+    /* Cleanup and return */
+    RtlFreeUnicodeString(&NameString);
+
+    if (LoadedImports)
+    {
+        MiDereferenceImports(LoadedImports);
+        ExFreePoolWithTag(LoadedImports, TAG_LDR_IMPORTS);
+    }
+
+    return Status;
 }
 
 VOID
@@ -1425,6 +1474,15 @@ MiFindInitializationCode(OUT PVOID *StartVa,
         LdrEntry = CONTAINING_RECORD(NextEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
         DllBase = (ULONG_PTR)LdrEntry->DllBase;
 
+        /* Only process boot loaded images. Other drivers are processed by
+           MmFreeDriverInitialization */
+        if (LdrEntry->Flags & LDRP_MM_LOADED)
+        {
+            /* Keep going */
+            NextEntry = NextEntry->Flink;
+            continue;
+        }
+
         /* Get the NT header */
         NtHeader = RtlImageNtHeader((PVOID)DllBase);
         if (!NtHeader)
@@ -1561,7 +1619,6 @@ MmFreeDriverInitialization(IN PLDR_DATA_TABLE_ENTRY LdrEntry)
     ULONG i;
     PIMAGE_NT_HEADERS NtHeader;
     PIMAGE_SECTION_HEADER Section, DiscardSection;
-    ULONG PagesDeleted;
 
     /* Get the base address and the page count */
     DllBase = LdrEntry->DllBase;
@@ -1606,7 +1663,7 @@ MmFreeDriverInitialization(IN PLDR_DATA_TABLE_ENTRY LdrEntry)
     if (!PageCount) return;
 
     /* Delete this many PTEs */
-    PagesDeleted = MiDeleteSystemPageableVm(StartPte, PageCount, 0, NULL);
+    MiDeleteSystemPageableVm(StartPte, PageCount, 0, NULL);
 }
 
 VOID
@@ -1720,8 +1777,7 @@ MiReloadBootLoadedDrivers(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
         if (!PointerPte)
         {
             /* Shouldn't happen */
-            DPRINT1("[Mm0]: Couldn't allocate driver section!\n");
-            ASSERT(FALSE); // while (TRUE);
+            ERROR_FATAL("[Mm0]: Couldn't allocate driver section!\n");
             return;
         }
 
@@ -1774,8 +1830,7 @@ MiReloadBootLoadedDrivers(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
             if (!NT_SUCCESS(Status))
             {
                 /* This shouldn't happen */
-                DPRINT1("Relocations failed!\n");
-                ASSERT(FALSE); // while (TRUE);
+                ERROR_FATAL("Relocations failed!\n");
                 return;
             }
         }
@@ -1858,8 +1913,8 @@ MiBuildImportsForBootDrivers(VOID)
         }
         else
         {
-            /* No referencing needed */
-            LdrEntry->LoadCount = 0;
+            /* Add a reference for all other modules as well */
+            LdrEntry->LoadCount = 1;
         }
 
         /* Remember this came from the loader */
@@ -1973,9 +2028,8 @@ MiBuildImportsForBootDrivers(VOID)
                 if (*ImageThunk)
                 {
                     /* Should not be happening */
-                    DPRINT1("Broken IAT entry for %p at %p (%lx)\n",
-                            LdrEntry, ImageThunk, *ImageThunk);
-                    ASSERT(FALSE);
+                    ERROR_FATAL("Broken IAT entry for %p at %p (%lx)\n",
+                                LdrEntry, ImageThunk, *ImageThunk);
                 }
 
                 /* Reset if we hit this */
@@ -2363,8 +2417,7 @@ MiWriteProtectSystemImage(IN PVOID ImageBase)
     else
     {
         /* Not supported */
-        DPRINT1("Session drivers not supported\n");
-        ASSERT(FALSE);
+        UNIMPLEMENTED_DBGBREAK("Session drivers not supported\n");
     }
 
     /* These are the only protection masks we care about */
@@ -2535,6 +2588,10 @@ MiSetPagingOfDriver(IN PMMPTE PointerPte,
     PMMPFN Pfn1;
     PAGED_CODE();
 
+    /* The page fault handler is broken and doesn't page back in! */
+    DPRINT1("WARNING: MiSetPagingOfDriver() called, but paging is broken! ignoring!\n");
+    return;
+
     /* Get the driver's base address */
     ImageBase = MiPteToAddress(PointerPte);
     ASSERT(MI_IS_SESSION_IMAGE_ADDRESS(ImageBase) == FALSE);
@@ -2924,8 +2981,7 @@ LoaderScan:
         else
         {
             /* We don't support session loading yet */
-            DPRINT1("Unsupported Session-Load!\n");
-            ASSERT(FALSE); // while (TRUE);
+            UNIMPLEMENTED_DBGBREAK("Unsupported Session-Load!\n");
             Status = STATUS_NOT_IMPLEMENTED;
         }
 
@@ -3026,8 +3082,7 @@ LoaderScan:
         if (Flags)
         {
             /* We don't support session loading yet */
-            DPRINT1("Unsupported Session-Load!\n");
-            ASSERT(FALSE); // while (TRUE);
+            UNIMPLEMENTED_DBGBREAK("Unsupported Session-Load!\n");
             goto Quickie;
         }
 
@@ -3049,7 +3104,7 @@ LoaderScan:
     ASSERT(Status != STATUS_ALREADY_COMMITTED);
 
     /* Get the size of the driver */
-    DriverSize = ((PROS_SECTION_OBJECT)Section)->ImageSection->ImageSize;
+    DriverSize = ((PROS_SECTION_OBJECT)Section)->ImageSection->ImageInformation.ImageFileSize;
 
     /* Make sure we're not being loaded into session space */
     if (!Flags)
@@ -3168,6 +3223,7 @@ LoaderScan:
 
     /* Resolve imports */
     MissingApiName = Buffer;
+    MissingDriverName = NULL;
     Status = MiResolveImageReferences(ModuleLoadBase,
                                       &BaseDirectory,
                                       NULL,
@@ -3176,7 +3232,23 @@ LoaderScan:
                                       &LoadedImports);
     if (!NT_SUCCESS(Status))
     {
+        BOOLEAN NeedToFreeString = FALSE;
+
+        /* If the lowest bit is set to 1, this is a hint that we need to free */
+        if (*(ULONG_PTR*)&MissingDriverName & 1)
+        {
+            NeedToFreeString = TRUE;
+            *(ULONG_PTR*)&MissingDriverName &= ~1;
+        }
+
         DPRINT1("MiResolveImageReferences failed with status 0x%x\n", Status);
+        DPRINT1(" Missing driver '%ls', missing API '%s'\n",
+                MissingDriverName, MissingApiName);
+
+        if (NeedToFreeString)
+        {
+            ExFreePoolWithTag(MissingDriverName, TAG_LDR_WSTR);
+        }
 
         /* Fail */
         MiProcessLoaderEntry(LdrEntry, FALSE);
@@ -3254,7 +3326,7 @@ LoaderScan:
         /* Notify the debugger */
         DbgLoadImageSymbols(&AnsiTemp,
                             LdrEntry->DllBase,
-                            (ULONG_PTR)ZwCurrentProcess());
+                            (ULONG_PTR)PsGetCurrentProcessId());
         LdrEntry->Flags |= LDRP_DEBUG_SYMBOLS_LOADED;
     }