- Fix KiDispatchException to unmask KI_EXCEPTION_INTERNAL when setting the exception...
authorAlex Ionescu <aionescu@gmail.com>
Thu, 1 Mar 2007 19:51:20 +0000 (19:51 +0000)
committerAlex Ionescu <aionescu@gmail.com>
Thu, 1 Mar 2007 19:51:20 +0000 (19:51 +0000)
- Fixes and compatible merges from KD Branch:
 - Add stubs for KdSave, KdRestore, KdDebuggerInitialize0, KdSendPacket, KdReceivePacket to kdcom.dll
 - Implement and export KeTryToAcquireSpinLockAtDpcLevel.
 - Add EXCEPTION_RECORD64 and LIST_ENTRY64, KeTryToAcquireSpinLockAtDpcLevel, BREAKPOINT_COMMAND_STRING, Ke386SetCr2, Ke386SetDr3, Ke386SetDr6.
 - Remove non-kernel routines from kdfuncs.h and remove deprecated routines from ke.h.
 - Implement KiRestoreProcessorControlState, KeFreezeExecution, KeThawExecution, ExAcquireTimeRefreshLock, ExReleaseTimeRefreshLock.
 - Rename ModuleLoadList to PsLoadedModuleList. Add PsNtosImageBase and set value in it.
 - Add skeleton wdbgexts.h with what's needed until now, this is a PSDK header.
 - Add kddll.h for KDCOM/1394/USB2.DLL prototypes.
 - Add windbgkd.h with KD protocol definitions. Used to be an NT5 DDK header, but was removed, so this goes into include\reactos.
 - Fix KiDebugService to load EDX from KTRAP_FRAME_EDX, not KTRAP_FRAME_EAX!.
 - Fix CommonDispatchException to check for the argument count in ECX, not EAX. Previously we were ignoring parameter counts and never filling out exception records!
 - Add KdDebuggerInitialize1 and enable call to it.
 - Fix KD_SYMBOLS_INFO definition and DbgLoadImageSymbols prototype.
 - Implement DbgUnLoadImageSymbols.
 - Fix some small bugs in KeBugCheckWithTf and add various debugger calls/checks where needed.
 - Fix bugcheck recursion code which was incorrect.
 - Only save/restore CR4 if KeFeatureBits indicates CR4 support exists.
 - Export KdDebuggerNotPresent since KDCOM needs it.
 - Add KCONTINUE_STATUS.
 - Add DBGKD_ANY_CONTROL_SET and X86/IA64/AMD64 control sets.
 - Add DBGKD_MANIPULATE_STATE64 and all sub-structures (READ_MEMORY, WRITE_MEMORY, etc).
 - Create GCC_ULONG64 type to hack around a bug in GCC which is incapable of creating entries for externals at compile-time for 64-bit pointers.
 - Rename NameSpaceRoot to ObpRootDirectoryObject, IopLogListHead to IopErrorLogListHead, BugcheckCallbackListHead to KeBugcheckCallbackListHead, BugcheckReasonCallbackListHead to KeBugcheckReasonCallbackListHead, ObTypeObjectType to ObpTypeObjectType.
 - Create ntverp.h and common.ver files. These are the standard files used by the NT/DDK build systems and we should try to support them as well instead of re-defining everything our own way (especially if we want to build ddk-compatible drivers later on).
 - Made init.c use version data from ntverp.h instead of hard-coding.
 - Defined NT 5.2.3790.1830 as the version we report.
 - Fixed up .rc file to be correct and match DDK-sytnax/style.
 - For now only the kernel uses this new versionning scheme, but we should change the build system later to use this for every component.
 - Fix KiSaveProcessorControlState and KiRestoreProcessorControlSate. The latter doesn't freeze the CPU anymore so it's enabled, and the former doesn't cause WinDBG to panic anymore and display weird data.
 - KPROCESSOR_STATE is not 4-byte aligned.
 - Use DR_MASK and DR7_OVERRIDE_V in KiUpdateDr7, KiRecordDr7 instead of DR_ACTIVE_MASK.
 - Add ExceptionRecord32To64.
 - Fix generation of driver name for symbol load.

svn path=/trunk/; revision=25937

18 files changed:
1  2 
reactos/include/ddk/ntifs.h
reactos/include/ddk/winddk.h
reactos/include/ndk/ketypes.h
reactos/lib/rtl/debug.c
reactos/lib/rtl/i386/debug_asm.S
reactos/ntoskrnl/ex/init.c
reactos/ntoskrnl/include/internal/ex.h
reactos/ntoskrnl/include/internal/ke.h
reactos/ntoskrnl/include/ntoskrnl.h
reactos/ntoskrnl/io/iomgr/iomgr.c
reactos/ntoskrnl/kd/kdmain.c
reactos/ntoskrnl/ke/bug.c
reactos/ntoskrnl/ke/except.c
reactos/ntoskrnl/ke/i386/exp.c
reactos/ntoskrnl/ke/i386/kiinit.c
reactos/ntoskrnl/ke/i386/trap.s
reactos/ntoskrnl/mm/sysldr.c
reactos/ntoskrnl/rtl/misc.c

Simple merge
Simple merge
@@@ -97,6 -97,6 +97,12 @@@ Author
  #define KF_NX_DISABLED                  0x40000000
  #define KF_NX_ENABLED                   0x80000000
  
++//
++// Internal Exception Codes
++//
++#define KI_EXCEPTION_INTERNAL           0x10000000
++#define KI_EXCEPTION_ACCESS_VIOLATION   (KI_EXCEPTION_INTERNAL | 0x04)
++
  //
  // KPCR Access for non-IA64 builds
  //
@@@ -328,7 -322,7 +328,7 @@@ DbgLoadImageSymbols(IN PANSI_STRING Nam
  
      /* Setup the symbol data */
      SymbolInfo.BaseOfDll = Base;
-     SymbolInfo.ProcessId = UlongToPtr(ProcessId);
 -    SymbolInfo.ProcessId = ProcessId;
++    SymbolInfo.ProcessId = (ULONG)ProcessId;
  
      /* Get NT Headers */
      NtHeader = NULL; //RtlImageNtHeader(Base);
@@@ -362,7 -356,7 +362,7 @@@ DbgUnLoadImageSymbols(IN PANSI_STRING N
  
      /* Setup the symbol data */
      SymbolInfo.BaseOfDll = Base;
-     SymbolInfo.ProcessId = (PVOID)ProcessId;
 -    SymbolInfo.ProcessId = ProcessId;
++    SymbolInfo.ProcessId = (ULONG)ProcessId;
      SymbolInfo.CheckSum = SymbolInfo.SizeOfImage = 0;
  
      /* Load the symbols */
Simple merge
Simple merge
@@@ -17,10 -17,13 +17,14 @@@ extern FAST_MUTEX ExpEnvironmentLock
  extern ERESOURCE ExpFirmwareTableResource;
  extern LIST_ENTRY ExpFirmwareTableProviderListHead;
  extern BOOLEAN ExpIsWinPEMode;
 -extern ULONG NtGlobalFlag;
+ extern LIST_ENTRY ExpSystemResourcesList;
  ULONG ExpAnsiCodePageDataOffset, ExpOemCodePageDataOffset;
  ULONG ExpUnicodeCaseTableDataOffset;
  PVOID ExpNlsSectionPointer;
+ extern CHAR NtBuildLab[];
+ extern ULONG CmNtCSDVersion;
++extern ULONG NtGlobalFlag;
 +extern ULONG ExpInitializationPhase;
  
  typedef struct _EXHANDLE
  {
@@@ -154,6 -149,9 +149,8 @@@ extern PVOID KeUserExceptionDispatcher
  extern PVOID KeRaiseUserExceptionDispatcher;
  extern UCHAR KiDebugRegisterTrapOffsets[9];
  extern UCHAR KiDebugRegisterContextOffsets[9];
 -extern ULONG KiFreezeFlag;
+ extern ULONG KeTimeIncrement;
+ extern ULONG_PTR KiBugCheckData[5];
  
  /* MACROS *************************************************************************/
  
@@@ -8,12 -8,14 +8,16 @@@
  
  /* INCLUDES ******************************************************************/
  
- /* Always target Windows 2003 Service Pack 1 */
+ /* Version Data */
+ #include <ntverp.h>
  #define _WIN32_WINNT _WIN32_WINNT_WS03
  #define NTDDI_VERSION NTDDI_WS03SP1
 +#define NTKERNELAPI
++#define NOEXTAPI
  
  /* DDK/IFS/NDK Headers */
+ #define NTKERNELAPI
+ #define NOEXTAPI
  #include <ntifs.h>
  #undef _KPROCESS
  #undef _EPROCESS
  #include <pseh/pseh.h>
  
  /* ReactOS Headers */
- #include <reactos/version.h>
- #include <reactos/resource.h>
+ #include <reactos/buildno.h>
  #include <reactos/bugcodes.h>
- #include <reactos/rossym.h>
  #define ExRaiseStatus RtlRaiseStatus
  #include <reactos/probe.h>
++#include <reactos/rossym.h>
  
  /* SetupLDR Support */
  #include <arc/setupblk.h>
Simple merge
index f781f18,0000000..603829d
mode 100644,000000..100644
--- /dev/null
@@@ -1,313 -1,0 +1,312 @@@
- ULONG KiBugCheckData;
 +/*
 + * COPYRIGHT:       See COPYING in the top level directory
 + * PROJECT:         ReactOS Kernel
 + * FILE:            ntoskrnl/kd/kdinit.c
 + * PURPOSE:         Kernel Debugger Initializtion
 + *
 + * PROGRAMMERS:     Alex Ionescu (alex@relsoft.net)
 + */
 +
 +#include <ntoskrnl.h>
 +#define NDEBUG
 +#include <internal/debug.h>
 +
 +/* VARIABLES ***************************************************************/
 +
 +BOOLEAN KdDebuggerEnabled = FALSE;
 +BOOLEAN KdEnteredDebugger = FALSE;
 +BOOLEAN KdDebuggerNotPresent = TRUE;
 +BOOLEAN KiEnableTimerWatchdog = FALSE;
 +BOOLEAN KdBreakAfterSymbolLoad = FALSE;
 +BOOLEAN KdpBreakPending;
 +VOID STDCALL PspDumpThreads(BOOLEAN SystemThreads);
 +
 +typedef struct
 +{
 +      ULONG ComponentId;
 +      ULONG Level;
 +} KD_COMPONENT_DATA;
 +#define MAX_KD_COMPONENT_TABLE_ENTRIES 128
 +KD_COMPONENT_DATA KdComponentTable[MAX_KD_COMPONENT_TABLE_ENTRIES];
 +ULONG KdComponentTableEntries = 0;
 +
 +/* PRIVATE FUNCTIONS *********************************************************/
 +
 +ULONG
 +STDCALL
 +KdpServiceDispatcher(ULONG Service,
 +                     PVOID Buffer1,
 +                     ULONG Buffer1Length)
 +{
 +    ULONG Result = 0;
 +
 +    switch (Service)
 +    {
 +        case BREAKPOINT_PRINT: /* DbgPrint */
 +            Result = KdpPrintString(Buffer1, Buffer1Length);
 +            break;
 +
 +#ifdef DBG
 +        case TAG('R', 'o', 's', ' '): /* ROS-INTERNAL */
 +        {
 +            switch ((ULONG)Buffer1)
 +            {
 +                case DumpNonPagedPool:
 +                    MiDebugDumpNonPagedPool(FALSE);
 +                    break;
 +
 +                case ManualBugCheck:
 +                    KEBUGCHECK(MANUALLY_INITIATED_CRASH);
 +                    break;
 +
 +                case DumpNonPagedPoolStats:
 +                    MiDebugDumpNonPagedPoolStats(FALSE);
 +                    break;
 +
 +                case DumpNewNonPagedPool:
 +                    MiDebugDumpNonPagedPool(TRUE);
 +                    break;
 +
 +                case DumpNewNonPagedPoolStats:
 +                    MiDebugDumpNonPagedPoolStats(TRUE);
 +                    break;
 +
 +                case DumpAllThreads:
 +                    PspDumpThreads(TRUE);
 +                    break;
 +
 +                case DumpUserThreads:
 +                    PspDumpThreads(FALSE);
 +                    break;
 +
 +                case EnterDebugger:
 +                    DbgBreakPoint();
 +                    break;
 +
 +                default:
 +                    break;
 +            }
 +        }
 +#endif
 +        default:
 +            HalDisplayString ("Invalid debug service call!\n");
 +            break;
 +    }
 +
 +    return Result;
 +}
 +
 +BOOLEAN
 +NTAPI
 +KdpEnterDebuggerException(IN PKTRAP_FRAME TrapFrame,
 +                          IN PKEXCEPTION_FRAME ExceptionFrame,
 +                          IN PEXCEPTION_RECORD ExceptionRecord,
 +                          IN PCONTEXT Context,
 +                          IN KPROCESSOR_MODE PreviousMode,
 +                          IN BOOLEAN SecondChance)
 +{
 +    KD_CONTINUE_TYPE Return;
 +
 +    /* HACK (just like all this routine */
 +    if (ExceptionRecord->ExceptionCode == STATUS_BREAKPOINT) Context->Eip++;
 +
 +    /* Get out of here if the Debugger isn't connected */
 +    if (KdDebuggerNotPresent) return FALSE;
 +
 +    /* Call KDBG if available */
 +    Return = KdbEnterDebuggerException(ExceptionRecord,
 +                                       PreviousMode,
 +                                       Context,
 +                                       TrapFrame,
 +                                       !SecondChance);
 +
 +    /* Convert return to BOOLEAN */
 +    if (Return == kdContinue) return TRUE;
 +    return FALSE;
 +}
 +
 +BOOLEAN
 +NTAPI
 +KdpCallGdb(IN PKTRAP_FRAME TrapFrame,
 +           IN PEXCEPTION_RECORD ExceptionRecord,
 +           IN PCONTEXT Context)
 +{
 +    KD_CONTINUE_TYPE Return = kdDoNotHandleException;
 +
 +    /* Get out of here if the Debugger isn't connected */
 +    if (KdDebuggerNotPresent) return FALSE;
 +
 +    /* FIXME:
 +     * Right now, the GDB wrapper seems to handle exceptions differntly
 +     * from KDGB and both are called at different times, while the GDB
 +     * one is only called once and that's it. I don't really have the knowledge
 +     * to fix the GDB stub, so until then, we'll be using this hack
 +     */
 +    if (WrapperInitRoutine)
 +    {
 +        Return = WrapperTable.KdpExceptionRoutine(ExceptionRecord,
 +                                                  Context,
 +                                                  TrapFrame);
 +    }
 +
 +    /* Convert return to BOOLEAN */
 +    if (Return == kdContinue) return TRUE;
 +    return FALSE;
 +}
 +
 +/* PUBLIC FUNCTIONS *********************************************************/
 +
 +/*
 + * @implemented
 + */
 +NTSTATUS
 +STDCALL
 +KdDisableDebugger(VOID)
 +{
 +    KIRQL OldIrql;
 +
 +    /* Raise IRQL */
 +    KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
 +
 +    /* TODO: Disable any breakpoints */
 +
 +    /* Disable the Debugger */
 +    KdDebuggerEnabled = FALSE;
 +
 +    /* Lower the IRQL */
 +    KeLowerIrql(OldIrql);
 +
 +    /* Return success */
 +    return STATUS_SUCCESS;
 +}
 +
 +/*
 + * @implemented
 + */
 +NTSTATUS
 +STDCALL
 +KdEnableDebugger(VOID)
 +{
 +    KIRQL OldIrql;
 +
 +    /* Raise IRQL */
 +    KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
 +
 +    /* TODO: Re-enable any breakpoints */
 +
 +    /* Enable the Debugger */
 +    KdDebuggerEnabled = TRUE;
 +
 +    /* Lower the IRQL */
 +    KeLowerIrql(OldIrql);
 +
 +    /* Return success */
 +    return STATUS_SUCCESS;
 +}
 +
 +/*
 + * @implemented
 + */
 +BOOLEAN
 +STDCALL
 +KdPollBreakIn(VOID)
 +{
 +    return KdpBreakPending;
 +}
 +
 +/*
 + * @implemented
 + */
 +VOID
 +STDCALL
 +KeEnterKernelDebugger(VOID)
 +{
 +    HalDisplayString("\n\n *** Entered kernel debugger ***\n");
 +
 +    /* Set the Variable */
 +    KdEnteredDebugger = TRUE;
 +
 +    /* Halt the CPU */
 +    for (;;) Ke386HaltProcessor();
 +}
 +
 +/*
 + * @unimplemented
 + */
 +NTSTATUS
 +STDCALL
 +KdPowerTransition(ULONG PowerState)
 +{
 +    UNIMPLEMENTED;
 +    return STATUS_NOT_IMPLEMENTED;
 +}
 +
 +/*
 + * @unimplemented
 + */
 +VOID
 +STDCALL
 +KdChangeOption(IN KD_OPTION Option,
 +               IN ULONG InBufferLength OPTIONAL,
 +               IN PVOID InBuffer,
 +               IN ULONG OutBufferLength OPTIONAL,
 +               OUT PVOID OutBuffer,
 +               OUT PULONG OutBufferRequiredLength OPTIONAL)
 +{
 +    UNIMPLEMENTED;
 +}
 +
 +
 +NTSTATUS
 +STDCALL
 +NtQueryDebugFilterState(IN ULONG ComponentId,
 +                        IN ULONG Level)
 +{
 +      unsigned int i;
 +
 +      /* convert Level to mask if it isn't already one */
 +      if ( Level < 32 )
 +              Level = 1 << Level;
 +
 +      for ( i = 0; i < KdComponentTableEntries; i++ )
 +      {
 +              if ( ComponentId == KdComponentTable[i].ComponentId )
 +              {
 +                      if ( Level & KdComponentTable[i].Level )
 +                              return TRUE;
 +                      break;
 +              }
 +      }
 +      return FALSE;
 +}
 +
 +NTSTATUS
 +STDCALL
 +NtSetDebugFilterState(IN ULONG ComponentId,
 +                      IN ULONG Level,
 +                      IN BOOLEAN State)
 +{
 +      unsigned int i;
 +      for ( i = 0; i < KdComponentTableEntries; i++ )
 +      {
 +              if ( ComponentId == KdComponentTable[i].ComponentId )
 +                      break;
 +      }
 +      if ( i == KdComponentTableEntries )
 +      {
 +              if ( i == MAX_KD_COMPONENT_TABLE_ENTRIES )
 +                      return STATUS_INVALID_PARAMETER_1;
 +              ++KdComponentTableEntries;
 +              KdComponentTable[i].ComponentId = ComponentId;
 +              KdComponentTable[i].Level = 0;
 +      }
 +      if ( State )
 +              KdComponentTable[i].Level |= Level;
 +      else
 +              KdComponentTable[i].Level &= ~Level;
 +      return STATUS_SUCCESS;
 +}
 +
 +PKDEBUG_ROUTINE KiDebugRoutine = KdpEnterDebuggerException;
 +
 + /* EOF */
@@@ -794,7 -818,8 +818,7 @@@ KeBugCheckWithTf(IN ULONG BugCheckCode
          }
      }
  
-     /* FIXME: Check if we need to save the context for KD */
+     /* Check if we need to save the context for KD */
 -    if (!KdPitchDebugger) KdDebuggerDataBlock.SavedContext = (ULONG)&Context;
  
      /* Check if a debugger is connected */
      if ((BugCheckCode != MANUALLY_INITIATED_CRASH) && (KdDebuggerEnabled))
              /* Break in the debugger */
              KiBugCheckDebugBreak(DBG_STATUS_BUGCHECK_FIRST);
          }
 +        else
 +        {
 +            /*
 +             * ROS HACK.
 +             * Ok, so debugging is enabled, but KDBG isn't there.
 +             * We'll manually dump the stack for the user.
 +             */
 +            KeRosDumpStackFrames(NULL, 0);
 +        }
      }
  
-     /* Use the boot video driver to clear, fill and write to screen. */
-     if (InbvIsBootDriverInstalled())
-     {
-         /* FIXME: This should happen in KiDisplayBlueScreen!!! */
-         InbvAcquireDisplayOwnership();
-         InbvResetDisplay();
-         InbvSolidColorFill(0, 0, 639, 479, 4);
-         InbvSetTextColor(15);
-         InbvInstallDisplayStringFilter(NULL);
-         InbvEnableDisplayString(TRUE);
-         InbvSetScrollRegion(0, 0, 639, 479);
-     }
      /* Raise IRQL to HIGH_LEVEL */
      _disable();
      KeRaiseIrql(HIGH_LEVEL, &OldIrql);
                              HardErrMessage,
                              AnsiName);
  
-         /* FIXME: Enable debugger if it was pending */
-         /* Print the last line */
-         InbvDisplayString("\r\n");
+         /* Check if the debugger is disabled but we can enable it */
 -        if (!(KdDebuggerEnabled) && !(KdPitchDebugger))
++        //if (!(KdDebuggerEnabled) && !(KdPitchDebugger))
+         {
+             /* Enable it */
 -            KdEnableDebuggerWithLock(FALSE);
++            //KdEnableDebuggerWithLock(FALSE);
+         }
 -        else
++        //else
+         {
+             /* Otherwise, print the last line */
+             InbvDisplayString("\r\n");
+         }
  
          /* Save the context */
          Prcb->ProcessorState.ContextFrame = Context;
@@@ -143,24 -143,24 +143,22 @@@ KiRaiseException(IN PEXCEPTION_RECORD E
          Status = _SEH_GetExceptionCode();
      }
      _SEH_END;
++    if (!NT_SUCCESS(Status)) return Status;
  
--    /* Make sure we didn't crash in SEH */
--    if (NT_SUCCESS(Status))
--    {
--        /* Convert the context record */
--        KeContextToTrapFrame(Context,
--                             ExceptionFrame,
--                             TrapFrame,
--                             Context->ContextFlags,
--                             PreviousMode);
--
--        /* Dispatch the exception */
--        KiDispatchException(ExceptionRecord,
--                            ExceptionFrame,
--                            TrapFrame,
--                            PreviousMode,
--                            SearchFrames);
--    }
++    /* Convert the context record */
++    KeContextToTrapFrame(Context,
++                         ExceptionFrame,
++                         TrapFrame,
++                         Context->ContextFlags,
++                         PreviousMode);
++
++    /* Dispatch the exception */
++    ExceptionRecord->ExceptionCode &= ~KI_EXCEPTION_INTERNAL;
++    KiDispatchException(ExceptionRecord,
++                        ExceptionFrame,
++                        TrapFrame,
++                        PreviousMode,
++                        SearchFrames);
  
      /* Return the status */
      return Status;
Simple merge
Simple merge
@@@ -487,45 -471,10 +487,45 @@@ _KiDebugService
      /* Call debug service dispatcher */
      mov eax, [ebp+KTRAP_FRAME_EAX]
      mov ecx, [ebp+KTRAP_FRAME_ECX]
-     mov edx, [ebp+KTRAP_FRAME_EAX]
+     mov edx, [ebp+KTRAP_FRAME_EDX]
  
 -    /* Jump to INT3 handler */
 -    jmp PrepareInt3
 +    /* Check for V86 mode */
 +    test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
 +    jnz NotUserMode
 +
 +    /* Check if this is kernel or user-mode */
 +    test byte ptr [ebp+KTRAP_FRAME_CS], 1
 +    jz CallDispatch
 +    cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
 +    jnz NotUserMode
 +
 +    /* Re-enable interrupts */
 +VdmProc:
 +    sti
 +
 +    /* Call the debug routine */
 +CallDispatch:
 +    mov esi, ecx
 +    mov edi, edx
 +    mov edx, eax
 +    mov ecx, 3
 +    push edi
 +    push esi
 +    push edx
 +    call _KdpServiceDispatcher@12
 +
 +NotUserMode:
 +
 +    /* Get the current process */
 +    mov ebx, [fs:KPCR_CURRENT_THREAD]
 +    mov ebx, [ebx+KTHREAD_APCSTATE_PROCESS]
 +
 +    /* Check if this is a VDM Process */
 +    //cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
 +    //jz VdmProc
 +
 +    /* Exit through common routine */
 +    jmp _Kei386EoiHelper@0
  .endfunc
  
  .func NtRaiseException@12
index ef40fed,0000000..d67d4a4
mode 100644,000000..100644
--- /dev/null
@@@ -1,1852 -1,0 +1,1852 @@@
- PVOID PsNtosImageBase;\r
 +/*\r
 +* PROJECT:         ReactOS Kernel\r
 +* LICENSE:         GPL - See COPYING in the top level directory\r
 +* FILE:            ntoskrnl/mm/sysldr.c\r
 +* PURPOSE:         Contains the Kernel Loader (SYSLDR) for loading PE files.\r
 +* PROGRAMMERS:     Alex Ionescu (alex.ionescu@reactos.org)\r
 +*/\r
 +\r
 +/* INCLUDES ******************************************************************/\r
 +\r
 +#include <ntoskrnl.h>\r
 +#define NDEBUG\r
 +#include <debug.h>\r
 +\r
 +/* GLOBALS *******************************************************************/\r
 +\r
 +LIST_ENTRY PsLoadedModuleList;\r
 +KSPIN_LOCK PsLoadedModuleSpinLock;\r
-     PsNtosImageBase = LdrEntry->DllBase;\r
++ULONG PsNtosImageBase;\r
 +KMUTANT MmSystemLoadLock;\r
 +extern ULONG NtGlobalFlag;\r
 +\r
 +/* FUNCTIONS *****************************************************************/\r
 +\r
 +VOID\r
 +NTAPI\r
 +MiFreeBootDriverMemory(PVOID BaseAddress,\r
 +                       ULONG Length)\r
 +{\r
 +    ULONG i;\r
 +\r
 +    /* Loop each page */\r
 +    for (i = 0; i < PAGE_ROUND_UP(Length) / PAGE_SIZE; i++)\r
 +    {\r
 +        /* Free the page */\r
 +        MmDeleteVirtualMapping(NULL,\r
 +                               (PVOID)((ULONG_PTR)BaseAddress + i * PAGE_SIZE),\r
 +                               TRUE,\r
 +                               NULL,\r
 +                               NULL);\r
 +    }\r
 +}\r
 +\r
 +NTSTATUS\r
 +NTAPI\r
 +MiLoadImageSection(IN OUT PVOID *SectionPtr,\r
 +                   OUT PVOID *ImageBase,\r
 +                   IN PUNICODE_STRING FileName,\r
 +                   IN BOOLEAN SessionLoad,\r
 +                   IN PLDR_DATA_TABLE_ENTRY LdrEntry)\r
 +{\r
 +    PROS_SECTION_OBJECT Section = *SectionPtr;\r
 +    NTSTATUS Status;\r
 +    PEPROCESS Process;\r
 +    PVOID Base = NULL;\r
 +    SIZE_T ViewSize = 0;\r
 +    KAPC_STATE ApcState;\r
 +    LARGE_INTEGER SectionOffset = {{0}};\r
 +    BOOLEAN LoadSymbols = FALSE;\r
 +    ULONG DriverSize;\r
 +    PVOID DriverBase;\r
 +    PAGED_CODE();\r
 +\r
 +    /* Detect session load */\r
 +    if (SessionLoad)\r
 +    {\r
 +        /* Fail */\r
 +        DPRINT1("Session loading not yet supported!\n");\r
 +        while (TRUE);\r
 +    }\r
 +\r
 +    /* Not session load, shouldn't have an entry */\r
 +    ASSERT(LdrEntry == NULL);\r
 +\r
 +    /* Attach to the system process */\r
 +    KeStackAttachProcess(&PsInitialSystemProcess->Pcb, &ApcState);\r
 +\r
 +    /* Check if we need to load symbols */\r
 +    if (NtGlobalFlag & FLG_ENABLE_KDEBUG_SYMBOL_LOAD)\r
 +    {\r
 +        /* Yes we do */\r
 +        LoadSymbols = TRUE;\r
 +        NtGlobalFlag &= ~FLG_ENABLE_KDEBUG_SYMBOL_LOAD;\r
 +    }\r
 +\r
 +    /* Map the driver */\r
 +    Process = PsGetCurrentProcess();\r
 +    Status = MmMapViewOfSection(Section,\r
 +                                Process,\r
 +                                &Base,\r
 +                                0,\r
 +                                0,\r
 +                                &SectionOffset,\r
 +                                &ViewSize,\r
 +                                ViewUnmap,\r
 +                                0,\r
 +                                PAGE_EXECUTE);\r
 +\r
 +    /* Re-enable the flag */\r
 +    if (LoadSymbols) NtGlobalFlag |= FLG_ENABLE_KDEBUG_SYMBOL_LOAD;\r
 +\r
 +    /* Check if we failed with distinguished status code */\r
 +    if (Status == STATUS_IMAGE_MACHINE_TYPE_MISMATCH)\r
 +    {\r
 +        /* Change it to something more generic */\r
 +        Status = STATUS_INVALID_IMAGE_FORMAT;\r
 +    }\r
 +\r
 +    /* Now check if we failed */\r
 +    if (!NT_SUCCESS(Status))\r
 +    {\r
 +        /* Detach and return */\r
 +        KeUnstackDetachProcess(&ApcState);\r
 +        return Status;\r
 +    }\r
 +\r
 +    /* Get the driver size */\r
 +    DriverSize = Section->ImageSection->ImageSize;\r
 +\r
 +    /*  Allocate a virtual section for the module  */\r
 +    DriverBase = MmAllocateSection(DriverSize, NULL);\r
 +    *ImageBase = DriverBase;\r
 +\r
 +    /* Copy the image */\r
 +    RtlCopyMemory(DriverBase, Base, DriverSize);\r
 +\r
 +    /* Now unmap the view */\r
 +    Status = MmUnmapViewOfSection(Process, Base);\r
 +    ASSERT(NT_SUCCESS(Status));\r
 +\r
 +    /* Detach and return status */\r
 +    KeUnstackDetachProcess(&ApcState);\r
 +    return Status;\r
 +}\r
 +\r
 +NTSTATUS\r
 +NTAPI\r
 +MiDereferenceImports(IN PLOAD_IMPORTS ImportList)\r
 +{\r
 +    /* Check if there's no imports or if we're a boot driver */\r
 +    if ((ImportList == (PVOID)-1) || (ImportList == (PVOID)-2))\r
 +    {\r
 +        /* Then there's nothing to do */\r
 +        return STATUS_SUCCESS;\r
 +    }\r
 +\r
 +    /* Otherwise, FIXME */\r
 +    DPRINT1("Imports not dereferenced!\n");\r
 +    return STATUS_UNSUCCESSFUL;\r
 +}\r
 +\r
 +VOID\r
 +NTAPI\r
 +MiClearImports(IN PLDR_DATA_TABLE_ENTRY LdrEntry)\r
 +{\r
 +    PAGED_CODE();\r
 +\r
 +    /* Check if there's no imports or we're a boot driver or only one entry */\r
 +    if ((LdrEntry->LoadedImports == (PVOID)-1) ||\r
 +        (LdrEntry->LoadedImports == (PVOID)-2) ||\r
 +        ((ULONG_PTR)LdrEntry->LoadedImports & 1))\r
 +    {\r
 +        /* Nothing to do */\r
 +        return;\r
 +    }\r
 +\r
 +    /* Otherwise, free the import list */\r
 +    ExFreePool(LdrEntry->LoadedImports);\r
 +}\r
 +\r
 +PVOID\r
 +NTAPI\r
 +MiFindExportedRoutineByName(IN PVOID DllBase,\r
 +                            IN PANSI_STRING ExportName)\r
 +{\r
 +    PULONG NameTable;\r
 +    PUSHORT OrdinalTable;\r
 +    PIMAGE_EXPORT_DIRECTORY ExportDirectory;\r
 +    LONG Low = 0, Mid = 0, High, Ret;\r
 +    USHORT Ordinal;\r
 +    PVOID Function;\r
 +    ULONG ExportSize;\r
 +    PULONG ExportTable;\r
 +    PAGED_CODE();\r
 +\r
 +    /* Get the export directory */\r
 +    ExportDirectory = RtlImageDirectoryEntryToData(DllBase,\r
 +                                                   TRUE,\r
 +                                                   IMAGE_DIRECTORY_ENTRY_EXPORT,\r
 +                                                   &ExportSize);\r
 +    if (!ExportDirectory) return NULL;\r
 +\r
 +    /* Setup name tables */\r
 +    NameTable = (PULONG)((ULONG_PTR)DllBase +\r
 +                         ExportDirectory->AddressOfNames);\r
 +    OrdinalTable = (PUSHORT)((ULONG_PTR)DllBase +\r
 +                             ExportDirectory->AddressOfNameOrdinals);\r
 +\r
 +    /* Do a binary search */\r
 +    High = ExportDirectory->NumberOfNames - 1;\r
 +    while (High >= Low)\r
 +    {\r
 +        /* Get new middle value */\r
 +        Mid = (Low + High) >> 1;\r
 +\r
 +        /* Compare name */\r
 +        Ret = strcmp(ExportName->Buffer, (PCHAR)DllBase + NameTable[Mid]);\r
 +        if (Ret < 0)\r
 +        {\r
 +            /* Update high */\r
 +            High = Mid - 1;\r
 +        }\r
 +        else if (Ret > 0)\r
 +        {\r
 +            /* Update low */\r
 +            Low = Mid + 1;\r
 +        }\r
 +        else\r
 +        {\r
 +            /* We got it */\r
 +            break;\r
 +        }\r
 +    }\r
 +\r
 +    /* Check if we couldn't find it */\r
 +    if (High < Low) return NULL;\r
 +\r
 +    /* Otherwise, this is the ordinal */\r
 +    Ordinal = OrdinalTable[Mid];\r
 +\r
 +    /* Resolve the address and write it */\r
 +    ExportTable = (PULONG)((ULONG_PTR)DllBase +\r
 +                           ExportDirectory->AddressOfFunctions);\r
 +    Function = (PVOID)((ULONG_PTR)DllBase + ExportTable[Ordinal]);\r
 +\r
 +    /* We found it! */\r
 +    ASSERT((Function > (PVOID)ExportDirectory) &&\r
 +           (Function < (PVOID)((ULONG_PTR)ExportDirectory + ExportSize)));\r
 +    return Function;\r
 +}\r
 +\r
 +PVOID\r
 +NTAPI\r
 +MiLocateExportName(IN PVOID DllBase,\r
 +                   IN PCHAR ExportName)\r
 +{\r
 +    PULONG NameTable;\r
 +    PUSHORT OrdinalTable;\r
 +    PIMAGE_EXPORT_DIRECTORY ExportDirectory;\r
 +    LONG Low = 0, Mid = 0, High, Ret;\r
 +    USHORT Ordinal;\r
 +    PVOID Function;\r
 +    ULONG ExportSize;\r
 +    PULONG ExportTable;\r
 +    PAGED_CODE();\r
 +\r
 +    /* Get the export directory */\r
 +    ExportDirectory = RtlImageDirectoryEntryToData(DllBase,\r
 +                                                   TRUE,\r
 +                                                   IMAGE_DIRECTORY_ENTRY_EXPORT,\r
 +                                                   &ExportSize);\r
 +    if (!ExportDirectory) return NULL;\r
 +\r
 +    /* Setup name tables */\r
 +    NameTable = (PULONG)((ULONG_PTR)DllBase +\r
 +                         ExportDirectory->AddressOfNames);\r
 +    OrdinalTable = (PUSHORT)((ULONG_PTR)DllBase +\r
 +                             ExportDirectory->AddressOfNameOrdinals);\r
 +\r
 +    /* Do a binary search */\r
 +    High = ExportDirectory->NumberOfNames - 1;\r
 +    while (High >= Low)\r
 +    {\r
 +        /* Get new middle value */\r
 +        Mid = (Low + High) >> 1;\r
 +\r
 +        /* Compare name */\r
 +        Ret = strcmp(ExportName, (PCHAR)DllBase + NameTable[Mid]);\r
 +        if (Ret < 0)\r
 +        {\r
 +            /* Update high */\r
 +            High = Mid - 1;\r
 +        }\r
 +        else if (Ret > 0)\r
 +        {\r
 +            /* Update low */\r
 +            Low = Mid + 1;\r
 +        }\r
 +        else\r
 +        {\r
 +            /* We got it */\r
 +            break;\r
 +        }\r
 +    }\r
 +\r
 +    /* Check if we couldn't find it */\r
 +    if (High < Low) return NULL;\r
 +\r
 +    /* Otherwise, this is the ordinal */\r
 +    Ordinal = OrdinalTable[Mid];\r
 +\r
 +    /* Resolve the address and write it */\r
 +    ExportTable = (PULONG)((ULONG_PTR)DllBase +\r
 +                           ExportDirectory->AddressOfFunctions);\r
 +    Function = (PVOID)((ULONG_PTR)DllBase + ExportTable[Ordinal]);\r
 +\r
 +    /* Check if the function is actually a forwarder */\r
 +    if (((ULONG_PTR)Function > (ULONG_PTR)ExportDirectory) &&\r
 +        ((ULONG_PTR)Function < ((ULONG_PTR)ExportDirectory + ExportSize)))\r
 +    {\r
 +        /* It is, fail */\r
 +        return NULL;\r
 +    }\r
 +\r
 +    /* We found it */\r
 +    return Function;\r
 +}\r
 +\r
 +NTSTATUS\r
 +NTAPI\r
 +MmCallDllInitialize(IN PLDR_DATA_TABLE_ENTRY LdrEntry,\r
 +                    IN PLIST_ENTRY ListHead)\r
 +{\r
 +    PMM_DLL_INITIALIZE DllInit;\r
 +\r
 +    /* Try to see if the image exports a DllInitialize routine */\r
 +    DllInit = (PMM_DLL_INITIALIZE)MiLocateExportName(LdrEntry->DllBase,\r
 +                                                     "DllInitialize");\r
 +    if (!DllInit) return STATUS_SUCCESS;\r
 +\r
 +    /* FIXME: TODO */\r
 +    DPRINT1("DllInitialize not called!\n");\r
 +    return STATUS_UNSUCCESSFUL;\r
 +}\r
 +\r
 +VOID\r
 +NTAPI\r
 +MiProcessLoaderEntry(IN PLDR_DATA_TABLE_ENTRY LdrEntry,\r
 +                     IN BOOLEAN Insert)\r
 +{\r
 +    KIRQL OldIrql;\r
 +\r
 +    /* Acquire the lock */\r
 +    KeAcquireSpinLock(&PsLoadedModuleSpinLock, &OldIrql);\r
 +\r
 +    /* Insert or remove from the list */\r
 +    Insert ? InsertTailList(&PsLoadedModuleList, &LdrEntry->InLoadOrderLinks) :\r
 +             RemoveEntryList(&LdrEntry->InLoadOrderLinks);\r
 +\r
 +    /* Release the lock */\r
 +    KeReleaseSpinLock(&PsLoadedModuleSpinLock, OldIrql);\r
 +}\r
 +\r
 +VOID\r
 +NTAPI\r
 +MiUpdateThunks(IN PLOADER_PARAMETER_BLOCK LoaderBlock,\r
 +               IN PVOID OldBase,\r
 +               IN PVOID NewBase,\r
 +               IN ULONG Size)\r
 +{\r
 +    ULONG_PTR OldBaseTop, Delta;\r
 +    PLDR_DATA_TABLE_ENTRY LdrEntry;\r
 +    PLIST_ENTRY NextEntry;\r
 +    ULONG ImportSize;\r
 +    PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor;\r
 +    PULONG ImageThunk;\r
 +\r
 +    /* Calculate the top and delta */\r
 +    OldBaseTop = (ULONG_PTR)OldBase + Size - 1;\r
 +    Delta = (ULONG_PTR)NewBase - (ULONG_PTR)OldBase;\r
 +\r
 +    /* Loop the loader block */\r
 +    for (NextEntry = LoaderBlock->LoadOrderListHead.Flink;\r
 +         NextEntry != &LoaderBlock->LoadOrderListHead;\r
 +         NextEntry = NextEntry->Flink)\r
 +    {\r
 +        /* Get the loader entry */\r
 +        LdrEntry = CONTAINING_RECORD(NextEntry,\r
 +                                     LDR_DATA_TABLE_ENTRY,\r
 +                                     InLoadOrderLinks);\r
 +\r
 +        /* Get the import table */\r
 +        ImportDescriptor = RtlImageDirectoryEntryToData(LdrEntry->DllBase,\r
 +                                                        TRUE,\r
 +                                                        IMAGE_DIRECTORY_ENTRY_IMPORT,\r
 +                                                        &ImportSize);\r
 +        if (!ImportDescriptor) continue;\r
 +\r
 +        /* Make sure we have an IAT */\r
 +        DPRINT("[Mm0]: Updating thunks in: %wZ\n", &LdrEntry->BaseDllName);\r
 +        while ((ImportDescriptor->Name) &&\r
 +               (ImportDescriptor->OriginalFirstThunk))\r
 +        {\r
 +            /* Get the image thunk */\r
 +            ImageThunk = (PVOID)((ULONG_PTR)LdrEntry->DllBase +\r
 +                                 ImportDescriptor->FirstThunk);\r
 +            while (*ImageThunk)\r
 +            {\r
 +                /* Check if it's within this module */\r
 +                if ((*ImageThunk >= (ULONG_PTR)OldBase) && (*ImageThunk <= OldBaseTop))\r
 +                {\r
 +                    /* Relocate it */\r
 +                    DPRINT("[Mm0]: Updating IAT at: %p. Old Entry: %p. New Entry: %p.\n",\r
 +                            ImageThunk, *ImageThunk, *ImageThunk + Delta);\r
 +                    *ImageThunk += Delta;\r
 +                }\r
 +\r
 +                /* Go to the next thunk */\r
 +                ImageThunk++;\r
 +            }\r
 +\r
 +            /* Go to the next import */\r
 +            ImportDescriptor++;\r
 +        }\r
 +    }\r
 +}\r
 +\r
 +NTSTATUS\r
 +NTAPI\r
 +MiSnapThunk(IN PVOID DllBase,\r
 +            IN PVOID ImageBase,\r
 +            IN PIMAGE_THUNK_DATA Name,\r
 +            IN PIMAGE_THUNK_DATA Address,\r
 +            IN PIMAGE_EXPORT_DIRECTORY ExportDirectory,\r
 +            IN ULONG ExportSize,\r
 +            IN BOOLEAN SnapForwarder,\r
 +            OUT PCHAR *MissingApi)\r
 +{\r
 +    BOOLEAN IsOrdinal;\r
 +    USHORT Ordinal;\r
 +    PULONG NameTable;\r
 +    PUSHORT OrdinalTable;\r
 +    PIMAGE_IMPORT_BY_NAME NameImport;\r
 +    USHORT Hint;\r
 +    ULONG Low = 0, Mid = 0, High;\r
 +    LONG Ret;\r
 +    NTSTATUS Status;\r
 +    PCHAR MissingForwarder;\r
 +    CHAR NameBuffer[MAXIMUM_FILENAME_LENGTH];\r
 +    PULONG ExportTable;\r
 +    ANSI_STRING DllName;\r
 +    UNICODE_STRING ForwarderName;\r
 +    PLIST_ENTRY NextEntry;\r
 +    PLDR_DATA_TABLE_ENTRY LdrEntry;\r
 +    ULONG ForwardExportSize;\r
 +    PIMAGE_EXPORT_DIRECTORY ForwardExportDirectory;\r
 +    PIMAGE_IMPORT_BY_NAME ForwardName;\r
 +    ULONG ForwardLength;\r
 +    IMAGE_THUNK_DATA ForwardThunk;\r
 +    PAGED_CODE();\r
 +\r
 +    /* Check if this is an ordinal */\r
 +    IsOrdinal = IMAGE_SNAP_BY_ORDINAL(Name->u1.Ordinal);\r
 +    if ((IsOrdinal) && !(SnapForwarder))\r
 +    {\r
 +        /* Get the ordinal number and set it as missing */\r
 +        Ordinal = (USHORT)(IMAGE_ORDINAL(Name->u1.Ordinal) -\r
 +                           ExportDirectory->Base);\r
 +        *MissingApi = (PCHAR)(ULONG_PTR)Ordinal;\r
 +    }\r
 +    else\r
 +    {\r
 +        /* Get the VA if we don't have to snap */\r
 +        if (!SnapForwarder) Name->u1.AddressOfData += (ULONG_PTR)ImageBase;\r
 +        NameImport = (PIMAGE_IMPORT_BY_NAME)Name->u1.AddressOfData;\r
 +\r
 +        /* Copy the procedure name */\r
 +        strncpy(*MissingApi,\r
 +                (PCHAR)&NameImport->Name[0],\r
 +                MAXIMUM_FILENAME_LENGTH - 1);\r
 +\r
 +        /* Setup name tables */\r
 +        DPRINT("Import name: %s\n", NameImport->Name);\r
 +        NameTable = (PULONG)((ULONG_PTR)DllBase +\r
 +                             ExportDirectory->AddressOfNames);\r
 +        OrdinalTable = (PUSHORT)((ULONG_PTR)DllBase +\r
 +                                 ExportDirectory->AddressOfNameOrdinals);\r
 +\r
 +        /* Get the hint and check if it's valid */\r
 +        Hint = NameImport->Hint;\r
 +        if ((Hint < ExportDirectory->NumberOfNames) &&\r
 +            !(strcmp((PCHAR) NameImport->Name, (PCHAR)DllBase + NameTable[Hint])))\r
 +        {\r
 +            /* We have a match, get the ordinal number from here */\r
 +            Ordinal = OrdinalTable[Hint];\r
 +        }\r
 +        else\r
 +        {\r
 +            /* Do a binary search */\r
 +            High = ExportDirectory->NumberOfNames - 1;\r
 +            while (High >= Low)\r
 +            {\r
 +                /* Get new middle value */\r
 +                Mid = (Low + High) >> 1;\r
 +\r
 +                /* Compare name */\r
 +                Ret = strcmp((PCHAR)NameImport->Name, (PCHAR)DllBase + NameTable[Mid]);\r
 +                if (Ret < 0)\r
 +                {\r
 +                    /* Update high */\r
 +                    High = Mid - 1;\r
 +                }\r
 +                else if (Ret > 0)\r
 +                {\r
 +                    /* Update low */\r
 +                    Low = Mid + 1;\r
 +                }\r
 +                else\r
 +                {\r
 +                    /* We got it */\r
 +                    break;\r
 +                }\r
 +            }\r
 +\r
 +            /* Check if we couldn't find it */\r
 +            if (High < Low) return STATUS_DRIVER_ENTRYPOINT_NOT_FOUND;\r
 +\r
 +            /* Otherwise, this is the ordinal */\r
 +            Ordinal = OrdinalTable[Mid];\r
 +        }\r
 +    }\r
 +\r
 +    /* Check if the ordinal is invalid */\r
 +    if (Ordinal >= ExportDirectory->NumberOfFunctions)\r
 +    {\r
 +        /* Fail */\r
 +        Status = STATUS_DRIVER_ORDINAL_NOT_FOUND;\r
 +    }\r
 +    else\r
 +    {\r
 +        /* In case the forwarder is missing */\r
 +        MissingForwarder = NameBuffer;\r
 +\r
 +        /* Resolve the address and write it */\r
 +        ExportTable = (PULONG)((ULONG_PTR)DllBase +\r
 +                               ExportDirectory->AddressOfFunctions);\r
 +        Address->u1.Function = (ULONG_PTR)DllBase + ExportTable[Ordinal];\r
 +\r
 +        /* Assume success from now on */\r
 +        Status = STATUS_SUCCESS;\r
 +\r
 +        /* Check if the function is actually a forwarder */\r
 +        if ((Address->u1.Function > (ULONG_PTR)ExportDirectory) &&\r
 +            (Address->u1.Function < ((ULONG_PTR)ExportDirectory + ExportSize)))\r
 +        {\r
 +            /* Now assume failure in case the forwarder doesn't exist */\r
 +            Status = STATUS_DRIVER_ENTRYPOINT_NOT_FOUND;\r
 +\r
 +            /* Build the forwarder name */\r
 +            DllName.Buffer = (PCHAR)Address->u1.Function;\r
 +            DllName.Length = strchr(DllName.Buffer, '.') -\r
 +                             DllName.Buffer +\r
 +                             sizeof(ANSI_NULL);\r
 +            DllName.MaximumLength = DllName.Length;\r
 +\r
 +            /* Convert it */\r
 +            if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&ForwarderName,\r
 +                                                         &DllName,\r
 +                                                         TRUE)))\r
 +            {\r
 +                /* We failed, just return an error */\r
 +                return Status;\r
 +            }\r
 +\r
 +            /* Loop the module list */\r
 +            NextEntry = PsLoadedModuleList.Flink;\r
 +            while (NextEntry != &PsLoadedModuleList)\r
 +            {\r
 +                /* Get the loader entry */\r
 +                LdrEntry = CONTAINING_RECORD(NextEntry,\r
 +                                             LDR_DATA_TABLE_ENTRY,\r
 +                                             InLoadOrderLinks);\r
 +\r
 +                /* Check if it matches */\r
 +                if (RtlPrefixString((PSTRING)&ForwarderName,\r
 +                                    (PSTRING)&LdrEntry->BaseDllName,\r
 +                                    TRUE))\r
 +                {\r
 +                    /* Get the forwarder export directory */\r
 +                    ForwardExportDirectory =\r
 +                        RtlImageDirectoryEntryToData(LdrEntry->DllBase,\r
 +                                                     TRUE,\r
 +                                                     IMAGE_DIRECTORY_ENTRY_EXPORT,\r
 +                                                     &ForwardExportSize);\r
 +                    if (!ForwardExportDirectory) break;\r
 +\r
 +                    /* Allocate a name entry */\r
 +                    ForwardLength = strlen(DllName.Buffer + DllName.Length) +\r
 +                                    sizeof(ANSI_NULL);\r
 +                    ForwardName = ExAllocatePoolWithTag(PagedPool,\r
 +                                                        sizeof(*ForwardName) +\r
 +                                                        ForwardLength,\r
 +                                                        TAG_LDR_WSTR);\r
 +                    if (!ForwardName) break;\r
 +\r
 +                    /* Copy the data */\r
 +                    RtlCopyMemory(&ForwardName->Name[0],\r
 +                                  DllName.Buffer + DllName.Length,\r
 +                                  ForwardLength);\r
 +                    ForwardName->Hint = 0;\r
 +\r
 +                    /* Set the new address */\r
 +                    *(PULONG)&ForwardThunk.u1.AddressOfData = (ULONG)ForwardName;\r
 +\r
 +                    /* Snap the forwarder */\r
 +                    Status = MiSnapThunk(LdrEntry->DllBase,\r
 +                                         ImageBase,\r
 +                                         &ForwardThunk,\r
 +                                         &ForwardThunk,\r
 +                                         ForwardExportDirectory,\r
 +                                         ForwardExportSize,\r
 +                                         TRUE,\r
 +                                         &MissingForwarder);\r
 +\r
 +                    /* Free the forwarder name and set the thunk */\r
 +                    ExFreePool(ForwardName);\r
 +                    Address->u1 = ForwardThunk.u1;\r
 +                    break;\r
 +                }\r
 +\r
 +                /* Go to the next entry */\r
 +                NextEntry = NextEntry->Flink;\r
 +            }\r
 +\r
 +            /* Free the name */\r
 +            RtlFreeUnicodeString(&ForwarderName);\r
 +        }\r
 +    }\r
 +\r
 +    /* Return status */\r
 +    return Status;\r
 +}\r
 +\r
 +NTSTATUS\r
 +NTAPI\r
 +MmUnloadSystemImage(IN PVOID ImageHandle)\r
 +{\r
 +    PLDR_DATA_TABLE_ENTRY LdrEntry = ImageHandle;\r
 +    PVOID BaseAddress = LdrEntry->DllBase;\r
 +    NTSTATUS Status;\r
 +    ANSI_STRING TempName;\r
 +    BOOLEAN HadEntry = FALSE;\r
 +\r
 +    /* Acquire the loader lock */\r
 +    KeEnterCriticalRegion();\r
 +    KeWaitForSingleObject(&MmSystemLoadLock,\r
 +                          WrVirtualMemory,\r
 +                          KernelMode,\r
 +                          FALSE,\r
 +                          NULL);\r
 +\r
 +    /* Check if this driver was loaded at boot and didn't get imports parsed */\r
 +    if (LdrEntry->LoadedImports == (PVOID)-1) goto Done;\r
 +\r
 +    /* We should still be alive */\r
 +    ASSERT(LdrEntry->LoadCount != 0);\r
 +    LdrEntry->LoadCount--;\r
 +\r
 +    /* Check if we're still loaded */\r
 +    if (LdrEntry->LoadCount) goto Done;\r
 +\r
 +    /* We should cleanup... are symbols loaded */\r
 +    if (LdrEntry->Flags & LDRP_DEBUG_SYMBOLS_LOADED)\r
 +    {\r
 +        /* Create the ANSI name */\r
 +        Status = RtlUnicodeStringToAnsiString(&TempName,\r
 +                                              &LdrEntry->BaseDllName,\r
 +                                              TRUE);\r
 +        if (NT_SUCCESS(Status))\r
 +        {\r
 +            /* Unload the symbols */\r
 +            DbgUnLoadImageSymbols(&TempName, BaseAddress, -1);\r
 +            RtlFreeAnsiString(&TempName);\r
 +        }\r
 +    }\r
 +\r
 +    /* FIXME: Free the driver */\r
 +    //MmFreeSection(LdrEntry->DllBase);\r
 +\r
 +    /* Check if we're linked in */\r
 +    if (LdrEntry->InLoadOrderLinks.Flink)\r
 +    {\r
 +        /* Remove us */\r
 +        MiProcessLoaderEntry(LdrEntry, FALSE);\r
 +        HadEntry = TRUE;\r
 +    }\r
 +\r
 +    /* Dereference and clear the imports */\r
 +    MiDereferenceImports(LdrEntry->LoadedImports);\r
 +    MiClearImports(LdrEntry);\r
 +\r
 +    /* Check if the entry needs to go away */\r
 +    if (HadEntry)\r
 +    {\r
 +        /* Check if it had a name */\r
 +        if (LdrEntry->FullDllName.Buffer)\r
 +        {\r
 +            /* Free it */\r
 +            ExFreePool(LdrEntry->FullDllName.Buffer);\r
 +        }\r
 +\r
 +        /* Check if we had a section */\r
 +        if (LdrEntry->SectionPointer)\r
 +        {\r
 +            /* Dereference it */\r
 +            ObDereferenceObject(LdrEntry->SectionPointer);\r
 +        }\r
 +\r
 +        /* Free the entry */\r
 +        ExFreePool(LdrEntry);\r
 +    }\r
 +\r
 +    /* Release the system lock and return */\r
 +Done:\r
 +    KeReleaseMutant(&MmSystemLoadLock, 1, FALSE, FALSE);\r
 +    KeLeaveCriticalRegion();\r
 +    return STATUS_SUCCESS;\r
 +}\r
 +\r
 +NTSTATUS\r
 +NTAPI\r
 +MiResolveImageReferences(IN PVOID ImageBase,\r
 +                         IN PUNICODE_STRING ImageFileDirectory,\r
 +                         IN PUNICODE_STRING NamePrefix OPTIONAL,\r
 +                         OUT PCHAR *MissingApi,\r
 +                         OUT PWCHAR *MissingDriver,\r
 +                         OUT PLOAD_IMPORTS *LoadImports)\r
 +{\r
 +    PCHAR MissingApiBuffer = *MissingApi, ImportName;\r
 +    PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor, CurrentImport;\r
 +    ULONG ImportSize, ImportCount = 0, LoadedImportsSize, ExportSize;\r
 +    PLOAD_IMPORTS LoadedImports;\r
 +    ULONG GdiLink, NormalLink, i;\r
 +    BOOLEAN ReferenceNeeded, Loaded;\r
 +    ANSI_STRING TempString;\r
 +    UNICODE_STRING NameString, DllName;\r
 +    PLDR_DATA_TABLE_ENTRY LdrEntry = NULL, DllEntry, ImportEntry = NULL;\r
 +    PVOID ImportBase, DllBase;\r
 +    PLIST_ENTRY NextEntry;\r
 +    PIMAGE_EXPORT_DIRECTORY ExportDirectory;\r
 +    NTSTATUS Status;\r
 +    PIMAGE_THUNK_DATA OrigThunk, FirstThunk;\r
 +    PAGED_CODE();\r
 +    DPRINT("%s - ImageBase: %p. ImageFileDirectory: %wZ\n",\r
 +           __FUNCTION__, ImageBase, ImageFileDirectory);\r
 +\r
 +    /* Assume no imports */\r
 +    *LoadImports = (PVOID)-2;\r
 +\r
 +    /* Get the import descriptor */\r
 +    ImportDescriptor = RtlImageDirectoryEntryToData(ImageBase,\r
 +                                                    TRUE,\r
 +                                                    IMAGE_DIRECTORY_ENTRY_IMPORT,\r
 +                                                    &ImportSize);\r
 +    if (!ImportDescriptor) return STATUS_SUCCESS;\r
 +\r
 +    /* Loop all imports to count them */\r
 +    for (CurrentImport = ImportDescriptor;\r
 +         (CurrentImport->Name) && (CurrentImport->OriginalFirstThunk);\r
 +         CurrentImport++)\r
 +    {\r
 +        /* One more */\r
 +        ImportCount++;\r
 +    }\r
 +\r
 +    /* Make sure we have non-zero imports */\r
 +    if (ImportCount)\r
 +    {\r
 +        /* Calculate and allocate the list we'll need */\r
 +        LoadedImportsSize = ImportCount * sizeof(PVOID) + sizeof(SIZE_T);\r
 +        LoadedImports = ExAllocatePoolWithTag(PagedPool,\r
 +                                              LoadedImportsSize,\r
 +                                              TAG_LDR_WSTR);\r
 +        if (LoadedImports)\r
 +        {\r
 +            /* Zero it and set the count */\r
 +            RtlZeroMemory(LoadedImports, LoadedImportsSize);\r
 +            LoadedImports->Count = ImportCount;\r
 +        }\r
 +    }\r
 +    else\r
 +    {\r
 +        /* No table */\r
 +        LoadedImports = NULL;\r
 +    }\r
 +\r
 +    /* Reset the import count and loop descriptors again */\r
 +    ImportCount = GdiLink = NormalLink = 0;\r
 +    while ((ImportDescriptor->Name) && (ImportDescriptor->OriginalFirstThunk))\r
 +    {\r
 +        /* Get the name */\r
 +        ImportName = (PCHAR)((ULONG_PTR)ImageBase + ImportDescriptor->Name);\r
 +\r
 +        /* Check if this is a GDI driver */\r
 +        GdiLink = GdiLink |\r
 +                  !(_strnicmp(ImportName, "win32k", sizeof("win32k") - 1));\r
 +\r
 +        /* We can also allow dxapi */\r
 +        NormalLink = NormalLink |\r
 +                     ((_strnicmp(ImportName, "win32k", sizeof("win32k") - 1)) &&\r
 +                      (_strnicmp(ImportName, "dxapi", sizeof("dxapi") - 1)));\r
 +\r
 +        /* Check if this is a valid GDI driver */\r
 +        if ((GdiLink) && (NormalLink))\r
 +        {\r
 +            /* It's not, it's importing stuff it shouldn't be! */\r
 +            MiDereferenceImports(LoadedImports);\r
 +            if (LoadedImports) ExFreePool(LoadedImports);\r
 +            return STATUS_PROCEDURE_NOT_FOUND;\r
 +        }\r
 +\r
 +        /* Check if this is a "core" import, which doesn't get referenced */\r
 +        if (!(_strnicmp(ImportName, "ntoskrnl", sizeof("ntoskrnl") - 1)) ||\r
 +            !(_strnicmp(ImportName, "win32k", sizeof("win32k") - 1)) ||\r
 +            !(_strnicmp(ImportName, "hal", sizeof("hal") - 1)))\r
 +        {\r
 +            /* Don't reference this */\r
 +            ReferenceNeeded = FALSE;\r
 +        }\r
 +        else\r
 +        {\r
 +            /* Reference these modules */\r
 +            ReferenceNeeded = TRUE;\r
 +        }\r
 +\r
 +        /* Now setup a unicode string for the import */\r
 +        RtlInitAnsiString(&TempString, ImportName);\r
 +        Status = RtlAnsiStringToUnicodeString(&NameString, &TempString, TRUE);\r
 +        if (!NT_SUCCESS(Status))\r
 +        {\r
 +            /* Failed */\r
 +            MiDereferenceImports(LoadedImports);\r
 +            if (LoadedImports) ExFreePool(LoadedImports);\r
 +            return Status;\r
 +        }\r
 +\r
 +        /* We don't support name prefixes yet */\r
 +        if (NamePrefix) DPRINT1("Name Prefix not yet supported!\n");\r
 +\r
 +        /* Remember that we haven't loaded the import at this point */\r
 +CheckDllState:\r
 +        Loaded = FALSE;\r
 +        ImportBase = NULL;\r
 +\r
 +        /* Loop the driver list */\r
 +        NextEntry = PsLoadedModuleList.Flink;\r
 +        while (NextEntry != &PsLoadedModuleList)\r
 +        {\r
 +            /* Get the loader entry and compare the name */\r
 +            LdrEntry = CONTAINING_RECORD(NextEntry,\r
 +                                         LDR_DATA_TABLE_ENTRY,\r
 +                                         InLoadOrderLinks);\r
 +            if (RtlEqualUnicodeString(&NameString,\r
 +                                      &LdrEntry->BaseDllName,\r
 +                                      TRUE))\r
 +            {\r
 +                /* Get the base address */\r
 +                ImportBase = LdrEntry->DllBase;\r
 +\r
 +                /* Check if we haven't loaded yet, and we need references */\r
 +                if (!(Loaded) && (ReferenceNeeded))\r
 +                {\r
 +                    /* Make sure we're not already loading */\r
 +                    if (!(LdrEntry->Flags & LDRP_LOAD_IN_PROGRESS))\r
 +                    {\r
 +                        /* Increase the load count */\r
 +                        LdrEntry->LoadCount++;\r
 +                    }\r
 +                }\r
 +\r
 +                /* Done, break out */\r
 +                break;\r
 +            }\r
 +\r
 +            /* Go to the next entry */\r
 +            NextEntry = NextEntry->Flink;\r
 +        }\r
 +\r
 +        /* Check if we haven't loaded the import yet */\r
 +        if (!ImportBase)\r
 +        {\r
 +            /* Setup the import DLL name */\r
 +            DllName.MaximumLength = NameString.Length +\r
 +                                    ImageFileDirectory->Length +\r
 +                                    sizeof(UNICODE_NULL);\r
 +            DllName.Buffer = ExAllocatePoolWithTag(NonPagedPool,\r
 +                                                   DllName.MaximumLength,\r
 +                                                   TAG_LDR_WSTR);\r
 +            if (DllName.Buffer)\r
 +            {\r
 +                /* Setup the base length and copy it */\r
 +                DllName.Length = ImageFileDirectory->Length;\r
 +                RtlCopyMemory(DllName.Buffer,\r
 +                              ImageFileDirectory->Buffer,\r
 +                              ImageFileDirectory->Length);\r
 +\r
 +                /* Now add the import name and null-terminate it */\r
 +                RtlAppendStringToString((PSTRING)&DllName,\r
 +                                        (PSTRING)&NameString);\r
 +                DllName.Buffer[(DllName.MaximumLength - 1) / 2] = UNICODE_NULL;\r
 +\r
 +                /* Load the image */\r
 +                Status = MmLoadSystemImage(&DllName,\r
 +                                           NamePrefix,\r
 +                                           NULL,\r
 +                                           0,\r
 +                                           (PVOID)&DllEntry,\r
 +                                           &DllBase);\r
 +                if (NT_SUCCESS(Status))\r
 +                {\r
 +                    /* We can free the DLL Name */\r
 +                    ExFreePool(DllName.Buffer);\r
 +                }\r
 +                else\r
 +                {\r
 +                    /* Fill out the information for the error */\r
 +                    *MissingDriver = DllName.Buffer;\r
 +                    *(PULONG)MissingDriver |= 1;\r
 +                    *MissingApi = NULL;\r
 +                }\r
 +            }\r
 +            else\r
 +            {\r
 +                /* We're out of resources */\r
 +                Status = STATUS_INSUFFICIENT_RESOURCES;\r
 +            }\r
 +\r
 +            /* Check if we're OK until now */\r
 +            if (NT_SUCCESS(Status))\r
 +            {\r
 +                /* We're now loaded */\r
 +                Loaded = TRUE;\r
 +\r
 +                /* Sanity check */\r
 +                ASSERT(DllBase = DllEntry->DllBase);\r
 +\r
 +                /* Call the initialization routines */\r
 +                Status = MmCallDllInitialize(DllEntry, &PsLoadedModuleList);\r
 +                if (!NT_SUCCESS(Status))\r
 +                {\r
 +                    /* We failed, unload the image */\r
 +                    MmUnloadSystemImage(DllEntry);\r
 +                    while (TRUE);\r
 +                    Loaded = FALSE;\r
 +                }\r
 +            }\r
 +\r
 +            /* Check if we failed by here */\r
 +            if (!NT_SUCCESS(Status))\r
 +            {\r
 +                /* Cleanup and return */\r
 +                RtlFreeUnicodeString(&NameString);\r
 +                MiDereferenceImports(LoadedImports);\r
 +                if (LoadedImports) ExFreePool(LoadedImports);\r
 +                return Status;\r
 +            }\r
 +\r
 +            /* Loop again to make sure that everything is OK */\r
 +            goto CheckDllState;\r
 +        }\r
 +\r
 +        /* Check if we're support to reference this import */\r
 +        if ((ReferenceNeeded) && (LoadedImports))\r
 +        {\r
 +            /* Make sure we're not already loading */\r
 +            if (!(LdrEntry->Flags & LDRP_LOAD_IN_PROGRESS))\r
 +            {\r
 +                /* Add the entry */\r
 +                LoadedImports->Entry[ImportCount] = LdrEntry;\r
 +                ImportCount++;\r
 +            }\r
 +        }\r
 +\r
 +        /* Free the import name */\r
 +        RtlFreeUnicodeString(&NameString);\r
 +\r
 +        /* Set the missing driver name and get the export directory */\r
 +        *MissingDriver = LdrEntry->BaseDllName.Buffer;\r
 +        ExportDirectory = RtlImageDirectoryEntryToData(ImportBase,\r
 +                                                       TRUE,\r
 +                                                       IMAGE_DIRECTORY_ENTRY_EXPORT,\r
 +                                                       &ExportSize);\r
 +        if (!ExportDirectory)\r
 +        {\r
 +            /* Cleanup and return */\r
 +            MiDereferenceImports(LoadedImports);\r
 +            if (LoadedImports) ExFreePool(LoadedImports);\r
 +            return STATUS_DRIVER_ENTRYPOINT_NOT_FOUND;\r
 +        }\r
 +\r
 +        /* Make sure we have an IAT */\r
 +        if (ImportDescriptor->OriginalFirstThunk)\r
 +        {\r
 +            /* Get the first thunks */\r
 +            OrigThunk = (PVOID)((ULONG_PTR)ImageBase +\r
 +                                ImportDescriptor->OriginalFirstThunk);\r
 +            FirstThunk = (PVOID)((ULONG_PTR)ImageBase +\r
 +                                 ImportDescriptor->FirstThunk);\r
 +\r
 +            /* Loop the IAT */\r
 +            while (OrigThunk->u1.AddressOfData)\r
 +            {\r
 +                /* Snap thunk */\r
 +                Status = MiSnapThunk(ImportBase,\r
 +                                     ImageBase,\r
 +                                     OrigThunk++,\r
 +                                     FirstThunk++,\r
 +                                     ExportDirectory,\r
 +                                     ExportSize,\r
 +                                     FALSE,\r
 +                                     MissingApi);\r
 +                if (!NT_SUCCESS(Status))\r
 +                {\r
 +                    /* Cleanup and return */\r
 +                    MiDereferenceImports(LoadedImports);\r
 +                    if (LoadedImports) ExFreePool(LoadedImports);\r
 +                    return Status;\r
 +                }\r
 +\r
 +                /* Reset the buffer */\r
 +                *MissingApi = MissingApiBuffer;\r
 +            }\r
 +        }\r
 +\r
 +        /* Go to the next import */\r
 +        ImportDescriptor++;\r
 +    }\r
 +\r
 +    /* Check if we have an import list */\r
 +    if (LoadedImports)\r
 +    {\r
 +        /* Reset the count again, and loop entries*/\r
 +        ImportCount = 0;\r
 +        for (i = 0; i < LoadedImports->Count; i++)\r
 +        {\r
 +            if (LoadedImports->Entry[i])\r
 +            {\r
 +                /* Got an entry, OR it with 1 in case it's the single entry */\r
 +                ImportEntry = (PVOID)((ULONG_PTR)LoadedImports->Entry[i] | 1);\r
 +                ImportCount++;\r
 +            }\r
 +        }\r
 +\r
 +        /* Check if we had no imports */\r
 +        if (!ImportCount)\r
 +        {\r
 +            /* Free the list and set it to no imports */\r
 +            ExFreePool(LoadedImports);\r
 +            LoadedImports = (PVOID)-2;\r
 +        }\r
 +        else if (ImportCount == 1)\r
 +        {\r
 +            /* Just one entry, we can free the table and only use our entry */\r
 +            ExFreePool(LoadedImports);\r
 +            LoadedImports = (PLOAD_IMPORTS)ImportEntry;\r
 +        }\r
 +        else if (ImportCount != LoadedImports->Count)\r
 +        {\r
 +            /* FIXME: Can this happen? */\r
 +            DPRINT1("Unhandled scenario\n");\r
 +            while (TRUE);\r
 +        }\r
 +\r
 +        /* Return the list */\r
 +        *LoadImports = LoadedImports;\r
 +    }\r
 +\r
 +    /* Return success */\r
 +    return STATUS_SUCCESS;\r
 +}\r
 +\r
 +VOID\r
 +NTAPI\r
 +MiReloadBootLoadedDrivers(IN PLOADER_PARAMETER_BLOCK LoaderBlock)\r
 +{\r
 +    PLIST_ENTRY NextEntry;\r
 +    ULONG i = 0;\r
 +    PIMAGE_NT_HEADERS NtHeader;\r
 +    PLDR_DATA_TABLE_ENTRY LdrEntry;\r
 +    PIMAGE_FILE_HEADER FileHeader;\r
 +    BOOLEAN ValidRelocs;\r
 +    PIMAGE_DATA_DIRECTORY DataDirectory;\r
 +    PVOID DllBase, NewImageAddress;\r
 +    NTSTATUS Status;\r
 +\r
 +    /* Loop driver list */\r
 +    for (NextEntry = LoaderBlock->LoadOrderListHead.Flink;\r
 +         NextEntry != &LoaderBlock->LoadOrderListHead;\r
 +         NextEntry = NextEntry->Flink)\r
 +    {\r
 +        /* Get the loader entry and NT header */\r
 +        LdrEntry = CONTAINING_RECORD(NextEntry,\r
 +                                     LDR_DATA_TABLE_ENTRY,\r
 +                                     InLoadOrderLinks);\r
 +        NtHeader = RtlImageNtHeader(LdrEntry->DllBase);\r
 +\r
 +        /* Debug info */\r
 +        DPRINT("[Mm0]: Driver at: %p ending at: %p for module: %wZ\n",\r
 +                LdrEntry->DllBase,\r
 +                (ULONG_PTR)LdrEntry->DllBase+ LdrEntry->SizeOfImage,\r
 +                &LdrEntry->FullDllName);\r
 +\r
 +        /* Skip kernel and HAL */\r
 +        /* ROS HACK: Skip BOOTVID/KDCOM too */\r
 +        i++;\r
 +        if (i <= 4) continue;\r
 +\r
 +        /* Skip non-drivers */\r
 +        if (!NtHeader) continue;\r
 +\r
 +        /* Get the file header and make sure we can relocate */\r
 +        FileHeader = &NtHeader->FileHeader;\r
 +        if (FileHeader->Characteristics & IMAGE_FILE_RELOCS_STRIPPED) continue;\r
 +        if (NtHeader->OptionalHeader.NumberOfRvaAndSizes <\r
 +            IMAGE_DIRECTORY_ENTRY_BASERELOC) continue;\r
 +\r
 +        /* Everything made sense until now, check the relocation section too */\r
 +        DataDirectory = &NtHeader->OptionalHeader.\r
 +                        DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];\r
 +        if (!DataDirectory->VirtualAddress)\r
 +        {\r
 +            /* We don't really have relocations */\r
 +            ValidRelocs = FALSE;\r
 +        }\r
 +        else\r
 +        {\r
 +            /* Make sure the size is valid */\r
 +            if ((DataDirectory->VirtualAddress + DataDirectory->Size) >\r
 +                LdrEntry->SizeOfImage)\r
 +            {\r
 +                /* They're not, skip */\r
 +                continue;\r
 +            }\r
 +\r
 +            /* We have relocations */\r
 +            ValidRelocs = TRUE;\r
 +        }\r
 +\r
 +        /* Remember the original address */\r
 +        DllBase = LdrEntry->DllBase;\r
 +\r
 +        /*  Allocate a virtual section for the module  */\r
 +        NewImageAddress = MmAllocateSection(LdrEntry->SizeOfImage, NULL);\r
 +        if (!NewImageAddress)\r
 +        {\r
 +            /* Shouldn't happen */\r
 +            DPRINT1("[Mm0]: Couldn't allocate driver section!\n");\r
 +            while (TRUE);\r
 +        }\r
 +\r
 +        /* Sanity check */\r
 +        DPRINT("[Mm0]: Copying from: %p to: %p\n", DllBase, NewImageAddress);\r
 +        ASSERT(ExpInitializationPhase == 0);\r
 +\r
 +        /* Now copy the entire driver over */\r
 +        RtlCopyMemory(NewImageAddress, DllBase, LdrEntry->SizeOfImage);\r
 +\r
 +        /* Sanity check */\r
 +        ASSERT(*(PULONG)NewImageAddress == *(PULONG)DllBase);\r
 +\r
 +        /* Set the image base to the old address */\r
 +        NtHeader->OptionalHeader.ImageBase = (ULONG_PTR)DllBase;\r
 +\r
 +        /* Check if we had relocations */\r
 +        if (ValidRelocs)\r
 +        {\r
 +            /* Relocate the image */\r
 +            Status = LdrRelocateImageWithBias(NewImageAddress,\r
 +                                              0,\r
 +                                              "SYSLDR",\r
 +                                              STATUS_SUCCESS,\r
 +                                              STATUS_CONFLICTING_ADDRESSES,\r
 +                                              STATUS_INVALID_IMAGE_FORMAT);\r
 +            if (!NT_SUCCESS(Status))\r
 +            {\r
 +                /* This shouldn't happen */\r
 +                DPRINT1("Relocations failed!\n");\r
 +                while (TRUE);\r
 +            }\r
 +        }\r
 +\r
 +        /* Update the loader entry */\r
 +        LdrEntry->DllBase = NewImageAddress;\r
 +\r
 +        /* Update the thunks */\r
 +        DPRINT("[Mm0]: Updating thunks to: %wZ\n", &LdrEntry->BaseDllName);\r
 +        MiUpdateThunks(LoaderBlock,\r
 +                       DllBase,\r
 +                       NewImageAddress,\r
 +                       LdrEntry->SizeOfImage);\r
 +\r
 +        /* Update the loader entry */\r
 +        LdrEntry->Flags |= 0x01000000;\r
 +        LdrEntry->EntryPoint = (PVOID)((ULONG_PTR)NewImageAddress +\r
 +                                NtHeader->OptionalHeader.AddressOfEntryPoint);\r
 +        LdrEntry->SizeOfImage = LdrEntry->SizeOfImage;\r
 +\r
 +        /* Free the old copy */\r
 +        MiFreeBootDriverMemory(DllBase, LdrEntry->SizeOfImage);\r
 +    }\r
 +}\r
 +\r
 +BOOLEAN\r
 +NTAPI\r
 +MiInitializeLoadedModuleList(IN PLOADER_PARAMETER_BLOCK LoaderBlock)\r
 +{\r
 +    PLDR_DATA_TABLE_ENTRY LdrEntry, NewEntry;\r
 +    PLIST_ENTRY ListHead, NextEntry;\r
 +    ULONG EntrySize;\r
 +\r
 +    /* Setup the loaded module list and lock */\r
 +    KeInitializeSpinLock(&PsLoadedModuleSpinLock);\r
 +    InitializeListHead(&PsLoadedModuleList);\r
 +\r
 +    /* Get loop variables and the kernel entry */\r
 +    ListHead = &LoaderBlock->LoadOrderListHead;\r
 +    NextEntry = ListHead->Flink;\r
 +    LdrEntry = CONTAINING_RECORD(NextEntry,\r
 +                                 LDR_DATA_TABLE_ENTRY,\r
 +                                 InLoadOrderLinks);\r
++    PsNtosImageBase = (ULONG)LdrEntry->DllBase;\r
 +\r
 +    /* Loop the loader block */\r
 +    while (NextEntry != ListHead)\r
 +    {\r
 +        /* Get the loader entry */\r
 +        LdrEntry = CONTAINING_RECORD(NextEntry,\r
 +                                     LDR_DATA_TABLE_ENTRY,\r
 +                                     InLoadOrderLinks);\r
 +\r
 +        /* FIXME: ROS HACK. Make sure this is a driver */\r
 +        if (!RtlImageNtHeader(LdrEntry->DllBase))\r
 +        {\r
 +            /* Skip this entry */\r
 +            NextEntry= NextEntry->Flink;\r
 +            continue;\r
 +        }\r
 +\r
 +        /* Calculate the size we'll need and allocate a copy */\r
 +        EntrySize = sizeof(LDR_DATA_TABLE_ENTRY) +\r
 +                    LdrEntry->BaseDllName.MaximumLength +\r
 +                    sizeof(UNICODE_NULL);\r
 +        NewEntry = ExAllocatePoolWithTag(NonPagedPool, EntrySize, TAG_LDR_WSTR);\r
 +        if (!NewEntry) return FALSE;\r
 +\r
 +        /* Copy the entry over */\r
 +        *NewEntry = *LdrEntry;\r
 +\r
 +        /* Allocate the name */\r
 +        NewEntry->FullDllName.Buffer =\r
 +            ExAllocatePoolWithTag(PagedPool,\r
 +                                  LdrEntry->FullDllName.MaximumLength +\r
 +                                  sizeof(UNICODE_NULL),\r
 +                                  TAG_LDR_WSTR);\r
 +        if (!NewEntry->FullDllName.Buffer) return FALSE;\r
 +\r
 +        /* Set the base name */\r
 +        NewEntry->BaseDllName.Buffer = (PVOID)(NewEntry + 1);\r
 +\r
 +        /* Copy the full and base name */\r
 +        RtlCopyMemory(NewEntry->FullDllName.Buffer,\r
 +                      LdrEntry->FullDllName.Buffer,\r
 +                      LdrEntry->FullDllName.MaximumLength);\r
 +        RtlCopyMemory(NewEntry->BaseDllName.Buffer,\r
 +                      LdrEntry->BaseDllName.Buffer,\r
 +                      LdrEntry->BaseDllName.MaximumLength);\r
 +\r
 +        /* Null-terminate the base name */\r
 +        NewEntry->BaseDllName.Buffer[NewEntry->BaseDllName.Length /\r
 +                                     sizeof(WCHAR)] = UNICODE_NULL;\r
 +\r
 +        /* Insert the entry into the list */\r
 +        InsertTailList(&PsLoadedModuleList, &NewEntry->InLoadOrderLinks);\r
 +        NextEntry = NextEntry->Flink;\r
 +    }\r
 +\r
 +    /* Build the import lists for the boot drivers */\r
 +    //MiBuildImportsForBootDrivers();\r
 +\r
 +    /* We're done */\r
 +    return TRUE;\r
 +}\r
 +\r
 +BOOLEAN\r
 +NTAPI\r
 +MmVerifyImageIsOkForMpUse(IN PVOID BaseAddress)\r
 +{\r
 +    PIMAGE_NT_HEADERS NtHeader;\r
 +    PAGED_CODE();\r
 +\r
 +    /* Get NT Headers */\r
 +    NtHeader = RtlImageNtHeader(BaseAddress);\r
 +    if (NtHeader)\r
 +    {\r
 +        /* Check if this image is only safe for UP while we have 2+ CPUs */\r
 +        if ((KeNumberProcessors > 1) &&\r
 +            (NtHeader->FileHeader.Characteristics & IMAGE_FILE_UP_SYSTEM_ONLY))\r
 +        {\r
 +            /* Fail */\r
 +            return FALSE;\r
 +        }\r
 +    }\r
 +\r
 +    /* Otherwise, it's safe */\r
 +    return TRUE;\r
 +}\r
 +\r
 +NTSTATUS\r
 +NTAPI\r
 +MmCheckSystemImage(IN HANDLE ImageHandle,\r
 +                   IN BOOLEAN PurgeSection)\r
 +{\r
 +    NTSTATUS Status;\r
 +    HANDLE SectionHandle;\r
 +    PVOID ViewBase = NULL;\r
 +    SIZE_T ViewSize = 0;\r
 +    IO_STATUS_BLOCK IoStatusBlock;\r
 +    FILE_STANDARD_INFORMATION FileStandardInfo;\r
 +    KAPC_STATE ApcState;\r
 +    PAGED_CODE();\r
 +\r
 +    /* Create a section for the DLL */\r
 +    Status = ZwCreateSection(&SectionHandle,\r
 +                             SECTION_MAP_EXECUTE,\r
 +                             NULL,\r
 +                             NULL,\r
 +                             PAGE_EXECUTE,\r
 +                             SEC_COMMIT,\r
 +                             ImageHandle);\r
 +    if (!NT_SUCCESS(Status)) return Status;\r
 +\r
 +    /* Make sure we're in the system process */\r
 +    KeStackAttachProcess(&PsInitialSystemProcess->Pcb, &ApcState);\r
 +\r
 +    /* Map it */\r
 +    Status = ZwMapViewOfSection(SectionHandle,\r
 +                                NtCurrentProcess(),\r
 +                                &ViewBase,\r
 +                                0,\r
 +                                0,\r
 +                                NULL,\r
 +                                &ViewSize,\r
 +                                ViewShare,\r
 +                                0,\r
 +                                PAGE_EXECUTE);\r
 +    if (!NT_SUCCESS(Status))\r
 +    {\r
 +        /* We failed, close the handle and return */\r
 +        KeUnstackDetachProcess(&ApcState);\r
 +        ZwClose(SectionHandle);\r
 +        return Status;\r
 +    }\r
 +\r
 +    /* Now query image information */\r
 +    Status = ZwQueryInformationFile(ImageHandle,\r
 +                                    &IoStatusBlock,\r
 +                                    &FileStandardInfo,\r
 +                                    sizeof(FileStandardInfo),\r
 +                                    FileStandardInformation);\r
 +    if ( NT_SUCCESS(Status) )\r
 +    {\r
 +        /* First, verify the checksum */\r
 +        if (!LdrVerifyMappedImageMatchesChecksum(ViewBase,\r
 +                                                 FileStandardInfo.\r
 +                                                 EndOfFile.LowPart,\r
 +                                                 FileStandardInfo.\r
 +                                                 EndOfFile.LowPart))\r
 +        {\r
 +            /* Set checksum failure */\r
 +            Status = STATUS_IMAGE_CHECKSUM_MISMATCH;\r
 +        }\r
 +\r
 +        /* Check that it's a valid SMP image if we have more then one CPU */\r
 +        if (!MmVerifyImageIsOkForMpUse(ViewBase))\r
 +        {\r
 +            /* Otherwise it's not the right image */\r
 +            Status = STATUS_IMAGE_MP_UP_MISMATCH;\r
 +        }\r
 +    }\r
 +\r
 +    /* Unmap the section, close the handle, and return status */\r
 +    ZwUnmapViewOfSection(NtCurrentProcess(), ViewBase);\r
 +    KeUnstackDetachProcess(&ApcState);\r
 +    ZwClose(SectionHandle);\r
 +    return Status;\r
 +}\r
 +\r
 +NTSTATUS\r
 +NTAPI\r
 +MmLoadSystemImage(IN PUNICODE_STRING FileName,\r
 +                  IN PUNICODE_STRING NamePrefix OPTIONAL,\r
 +                  IN PUNICODE_STRING LoadedName OPTIONAL,\r
 +                  IN ULONG Flags,\r
 +                  OUT PVOID *ModuleObject,\r
 +                  OUT PVOID *ImageBaseAddress)\r
 +{\r
 +    PVOID ModuleLoadBase = NULL;\r
 +    NTSTATUS Status;\r
 +    HANDLE FileHandle = NULL;\r
 +    OBJECT_ATTRIBUTES ObjectAttributes;\r
 +    IO_STATUS_BLOCK IoStatusBlock;\r
 +    PIMAGE_NT_HEADERS NtHeader;\r
 +    UNICODE_STRING BaseName, BaseDirectory, PrefixName;\r
 +    PLDR_DATA_TABLE_ENTRY LdrEntry = NULL;\r
 +    ULONG EntrySize;\r
 +    PLOAD_IMPORTS LoadedImports = (PVOID)-2;\r
 +    PCHAR MissingApiName, Buffer;\r
 +    PWCHAR MissingDriverName;\r
 +    HANDLE SectionHandle;\r
 +    ACCESS_MASK DesiredAccess;\r
 +    PVOID Section = NULL;\r
 +    BOOLEAN LockOwned = FALSE;\r
 +    PLIST_ENTRY NextEntry;\r
 +    PAGED_CODE();\r
 +\r
 +    /* Detect session-load */\r
 +    if (Flags)\r
 +    {\r
 +        /* Sanity checks */\r
 +        ASSERT(NamePrefix == NULL);\r
 +        ASSERT(LoadedName == NULL);\r
 +\r
 +        /* Make sure the process is in session too */\r
 +        if (!PsGetCurrentProcess()->ProcessInSession) return STATUS_NO_MEMORY;\r
 +    }\r
 +\r
 +    if (ModuleObject) *ModuleObject = NULL;\r
 +    if (ImageBaseAddress) *ImageBaseAddress = NULL;\r
 +\r
 +    /* Allocate a buffer we'll use for names */\r
 +    Buffer = ExAllocatePoolWithTag(NonPagedPool, MAX_PATH, TAG_LDR_WSTR);\r
 +    if (!Buffer) return STATUS_INSUFFICIENT_RESOURCES;\r
 +\r
 +    /* Check for a separator */\r
 +    if (FileName->Buffer[0] == OBJ_NAME_PATH_SEPARATOR)\r
 +    {\r
 +        PWCHAR p;\r
 +        ULONG BaseLength;\r
 +\r
 +        /* Loop the path until we get to the base name */\r
 +        p = &FileName->Buffer[FileName->Length / sizeof(WCHAR)];\r
 +        while (*(p - 1) != OBJ_NAME_PATH_SEPARATOR) p--;\r
 +\r
 +        /* Get the length */\r
 +        BaseLength = (ULONG)(&FileName->Buffer[FileName->Length / sizeof(WCHAR)] - p);\r
 +        BaseLength *= sizeof(WCHAR);\r
 +\r
 +        /* Setup the string */\r
 +        BaseName.Length = (USHORT)BaseLength;\r
 +        BaseName.Buffer = p;\r
 +    }\r
 +    else\r
 +    {\r
 +        /* Otherwise, we already have a base name */\r
 +        BaseName.Length = FileName->Length;\r
 +        BaseName.Buffer = FileName->Buffer;\r
 +    }\r
 +\r
 +    /* Setup the maximum length */\r
 +    BaseName.MaximumLength = BaseName.Length;\r
 +\r
 +    /* Now compute the base directory */\r
 +    BaseDirectory = *FileName;\r
 +    BaseDirectory.Length -= BaseName.Length;\r
 +    BaseDirectory.MaximumLength = BaseDirectory.Length;\r
 +\r
 +    /* And the prefix, which for now is just the name itself */\r
 +    PrefixName = *FileName;\r
 +\r
 +    /* Check if we have a prefix */\r
 +    if (NamePrefix) DPRINT1("Prefixed images are not yet supported!\n");\r
 +\r
 +    /* Check if we already have a name, use it instead */\r
 +    if (LoadedName) BaseName = *LoadedName;\r
 +\r
 +    /* Acquire the load lock */\r
 +LoaderScan:\r
 +    ASSERT(LockOwned == FALSE);\r
 +    LockOwned = TRUE;\r
 +    KeEnterCriticalRegion();\r
 +    KeWaitForSingleObject(&MmSystemLoadLock,\r
 +                          WrVirtualMemory,\r
 +                          KernelMode,\r
 +                          FALSE,\r
 +                          NULL);\r
 +\r
 +    /* Scan the module list */\r
 +    NextEntry = PsLoadedModuleList.Flink;\r
 +    while (NextEntry != &PsLoadedModuleList)\r
 +    {\r
 +        /* Get the entry and compare the names */\r
 +        LdrEntry = CONTAINING_RECORD(NextEntry,\r
 +                                     LDR_DATA_TABLE_ENTRY,\r
 +                                     InLoadOrderLinks);\r
 +        if (RtlEqualUnicodeString(&PrefixName, &LdrEntry->FullDllName, TRUE))\r
 +        {\r
 +            /* Found it, break out */\r
 +            break;\r
 +        }\r
 +\r
 +        /* Keep scanning */\r
 +        NextEntry = NextEntry->Flink;\r
 +    }\r
 +\r
 +    /* Check if we found the image */\r
 +    if (NextEntry != &PsLoadedModuleList)\r
 +    {\r
 +        /* Check if we had already mapped a section */\r
 +        if (Section)\r
 +        {\r
 +            /* Dereference and clear */\r
 +            ObDereferenceObject(Section);\r
 +            Section = NULL;\r
 +        }\r
 +\r
 +        /* Check if this was supposed to be a session load */\r
 +        if (!Flags)\r
 +        {\r
 +            /* It wasn't, so just return the data */\r
 +            if (ModuleObject) *ModuleObject = LdrEntry;\r
 +            if (ImageBaseAddress) *ImageBaseAddress = LdrEntry->DllBase;\r
 +            Status = STATUS_IMAGE_ALREADY_LOADED;\r
 +        }\r
 +        else\r
 +        {\r
 +            /* We don't support session loading yet */\r
 +            DPRINT1("Unsupported Session-Load!\n");\r
 +            while (TRUE);\r
 +        }\r
 +\r
 +        /* Do cleanup */\r
 +        goto Quickie;\r
 +    }\r
 +    else if (!Section)\r
 +    {\r
 +        /* It wasn't loaded, and we didn't have a previous attempt */\r
 +        KeReleaseMutant(&MmSystemLoadLock, 1, FALSE, FALSE);\r
 +        KeLeaveCriticalRegion();\r
 +        LockOwned = FALSE;\r
 +\r
 +        /* Check if KD is enabled */\r
 +        if ((KdDebuggerEnabled) && !(KdDebuggerNotPresent))\r
 +        {\r
 +            /* FIXME: Attempt to get image from KD */\r
 +        }\r
 +\r
 +        /* We don't have a valid entry */\r
 +        LdrEntry = NULL;\r
 +\r
 +        /* Setup image attributes */\r
 +        InitializeObjectAttributes(&ObjectAttributes,\r
 +                                   FileName,\r
 +                                   OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,\r
 +                                   NULL,\r
 +                                   NULL);\r
 +\r
 +        /* Open the image */\r
 +        Status = ZwOpenFile(&FileHandle,\r
 +                            FILE_EXECUTE,\r
 +                            &ObjectAttributes,\r
 +                            &IoStatusBlock,\r
 +                            FILE_SHARE_READ | FILE_SHARE_DELETE,\r
 +                            0);\r
 +        if (!NT_SUCCESS(Status)) goto Quickie;\r
 +\r
 +        /* Validate it */\r
 +        Status = MmCheckSystemImage(FileHandle, FALSE);\r
 +        if ((Status == STATUS_IMAGE_CHECKSUM_MISMATCH) ||\r
 +            (Status == STATUS_IMAGE_MP_UP_MISMATCH) ||\r
 +            (Status == STATUS_INVALID_IMAGE_FORMAT))\r
 +        {\r
 +            /* Fail loading */\r
 +            goto Quickie;\r
 +        }\r
 +\r
 +        /* Check if this is a session-load */\r
 +        if (Flags)\r
 +        {\r
 +            /* Then we only need read and execute */\r
 +            DesiredAccess = SECTION_MAP_READ | SECTION_MAP_EXECUTE;\r
 +        }\r
 +        else\r
 +        {\r
 +            /* Otherwise, we can allow write access */\r
 +            DesiredAccess = SECTION_ALL_ACCESS;\r
 +        }\r
 +\r
 +        /* Initialize the attributes for the section */\r
 +        InitializeObjectAttributes(&ObjectAttributes,\r
 +                                   NULL,\r
 +                                   OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,\r
 +                                   NULL,\r
 +                                   NULL);\r
 +\r
 +        /* Create the section */\r
 +        Status = ZwCreateSection(&SectionHandle,\r
 +                                 DesiredAccess,\r
 +                                 &ObjectAttributes,\r
 +                                 NULL,\r
 +                                 PAGE_EXECUTE,\r
 +                                 SEC_IMAGE,\r
 +                                 FileHandle);\r
 +        if (!NT_SUCCESS(Status)) goto Quickie;\r
 +\r
 +        /* Now get the section pointer */\r
 +        Status = ObReferenceObjectByHandle(SectionHandle,\r
 +                                           SECTION_MAP_EXECUTE,\r
 +                                           MmSectionObjectType,\r
 +                                           KernelMode,\r
 +                                           &Section,\r
 +                                           NULL);\r
 +        ZwClose(SectionHandle);\r
 +        if (!NT_SUCCESS(Status)) goto Quickie;\r
 +\r
 +        /* Check if this was supposed to be a session-load */\r
 +        if (Flags)\r
 +        {\r
 +            /* We don't support session loading yet */\r
 +            DPRINT1("Unsupported Session-Load!\n");\r
 +            while (TRUE);\r
 +        }\r
 +\r
 +        /* Check the loader list again, we should end up in the path below */\r
 +        goto LoaderScan;\r
 +    }\r
 +    else\r
 +    {\r
 +        /* We don't have a valid entry */\r
 +        LdrEntry = NULL;\r
 +    }\r
 +\r
 +    /* Load the image */\r
 +    Status = MiLoadImageSection(&Section,\r
 +                                &ModuleLoadBase,\r
 +                                FileName,\r
 +                                FALSE,\r
 +                                NULL);\r
 +    ASSERT(Status != STATUS_ALREADY_COMMITTED);\r
 +\r
 +    /* Get the NT Header */\r
 +    NtHeader = RtlImageNtHeader(ModuleLoadBase);\r
 +\r
 +    /* Relocate the driver */\r
 +    Status = LdrRelocateImageWithBias(ModuleLoadBase,\r
 +                                      0,\r
 +                                      "SYSLDR",\r
 +                                      STATUS_SUCCESS,\r
 +                                      STATUS_CONFLICTING_ADDRESSES,\r
 +                                      STATUS_INVALID_IMAGE_FORMAT);\r
 +    if (!NT_SUCCESS(Status)) goto Quickie;\r
 +\r
 +    /* Calculate the size we'll need for the entry and allocate it */\r
 +    EntrySize = sizeof(LDR_DATA_TABLE_ENTRY) +\r
 +                BaseName.Length +\r
 +                sizeof(UNICODE_NULL);\r
 +\r
 +    /* Allocate the entry */\r
 +    LdrEntry = ExAllocatePoolWithTag(NonPagedPool, EntrySize, TAG_MODULE_OBJECT);\r
 +    if (!LdrEntry)\r
 +    {\r
 +        /* Fail */\r
 +        Status = STATUS_INSUFFICIENT_RESOURCES;\r
 +        goto Quickie;\r
 +    }\r
 +\r
 +    /* Setup the entry */\r
 +    LdrEntry->Flags = LDRP_LOAD_IN_PROGRESS;\r
 +    LdrEntry->LoadCount = 1;\r
 +    LdrEntry->LoadedImports = LoadedImports;\r
 +    LdrEntry->PatchInformation = NULL;\r
 +\r
 +    /* Check the version */\r
 +    if ((NtHeader->OptionalHeader.MajorOperatingSystemVersion >= 5) &&\r
 +        (NtHeader->OptionalHeader.MajorImageVersion >= 5))\r
 +    {\r
 +        /* Mark this image as a native image */\r
 +        LdrEntry->Flags |= 0x80000000;\r
 +    }\r
 +\r
 +    /* Setup the rest of the entry */\r
 +    LdrEntry->DllBase = ModuleLoadBase;\r
 +    LdrEntry->EntryPoint = (PVOID)((ULONG_PTR)ModuleLoadBase +\r
 +                                   NtHeader->OptionalHeader.AddressOfEntryPoint);\r
 +    LdrEntry->SizeOfImage = ((PROS_SECTION_OBJECT)Section)->ImageSection->ImageSize;\r
 +    LdrEntry->CheckSum = NtHeader->OptionalHeader.CheckSum;\r
 +    LdrEntry->SectionPointer = LdrEntry;\r
 +\r
 +    /* Now write the DLL name */\r
 +    LdrEntry->BaseDllName.Buffer = (PVOID)(LdrEntry + 1);\r
 +    LdrEntry->BaseDllName.Length = BaseName.Length;\r
 +    LdrEntry->BaseDllName.MaximumLength = BaseName.Length;\r
 +\r
 +    /* Copy and null-terminate it */\r
 +    RtlCopyMemory(LdrEntry->BaseDllName.Buffer,\r
 +                  BaseName.Buffer,\r
 +                  BaseName.Length);\r
 +    LdrEntry->BaseDllName.Buffer[BaseName.Length / 2] = UNICODE_NULL;\r
 +\r
 +    /* Now allocate the full name */\r
 +    LdrEntry->FullDllName.Buffer = ExAllocatePoolWithTag(PagedPool,\r
 +                                                         PrefixName.Length +\r
 +                                                         sizeof(UNICODE_NULL),\r
 +                                                         TAG_LDR_WSTR);\r
 +    if (!LdrEntry->FullDllName.Buffer)\r
 +    {\r
 +        /* Don't fail, just set it to zero */\r
 +        LdrEntry->FullDllName.Length = 0;\r
 +        LdrEntry->FullDllName.MaximumLength = 0;\r
 +    }\r
 +    else\r
 +    {\r
 +        /* Set it up */\r
 +        LdrEntry->FullDllName.Length = PrefixName.Length;\r
 +        LdrEntry->FullDllName.MaximumLength = PrefixName.Length;\r
 +\r
 +        /* Copy and null-terminate */\r
 +        RtlCopyMemory(LdrEntry->FullDllName.Buffer,\r
 +                      PrefixName.Buffer,\r
 +                      PrefixName.Length);\r
 +        LdrEntry->FullDllName.Buffer[PrefixName.Length / 2] = UNICODE_NULL;\r
 +    }\r
 +\r
 +    /* Add the entry */\r
 +    MiProcessLoaderEntry(LdrEntry, TRUE);\r
 +\r
 +    /* Resolve imports */\r
 +    MissingApiName = Buffer;\r
 +    Status = MiResolveImageReferences(ModuleLoadBase,\r
 +                                      &BaseDirectory,\r
 +                                      NULL,\r
 +                                      &MissingApiName,\r
 +                                      &MissingDriverName,\r
 +                                      &LoadedImports);\r
 +    if (!NT_SUCCESS(Status))\r
 +    {\r
 +        /* Fail */\r
 +        MiProcessLoaderEntry(LdrEntry, FALSE);\r
 +\r
 +        /* Check if we need to free the name */\r
 +        if (LdrEntry->FullDllName.Buffer)\r
 +        {\r
 +            /* Free it */\r
 +            ExFreePool(LdrEntry->FullDllName.Buffer);\r
 +        }\r
 +\r
 +        /* Free the entry itself */\r
 +        ExFreePool(LdrEntry);\r
 +        LdrEntry = NULL;\r
 +        goto Quickie;\r
 +    }\r
 +\r
 +    if (ModuleObject) *ModuleObject = LdrEntry;\r
 +    if (ImageBaseAddress) *ImageBaseAddress = LdrEntry->DllBase;\r
 +\r
 +    /* Hook for KDB on loading a driver. */\r
 +    KDB_LOADDRIVER_HOOK(FileName, LdrEntry);\r
 +\r
 +Quickie:\r
 +    /* If we have a file handle, close it */\r
 +    if (FileHandle) ZwClose(FileHandle);\r
 +\r
 +    /* Check if we have the lock acquired */\r
 +    if (LockOwned)\r
 +    {\r
 +        /* Release the lock */\r
 +        KeReleaseMutant(&MmSystemLoadLock, 1, FALSE, FALSE);\r
 +        KeLeaveCriticalRegion();\r
 +        LockOwned = FALSE;\r
 +    }\r
 +\r
 +    /* Check if we had a prefix */\r
 +    if (NamePrefix) ExFreePool(PrefixName.Buffer);\r
 +\r
 +    /* Free the name buffer and return status */\r
 +    ExFreePool(Buffer);\r
 +    return Status;\r
 +}\r
 +\r
 +/*\r
 + * @implemented\r
 + */\r
 +PVOID\r
 +NTAPI\r
 +MmGetSystemRoutineAddress(IN PUNICODE_STRING SystemRoutineName)\r
 +{\r
 +    PVOID ProcAddress = NULL;\r
 +    ANSI_STRING AnsiRoutineName;\r
 +    NTSTATUS Status;\r
 +    PLIST_ENTRY NextEntry;\r
 +    extern LIST_ENTRY PsLoadedModuleList;\r
 +    PLDR_DATA_TABLE_ENTRY LdrEntry;\r
 +    BOOLEAN Found = FALSE;\r
 +    UNICODE_STRING KernelName = RTL_CONSTANT_STRING(L"ntoskrnl.exe");\r
 +    UNICODE_STRING HalName = RTL_CONSTANT_STRING(L"hal.dll");\r
 +    ULONG Modules = 0;\r
 +\r
 +    /* Convert routine to ansi name */\r
 +    Status = RtlUnicodeStringToAnsiString(&AnsiRoutineName,\r
 +                                          SystemRoutineName,\r
 +                                          TRUE);\r
 +    if (!NT_SUCCESS(Status)) return NULL;\r
 +\r
 +    /* Lock the list */\r
 +    KeEnterCriticalRegion();\r
 +\r
 +    /* Loop the loaded module list */\r
 +    NextEntry = PsLoadedModuleList.Flink;\r
 +    while (NextEntry != &PsLoadedModuleList)\r
 +    {\r
 +        /* Get the entry */\r
 +        LdrEntry = CONTAINING_RECORD(NextEntry,\r
 +                                     LDR_DATA_TABLE_ENTRY,\r
 +                                     InLoadOrderLinks);\r
 +\r
 +        /* Check if it's the kernel or HAL */\r
 +        if (RtlEqualUnicodeString(&KernelName, &LdrEntry->BaseDllName, TRUE))\r
 +        {\r
 +            /* Found it */\r
 +            Found = TRUE;\r
 +            Modules++;\r
 +        }\r
 +        else if (RtlEqualUnicodeString(&HalName, &LdrEntry->BaseDllName, TRUE))\r
 +        {\r
 +            /* Found it */\r
 +            Found = TRUE;\r
 +            Modules++;\r
 +        }\r
 +\r
 +        /* Check if we found a valid binary */\r
 +        if (Found)\r
 +        {\r
 +            /* Find the procedure name */\r
 +            ProcAddress = MiFindExportedRoutineByName(LdrEntry->DllBase,\r
 +                                                      &AnsiRoutineName);\r
 +\r
 +            /* Break out if we found it or if we already tried both modules */\r
 +            if (ProcAddress) break;\r
 +            if (Modules == 2) break;\r
 +        }\r
 +\r
 +        /* Keep looping */\r
 +        NextEntry = NextEntry->Flink;\r
 +    }\r
 +\r
 +    /* Release the lock */\r
 +    KeLeaveCriticalRegion();\r
 +\r
 +    /* Free the string and return */\r
 +    RtlFreeAnsiString(&AnsiRoutineName);\r
 +    return ProcAddress;\r
 +}\r
 +\r
Simple merge