]> git.proxmox.com Git - mirror_edk2.git/blobdiff - EmulatorPkg/Win/Host/WinHost.c
EmulatorPkg: Add persistent memory in EmuThunkPpi
[mirror_edk2.git] / EmulatorPkg / Win / Host / WinHost.c
index 65e8960eff4510c89480db0e0ee7bd5c7bf9587f..19199c648c1532207ec26542a3afb14f8113c751 100644 (file)
@@ -8,40 +8,61 @@
   This code produces 128 K of temporary memory for the SEC stack by directly\r
   allocate memory space with ReadWrite and Execute attribute.\r
 \r
-Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>\r
-(C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>\r
-This program and the accompanying materials\r
-are licensed and made available under the terms and conditions of the BSD License\r
-which accompanies this distribution.  The full text of the license may be found at\r
-http://opensource.org/licenses/bsd-license.php\r
-\r
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+Copyright (c) 2006 - 2022, Intel Corporation. All rights reserved.<BR>\r
+(C) Copyright 2016-2020 Hewlett Packard Enterprise Development LP<BR>\r
+SPDX-License-Identifier: BSD-2-Clause-Patent\r
 **/\r
 \r
 #include "WinHost.h"\r
 \r
 #ifndef SE_TIME_ZONE_NAME\r
-#define SE_TIME_ZONE_NAME                 TEXT("SeTimeZonePrivilege")\r
+#define SE_TIME_ZONE_NAME  TEXT("SeTimeZonePrivilege")\r
 #endif\r
 \r
+//\r
+// The growth size for array of module handle entries\r
+//\r
+#define MAX_PDB_NAME_TO_MOD_HANDLE_ARRAY_SIZE  0x100\r
+\r
+//\r
+// Module handle entry structure\r
+//\r
+typedef struct {\r
+  CHAR8    *PdbPointer;\r
+  VOID     *ModHandle;\r
+} PDB_NAME_TO_MOD_HANDLE;\r
+\r
+//\r
+// An Array to hold the module handles\r
+//\r
+PDB_NAME_TO_MOD_HANDLE  *mPdbNameModHandleArray    = NULL;\r
+UINTN                   mPdbNameModHandleArraySize = 0;\r
+\r
 //\r
 // Default information about where the FD is located.\r
 //  This array gets filled in with information from PcdWinNtFirmwareVolume\r
 //  The number of array elements is allocated base on parsing\r
 //  PcdWinNtFirmwareVolume and the memory is never freed.\r
 //\r
-UINTN                                     gFdInfoCount = 0;\r
-NT_FD_INFO                                *gFdInfo;\r
+UINTN       gFdInfoCount = 0;\r
+NT_FD_INFO  *gFdInfo;\r
 \r
 //\r
-// Array that supports seperate memory rantes.\r
+// Array that supports separate memory ranges.\r
 //  The memory ranges are set by PcdWinNtMemorySizeForSecMain.\r
 //  The number of array elements is allocated base on parsing\r
 //  PcdWinNtMemorySizeForSecMain value and the memory is never freed.\r
 //\r
-UINTN                                     gSystemMemoryCount = 0;\r
-NT_SYSTEM_MEMORY                          *gSystemMemory;\r
+UINTN             gSystemMemoryCount = 0;\r
+NT_SYSTEM_MEMORY  *gSystemMemory;\r
+\r
+BASE_LIBRARY_JUMP_BUFFER  mResetJumpBuffer;\r
+CHAR8                     *mResetTypeStr[] = {\r
+  "EfiResetCold",\r
+  "EfiResetWarm",\r
+  "EfiResetShutdown",\r
+  "EfiResetPlatformSpecific"\r
+};\r
 \r
 /*++\r
 \r
@@ -74,14 +95,6 @@ WinPeiAutoScan (
     return EFI_UNSUPPORTED;\r
   }\r
 \r
-  //\r
-  // Allocate enough memory space for emulator\r
-  //\r
-  gSystemMemory[Index].Memory = (EFI_PHYSICAL_ADDRESS) (UINTN) VirtualAlloc (NULL, (SIZE_T) (gSystemMemory[Index].Size), MEM_COMMIT, PAGE_EXECUTE_READWRITE);\r
-  if (gSystemMemory[Index].Memory == 0) {\r
-    return EFI_OUT_OF_RESOURCES;\r
-  }\r
-\r
   *MemoryBase = gSystemMemory[Index].Memory;\r
   *MemorySize = gSystemMemory[Index].Size;\r
 \r
@@ -92,7 +105,7 @@ WinPeiAutoScan (
 \r
 Routine Description:\r
   Return the FD Size and base address. Since the FD is loaded from a\r
-  file into host memory only the SEC will know it's address.\r
+  file into host memory only the SEC will know its address.\r
 \r
 Arguments:\r
   Index  - Which FD, starts at zero.\r
@@ -117,12 +130,11 @@ WinFdAddress (
     return EFI_UNSUPPORTED;\r
   }\r
 \r
-\r
   *FdBase = (EFI_PHYSICAL_ADDRESS)(UINTN)gFdInfo[Index].Address;\r
   *FdSize = (UINT64)gFdInfo[Index].Size;\r
   *FixUp  = 0;\r
 \r
-  if (*FdBase == 0 && *FdSize == 0) {\r
+  if ((*FdBase == 0) && (*FdSize == 0)) {\r
     return EFI_UNSUPPORTED;\r
   }\r
 \r
@@ -160,8 +172,7 @@ WinThunk (
   return &gEmuThunkProtocol;\r
 }\r
 \r
-\r
-EMU_THUNK_PPI mSecEmuThunkPpi = {\r
+EMU_THUNK_PPI  mSecEmuThunkPpi = {\r
   WinPeiAutoScan,\r
   WinFdAddress,\r
   WinThunk\r
@@ -193,6 +204,59 @@ SecPrint (
     );\r
 }\r
 \r
+/**\r
+  Resets the entire platform.\r
+\r
+  @param[in] ResetType      The type of reset to perform.\r
+  @param[in] ResetStatus    The status code for the reset.\r
+  @param[in] DataSize       The size, in bytes, of ResetData.\r
+  @param[in] ResetData      For a ResetType of EfiResetCold, EfiResetWarm, or EfiResetShutdown\r
+                            the data buffer starts with a Null-terminated string, optionally\r
+                            followed by additional binary data. The string is a description\r
+                            that the caller may use to further indicate the reason for the\r
+                            system reset.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+WinReset (\r
+  IN EFI_RESET_TYPE  ResetType,\r
+  IN EFI_STATUS      ResetStatus,\r
+  IN UINTN           DataSize,\r
+  IN VOID            *ResetData OPTIONAL\r
+  )\r
+{\r
+  UINTN  Index;\r
+\r
+  ASSERT (ResetType <= EfiResetPlatformSpecific);\r
+  SecPrint ("  Emu ResetSystem is called: ResetType = %s\n", mResetTypeStr[ResetType]);\r
+\r
+  if (ResetType == EfiResetShutdown) {\r
+    exit (0);\r
+  } else {\r
+    //\r
+    // Unload all DLLs\r
+    //\r
+    for (Index = 0; Index < mPdbNameModHandleArraySize; Index++) {\r
+      if (mPdbNameModHandleArray[Index].PdbPointer != NULL) {\r
+        SecPrint ("  Emu Unload DLL: %s\n", mPdbNameModHandleArray[Index].PdbPointer);\r
+        FreeLibrary (mPdbNameModHandleArray[Index].ModHandle);\r
+        HeapFree (GetProcessHeap (), 0, mPdbNameModHandleArray[Index].PdbPointer);\r
+        mPdbNameModHandleArray[Index].PdbPointer = NULL;\r
+      }\r
+    }\r
+\r
+    //\r
+    // Jump back to SetJump with jump code = ResetType + 1\r
+    //\r
+    LongJump (&mResetJumpBuffer, ResetType + 1);\r
+  }\r
+}\r
+\r
+EFI_PEI_RESET2_PPI  mEmuReset2Ppi = {\r
+  WinReset\r
+};\r
+\r
 /*++\r
 \r
 Routine Description:\r
@@ -214,7 +278,7 @@ Returns:
 **/\r
 BOOLEAN\r
 EfiSystemMemoryRange (\r
-  IN  VOID *MemoryAddress\r
+  IN  VOID  *MemoryAddress\r
   )\r
 {\r
   UINTN                 Index;\r
@@ -223,7 +287,8 @@ EfiSystemMemoryRange (
   MemoryBase = (EFI_PHYSICAL_ADDRESS)(UINTN)MemoryAddress;\r
   for (Index = 0; Index < gSystemMemoryCount; Index++) {\r
     if ((MemoryBase >= gSystemMemory[Index].Memory) &&\r
-        (MemoryBase < (gSystemMemory[Index].Memory + gSystemMemory[Index].Size)) ) {\r
+        (MemoryBase < (gSystemMemory[Index].Memory + gSystemMemory[Index].Size)))\r
+    {\r
       return TRUE;\r
     }\r
   }\r
@@ -231,15 +296,15 @@ EfiSystemMemoryRange (
   return FALSE;\r
 }\r
 \r
-\r
 EFI_STATUS\r
 WinNtOpenFile (\r
-  IN  CHAR16                    *FileName,            OPTIONAL\r
-  IN  UINT32                    MapSize,\r
-  IN  DWORD                     CreationDisposition,\r
-  IN OUT  VOID                  **BaseAddress,\r
-  OUT UINTN                     *Length\r
+  IN  CHAR16    *FileName             OPTIONAL,\r
+  IN  UINT32    MapSize,\r
+  IN  DWORD     CreationDisposition,\r
+  IN OUT  VOID  **BaseAddress,\r
+  OUT UINTN     *Length\r
   )\r
+\r
 /*++\r
 \r
 Routine Description:\r
@@ -260,7 +325,7 @@ Arguments:
 Returns:\r
   EFI_SUCCESS      - The file was opened and mapped.\r
   EFI_NOT_FOUND    - FileName was not found in the current directory\r
-  EFI_DEVICE_ERROR - An error occured attempting to map the opened file\r
+  EFI_DEVICE_ERROR - An error occurred attempting to map the opened file\r
 \r
 --*/\r
 {\r
@@ -287,6 +352,7 @@ Returns:
       return EFI_NOT_FOUND;\r
     }\r
   }\r
+\r
   //\r
   // Map the open file into a memory range\r
   //\r
@@ -301,17 +367,18 @@ Returns:
   if (NtMapHandle == NULL) {\r
     return EFI_DEVICE_ERROR;\r
   }\r
+\r
   //\r
   // Get the virtual address (address in the emulator) of the mapped file\r
   //\r
   VirtualAddress = MapViewOfFileEx (\r
-                    NtMapHandle,\r
-                    FILE_MAP_EXECUTE | FILE_MAP_ALL_ACCESS,\r
-                    0,\r
-                    0,\r
-                    MapSize,\r
-                    *BaseAddress\r
-                    );\r
+                     NtMapHandle,\r
+                     FILE_MAP_EXECUTE | FILE_MAP_ALL_ACCESS,\r
+                     0,\r
+                     0,\r
+                     MapSize,\r
+                     *BaseAddress\r
+                     );\r
   if (VirtualAddress == NULL) {\r
     return EFI_DEVICE_ERROR;\r
   }\r
@@ -321,11 +388,11 @@ Returns:
     // Seek to the end of the file to figure out the true file size.\r
     //\r
     FileSize = SetFilePointer (\r
-                NtFileHandle,\r
-                0,\r
-                NULL,\r
-                FILE_END\r
-                );\r
+                 NtFileHandle,\r
+                 0,\r
+                 NULL,\r
+                 FILE_END\r
+                 );\r
     if (FileSize == -1) {\r
       return EFI_DEVICE_ERROR;\r
     }\r
@@ -343,10 +410,11 @@ Returns:
 INTN\r
 EFIAPI\r
 main (\r
-  IN  INTN  Argc,\r
-  IN  CHAR8 **Argv,\r
-  IN  CHAR8 **Envp\r
+  IN  INT    Argc,\r
+  IN  CHAR8  **Argv,\r
+  IN  CHAR8  **Envp\r
   )\r
+\r
 /*++\r
 \r
 Routine Description:\r
@@ -363,45 +431,47 @@ Returns:
 \r
 --*/\r
 {\r
-  EFI_STATUS            Status;\r
-  HANDLE                Token;\r
-  TOKEN_PRIVILEGES      TokenPrivileges;\r
-  VOID                  *TemporaryRam;\r
-  UINT32                TemporaryRamSize;\r
-  VOID                  *EmuMagicPage;\r
-  UINTN                 Index;\r
-  UINTN                 Index1;\r
-  CHAR16                *FileName;\r
-  CHAR16                *FileNamePtr;\r
-  BOOLEAN               Done;\r
-  EFI_PEI_FILE_HANDLE   FileHandle;\r
-  VOID                  *SecFile;\r
-  CHAR16                *MemorySizeStr;\r
-  CHAR16                *FirmwareVolumesStr;\r
-  UINT32                ProcessAffinityMask;\r
-  UINT32                SystemAffinityMask;\r
-  INT32                 LowBit;\r
+  EFI_STATUS           Status;\r
+  HANDLE               Token;\r
+  TOKEN_PRIVILEGES     TokenPrivileges;\r
+  VOID                 *TemporaryRam;\r
+  UINT32               TemporaryRamSize;\r
+  VOID                 *EmuMagicPage;\r
+  UINTN                Index;\r
+  UINTN                Index1;\r
+  CHAR16               *FileName;\r
+  CHAR16               *FileNamePtr;\r
+  BOOLEAN              Done;\r
+  EFI_PEI_FILE_HANDLE  FileHandle;\r
+  VOID                 *SecFile;\r
+  CHAR16               *MemorySizeStr;\r
+  CHAR16               *FirmwareVolumesStr;\r
+  UINTN                ProcessAffinityMask;\r
+  UINTN                SystemAffinityMask;\r
+  INT32                LowBit;\r
+  UINTN                ResetJumpCode;\r
+  EMU_THUNK_PPI        *SecEmuThunkPpi;\r
 \r
   //\r
   // Enable the privilege so that RTC driver can successfully run SetTime()\r
   //\r
-  OpenProcessToken (GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY, &Token);\r
-  if (LookupPrivilegeValue(NULL, SE_TIME_ZONE_NAME, &TokenPrivileges.Privileges[0].Luid)) {\r
-    TokenPrivileges.PrivilegeCount = 1;\r
+  OpenProcessToken (GetCurrentProcess (), TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY, &Token);\r
+  if (LookupPrivilegeValue (NULL, SE_TIME_ZONE_NAME, &TokenPrivileges.Privileges[0].Luid)) {\r
+    TokenPrivileges.PrivilegeCount           = 1;\r
     TokenPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;\r
-    AdjustTokenPrivileges(Token, FALSE, &TokenPrivileges, 0, (PTOKEN_PRIVILEGES) NULL, 0);\r
+    AdjustTokenPrivileges (Token, FALSE, &TokenPrivileges, 0, (PTOKEN_PRIVILEGES)NULL, 0);\r
   }\r
 \r
-  MemorySizeStr      = (CHAR16 *) PcdGetPtr (PcdEmuMemorySize);\r
-  FirmwareVolumesStr = (CHAR16 *) PcdGetPtr (PcdEmuFirmwareVolume);\r
+  MemorySizeStr      = (CHAR16 *)PcdGetPtr (PcdEmuMemorySize);\r
+  FirmwareVolumesStr = (CHAR16 *)PcdGetPtr (PcdEmuFirmwareVolume);\r
 \r
-  SecPrint ("\nEDK II WIN Host Emulation Environment from http://www.tianocore.org/edk2/\n");\r
+  SecPrint ("\n\rEDK II WIN Host Emulation Environment from http://www.tianocore.org/edk2/\n\r");\r
 \r
   //\r
   // Determine the first thread available to this process.\r
   //\r
   if (GetProcessAffinityMask (GetCurrentProcess (), &ProcessAffinityMask, &SystemAffinityMask)) {\r
-    LowBit = (INT32)LowBitSet32 (ProcessAffinityMask);\r
+    LowBit = (INT32)LowBitSet32 ((UINT32)ProcessAffinityMask);\r
     if (LowBit != -1) {\r
       //\r
       // Force the system to bind the process to a single thread to work\r
@@ -422,7 +492,16 @@ Returns:
   //\r
   // PPIs pased into PEI_CORE\r
   //\r
-  AddThunkPpi (EFI_PEI_PPI_DESCRIPTOR_PPI, &gEmuThunkPpiGuid, &mSecEmuThunkPpi);\r
+  SecEmuThunkPpi = AllocateZeroPool (sizeof (EMU_THUNK_PPI) + FixedPcdGet32 (PcdPersistentMemorySize));\r
+  if (SecEmuThunkPpi == NULL) {\r
+    SecPrint ("ERROR : Can not allocate memory for SecEmuThunkPpi.  Exiting.\n");\r
+    exit (1);\r
+  }\r
+\r
+  CopyMem (SecEmuThunkPpi, &mSecEmuThunkPpi, sizeof (EMU_THUNK_PPI));\r
+  SecEmuThunkPpi->PersistentMemorySize = FixedPcdGet32 (PcdPersistentMemorySize);\r
+  AddThunkPpi (EFI_PEI_PPI_DESCRIPTOR_PPI, &gEmuThunkPpiGuid, SecEmuThunkPpi);\r
+  AddThunkPpi (EFI_PEI_PPI_DESCRIPTOR_PPI, &gEfiPeiReset2PpiGuid, &mEmuReset2Ppi);\r
 \r
   //\r
   // Emulator Bus Driver Thunks\r
@@ -430,30 +509,56 @@ Returns:
   AddThunkProtocol (&mWinNtWndThunkIo, (CHAR16 *)PcdGetPtr (PcdEmuGop), TRUE);\r
   AddThunkProtocol (&mWinNtFileSystemThunkIo, (CHAR16 *)PcdGetPtr (PcdEmuFileSystem), TRUE);\r
   AddThunkProtocol (&mWinNtBlockIoThunkIo, (CHAR16 *)PcdGetPtr (PcdEmuVirtualDisk), TRUE);\r
+  AddThunkProtocol (&mWinNtSnpThunkIo, (CHAR16 *)PcdGetPtr (PcdEmuNetworkInterface), TRUE);\r
 \r
   //\r
   // Allocate space for gSystemMemory Array\r
   //\r
-  gSystemMemoryCount  = CountSeparatorsInString (MemorySizeStr, '!') + 1;\r
-  gSystemMemory       = calloc (gSystemMemoryCount, sizeof (NT_SYSTEM_MEMORY));\r
+  gSystemMemoryCount = CountSeparatorsInString (MemorySizeStr, '!') + 1;\r
+  gSystemMemory      = calloc (gSystemMemoryCount, sizeof (NT_SYSTEM_MEMORY));\r
   if (gSystemMemory == NULL) {\r
-    SecPrint ("ERROR : Can not allocate memory for %S.  Exiting.\n", MemorySizeStr);\r
+    SecPrint ("ERROR : Can not allocate memory for %S.  Exiting.\n\r", MemorySizeStr);\r
     exit (1);\r
   }\r
 \r
+  //\r
+  // Allocate "physical" memory space for emulator. It will be reported out later throuth MemoryAutoScan()\r
+  //\r
+  for (Index = 0, Done = FALSE; !Done; Index++) {\r
+    ASSERT (Index < gSystemMemoryCount);\r
+    gSystemMemory[Index].Size   = ((UINT64)_wtoi (MemorySizeStr)) * ((UINT64)SIZE_1MB);\r
+    gSystemMemory[Index].Memory = (EFI_PHYSICAL_ADDRESS)(UINTN)VirtualAlloc (NULL, (SIZE_T)(gSystemMemory[Index].Size), MEM_COMMIT, PAGE_EXECUTE_READWRITE);\r
+    if (gSystemMemory[Index].Memory == 0) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+\r
+    //\r
+    // Find the next region\r
+    //\r
+    for (Index1 = 0; MemorySizeStr[Index1] != '!' && MemorySizeStr[Index1] != 0; Index1++) {\r
+    }\r
+\r
+    if (MemorySizeStr[Index1] == 0) {\r
+      Done = TRUE;\r
+    }\r
+\r
+    MemorySizeStr = MemorySizeStr + Index1 + 1;\r
+  }\r
+\r
   //\r
   // Allocate space for gSystemMemory Array\r
   //\r
-  gFdInfoCount  = CountSeparatorsInString (FirmwareVolumesStr, '!') + 1;\r
-  gFdInfo       = calloc (gFdInfoCount, sizeof (NT_FD_INFO));\r
+  gFdInfoCount = CountSeparatorsInString (FirmwareVolumesStr, '!') + 1;\r
+  gFdInfo      = calloc (gFdInfoCount, sizeof (NT_FD_INFO));\r
   if (gFdInfo == NULL) {\r
-    SecPrint ("ERROR : Can not allocate memory for %S.  Exiting.\n", FirmwareVolumesStr);\r
+    SecPrint ("ERROR : Can not allocate memory for %S.  Exiting.\n\r", FirmwareVolumesStr);\r
     exit (1);\r
   }\r
+\r
   //\r
   // Setup Boot Mode.\r
   //\r
-  SecPrint ("  BootMode 0x%02x\n", PcdGet32 (PcdEmuBootMode));\r
+  SecPrint ("  BootMode 0x%02x\n\r", PcdGet32 (PcdEmuBootMode));\r
 \r
   //\r
   //  Allocate 128K memory to emulate temp memory for PEI.\r
@@ -461,17 +566,11 @@ Returns:
   //  Set TemporaryRam to zero so WinNtOpenFile will allocate a new mapping\r
   //\r
   TemporaryRamSize = TEMPORARY_RAM_SIZE;\r
-  TemporaryRam     = VirtualAlloc (NULL, (SIZE_T) (TemporaryRamSize), MEM_COMMIT, PAGE_EXECUTE_READWRITE);\r
+  TemporaryRam     = VirtualAlloc (NULL, (SIZE_T)(TemporaryRamSize), MEM_COMMIT, PAGE_EXECUTE_READWRITE);\r
   if (TemporaryRam == NULL) {\r
-    SecPrint ("ERROR : Can not allocate enough space for SecStack\n");\r
+    SecPrint ("ERROR : Can not allocate enough space for SecStack\n\r");\r
     exit (1);\r
   }\r
-  SetMem32 (TemporaryRam, TemporaryRamSize, PcdGet32 (PcdInitValueInTempStack));\r
-\r
-  SecPrint ("  OS Emulator passing in %u KB of temp RAM at 0x%08lx to SEC\n",\r
-    TemporaryRamSize / SIZE_1KB,\r
-    TemporaryRam\r
-    );\r
 \r
   //\r
   // If enabled use the magic page to communicate between modules\r
@@ -483,14 +582,14 @@ Returns:
   if (EmuMagicPage != NULL) {\r
     UINT64  Size;\r
     Status = WinNtOpenFile (\r
-              NULL,\r
-              SIZE_4KB,\r
-              0,\r
-              &EmuMagicPage,\r
-              &Size\r
-              );\r
+               NULL,\r
+               SIZE_4KB,\r
+               0,\r
+               &EmuMagicPage,\r
+               &Size\r
+               );\r
     if (EFI_ERROR (Status)) {\r
-      SecPrint ("ERROR : Could not allocate PeiServicesTablePage @ %p\n", EmuMagicPage);\r
+      SecPrint ("ERROR : Could not allocate PeiServicesTablePage @ %p\n\r", EmuMagicPage);\r
       return EFI_DEVICE_ERROR;\r
     }\r
   }\r
@@ -501,37 +600,38 @@ Returns:
   //\r
   FileNamePtr = AllocateCopyPool (StrSize (FirmwareVolumesStr), FirmwareVolumesStr);\r
   if (FileNamePtr == NULL) {\r
-    SecPrint ("ERROR : Can not allocate memory for firmware volume string\n");\r
+    SecPrint ("ERROR : Can not allocate memory for firmware volume string\n\r");\r
     exit (1);\r
   }\r
 \r
   for (Done = FALSE, Index = 0, SecFile = NULL; !Done; Index++) {\r
     FileName = FileNamePtr;\r
-    for (Index1 = 0; (FileNamePtr[Index1] != '!') && (FileNamePtr[Index1] != 0); Index1++)\r
-      ;\r
+    for (Index1 = 0; (FileNamePtr[Index1] != '!') && (FileNamePtr[Index1] != 0); Index1++) {\r
+    }\r
+\r
     if (FileNamePtr[Index1] == 0) {\r
       Done = TRUE;\r
     } else {\r
-      FileNamePtr[Index1]  = '\0';\r
-      FileNamePtr = &FileNamePtr[Index1 + 1];\r
+      FileNamePtr[Index1] = '\0';\r
+      FileNamePtr         = &FileNamePtr[Index1 + 1];\r
     }\r
 \r
     //\r
     // Open the FD and remember where it got mapped into our processes address space\r
     //\r
     Status = WinNtOpenFile (\r
-              FileName,\r
-              0,\r
-              OPEN_EXISTING,\r
-              &gFdInfo[Index].Address,\r
-              &gFdInfo[Index].Size\r
-              );\r
+               FileName,\r
+               0,\r
+               OPEN_EXISTING,\r
+               &gFdInfo[Index].Address,\r
+               &gFdInfo[Index].Size\r
+               );\r
     if (EFI_ERROR (Status)) {\r
-      SecPrint ("ERROR : Can not open Firmware Device File %S (0x%X).  Exiting.\n", FileName, Status);\r
+      SecPrint ("ERROR : Can not open Firmware Device File %S (0x%X).  Exiting.\n\r", FileName, Status);\r
       exit (1);\r
     }\r
 \r
-    SecPrint ("  FD loaded from %S\n", FileName);\r
+    SecPrint ("  FD loaded from %S", FileName);\r
 \r
     if (SecFile == NULL) {\r
       //\r
@@ -539,11 +639,11 @@ Returns:
       // Load the first one we find.\r
       //\r
       FileHandle = NULL;\r
-      Status = PeiServicesFfsFindNextFile (\r
-                  EFI_FV_FILETYPE_SECURITY_CORE,\r
-                  (EFI_PEI_FV_HANDLE)gFdInfo[Index].Address,\r
-                  &FileHandle\r
-                  );\r
+      Status     = PeiServicesFfsFindNextFile (\r
+                     EFI_FV_FILETYPE_SECURITY_CORE,\r
+                     (EFI_PEI_FV_HANDLE)gFdInfo[Index].Address,\r
+                     &FileHandle\r
+                     );\r
       if (!EFI_ERROR (Status)) {\r
         Status = PeiServicesFfsFindSectionData (EFI_SECTION_PE32, FileHandle, &SecFile);\r
         if (!EFI_ERROR (Status)) {\r
@@ -552,33 +652,27 @@ Returns:
       }\r
     }\r
 \r
-    SecPrint ("\n");\r
+    SecPrint ("\n\r");\r
   }\r
+\r
+  ResetJumpCode = SetJump (&mResetJumpBuffer);\r
+\r
   //\r
-  // Calculate memory regions and store the information in the gSystemMemory\r
-  //  global for later use. The autosizing code will use this data to\r
-  //  map this memory into the SEC process memory space.\r
+  // Do not clear memory content for warm reset.\r
   //\r
-  for (Index = 0, Done = FALSE; !Done; Index++) {\r
-    //\r
-    // Save the size of the memory and make a Unicode filename SystemMemory00, ...\r
-    //\r
-    gSystemMemory[Index].Size = _wtoi (MemorySizeStr) * SIZE_1MB;\r
-\r
-    //\r
-    // Find the next region\r
-    //\r
-    for (Index1 = 0; MemorySizeStr[Index1] != '!' && MemorySizeStr[Index1] != 0; Index1++)\r
-      ;\r
-    if (MemorySizeStr[Index1] == 0) {\r
-      Done = TRUE;\r
+  if (ResetJumpCode != EfiResetWarm + 1) {\r
+    SecPrint ("  OS Emulator clearing temp RAM and physical RAM (to be discovered later)......\n\r");\r
+    SetMem32 (TemporaryRam, TemporaryRamSize, PcdGet32 (PcdInitValueInTempStack));\r
+    for (Index = 0; Index < gSystemMemoryCount; Index++) {\r
+      SetMem32 ((VOID *)(UINTN)gSystemMemory[Index].Memory, (UINTN)gSystemMemory[Index].Size, PcdGet32 (PcdInitValueInTempStack));\r
     }\r
-\r
-    MemorySizeStr = MemorySizeStr + Index1 + 1;\r
   }\r
 \r
-  SecPrint ("\n");\r
-\r
+  SecPrint (\r
+    "  OS Emulator passing in %u KB of temp RAM at 0x%08lx to SEC\n\r",\r
+    TemporaryRamSize / SIZE_1KB,\r
+    TemporaryRam\r
+    );\r
   //\r
   // Hand off to SEC Core\r
   //\r
@@ -588,18 +682,19 @@ Returns:
   // If we get here, then the SEC Core returned. This is an error as SEC should\r
   //  always hand off to PEI Core and then on to DXE Core.\r
   //\r
-  SecPrint ("ERROR : SEC returned\n");\r
+  SecPrint ("ERROR : SEC returned\n\r");\r
   exit (1);\r
 }\r
 \r
 VOID\r
 SecLoadSecCore (\r
-  IN  UINTN   TemporaryRam,\r
-  IN  UINTN   TemporaryRamSize,\r
-  IN  VOID    *BootFirmwareVolumeBase,\r
-  IN  UINTN   BootFirmwareVolumeSize,\r
-  IN  VOID    *SecCorePe32File\r
+  IN  UINTN  TemporaryRam,\r
+  IN  UINTN  TemporaryRamSize,\r
+  IN  VOID   *BootFirmwareVolumeBase,\r
+  IN  UINTN  BootFirmwareVolumeSize,\r
+  IN  VOID   *SecCorePe32File\r
   )\r
+\r
 /*++\r
 \r
 Routine Description:\r
@@ -612,15 +707,15 @@ Arguments:
   SecCorePe32File         - SEC Core PE32\r
 \r
 Returns:\r
-  Success means control is transfered and thus we should never return\r
+  Success means control is transferred and thus we should never return\r
 \r
 --*/\r
 {\r
-  EFI_STATUS                  Status;\r
-  VOID                        *TopOfStack;\r
-  VOID                        *SecCoreEntryPoint;\r
-  EFI_SEC_PEI_HAND_OFF        *SecCoreData;\r
-  UINTN                       SecStackSize;\r
+  EFI_STATUS            Status;\r
+  VOID                  *TopOfStack;\r
+  VOID                  *SecCoreEntryPoint;\r
+  EFI_SEC_PEI_HAND_OFF  *SecCoreData;\r
+  UINTN                 SecStackSize;\r
 \r
   //\r
   // Compute Top Of Memory for Stack and PEI Core Allocations\r
@@ -636,37 +731,37 @@ Returns:
   // |  Stack    |\r
   // |-----------| <---- TemporaryRamBase\r
   //\r
-  TopOfStack  = (VOID *)(TemporaryRam + SecStackSize);\r
+  TopOfStack = (VOID *)(TemporaryRam + SecStackSize);\r
 \r
   //\r
   // Reservet space for storing PeiCore's parament in stack.\r
   //\r
-  TopOfStack  = (VOID *)((UINTN)TopOfStack - sizeof (EFI_SEC_PEI_HAND_OFF) - CPU_STACK_ALIGNMENT);\r
-  TopOfStack  = ALIGN_POINTER (TopOfStack, CPU_STACK_ALIGNMENT);\r
+  TopOfStack = (VOID *)((UINTN)TopOfStack - sizeof (EFI_SEC_PEI_HAND_OFF) - CPU_STACK_ALIGNMENT);\r
+  TopOfStack = ALIGN_POINTER (TopOfStack, CPU_STACK_ALIGNMENT);\r
 \r
   //\r
   // Bind this information into the SEC hand-off state\r
   //\r
-  SecCoreData                         = (EFI_SEC_PEI_HAND_OFF*)(UINTN)TopOfStack;\r
+  SecCoreData                         = (EFI_SEC_PEI_HAND_OFF *)(UINTN)TopOfStack;\r
   SecCoreData->DataSize               = sizeof (EFI_SEC_PEI_HAND_OFF);\r
   SecCoreData->BootFirmwareVolumeBase = BootFirmwareVolumeBase;\r
   SecCoreData->BootFirmwareVolumeSize = BootFirmwareVolumeSize;\r
-  SecCoreData->TemporaryRamBase       = (VOID*)TemporaryRam;\r
+  SecCoreData->TemporaryRamBase       = (VOID *)TemporaryRam;\r
   SecCoreData->TemporaryRamSize       = TemporaryRamSize;\r
   SecCoreData->StackBase              = SecCoreData->TemporaryRamBase;\r
   SecCoreData->StackSize              = SecStackSize;\r
-  SecCoreData->PeiTemporaryRamBase    = (VOID*) ((UINTN) SecCoreData->TemporaryRamBase + SecStackSize);\r
+  SecCoreData->PeiTemporaryRamBase    = (VOID *)((UINTN)SecCoreData->TemporaryRamBase + SecStackSize);\r
   SecCoreData->PeiTemporaryRamSize    = TemporaryRamSize - SecStackSize;\r
 \r
   //\r
   // Load the PEI Core from a Firmware Volume\r
   //\r
   Status = SecPeCoffGetEntryPoint (\r
-            SecCorePe32File,\r
-            &SecCoreEntryPoint\r
-            );\r
+             SecCorePe32File,\r
+             &SecCoreEntryPoint\r
+             );\r
   if (EFI_ERROR (Status)) {\r
-    return ;\r
+    return;\r
   }\r
 \r
   //\r
@@ -681,7 +776,7 @@ Returns:
   //\r
   // If we get here, then the SEC Core returned.  This is an error\r
   //\r
-  return ;\r
+  return;\r
 }\r
 \r
 RETURN_STATUS\r
@@ -691,31 +786,23 @@ SecPeCoffGetEntryPoint (
   IN OUT VOID  **EntryPoint\r
   )\r
 {\r
-  EFI_STATUS                            Status;\r
-  PE_COFF_LOADER_IMAGE_CONTEXT          ImageContext;\r
+  EFI_STATUS                    Status;\r
+  PE_COFF_LOADER_IMAGE_CONTEXT  ImageContext;\r
 \r
   ZeroMem (&ImageContext, sizeof (ImageContext));\r
-  ImageContext.Handle     = Pe32Data;\r
+  ImageContext.Handle = Pe32Data;\r
 \r
-  ImageContext.ImageRead  = (PE_COFF_LOADER_READ_FILE) SecImageRead;\r
+  ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE)SecImageRead;\r
 \r
-  Status                  = PeCoffLoaderGetImageInfo (&ImageContext);\r
+  Status = PeCoffLoaderGetImageInfo (&ImageContext);\r
   if (EFI_ERROR (Status)) {\r
     return Status;\r
   }\r
+\r
   //\r
-  // Allocate space in NT (not emulator) memory with ReadWrite and Execute attribute.\r
-  // Extra space is for alignment\r
-  //\r
-  ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) VirtualAlloc (NULL, (SIZE_T) (ImageContext.ImageSize + (ImageContext.SectionAlignment * 2)), MEM_COMMIT, PAGE_EXECUTE_READWRITE);\r
-  if (ImageContext.ImageAddress == 0) {\r
-    return EFI_OUT_OF_RESOURCES;\r
-  }\r
-  //\r
-  // Align buffer on section boundary\r
+  // XIP for SEC and PEI_CORE\r
   //\r
-  ImageContext.ImageAddress += ImageContext.SectionAlignment - 1;\r
-  ImageContext.ImageAddress &= ~((EFI_PHYSICAL_ADDRESS)ImageContext.SectionAlignment - 1);\r
+  ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)Pe32Data;\r
 \r
   Status = PeCoffLoaderLoadImage (&ImageContext);\r
   if (EFI_ERROR (Status)) {\r
@@ -727,7 +814,7 @@ SecPeCoffGetEntryPoint (
     return Status;\r
   }\r
 \r
-  *EntryPoint   = (VOID *)(UINTN)ImageContext.EntryPoint;\r
+  *EntryPoint = (VOID *)(UINTN)ImageContext.EntryPoint;\r
 \r
   return EFI_SUCCESS;\r
 }\r
@@ -735,11 +822,12 @@ SecPeCoffGetEntryPoint (
 EFI_STATUS\r
 EFIAPI\r
 SecImageRead (\r
-  IN     VOID    *FileHandle,\r
-  IN     UINTN   FileOffset,\r
-  IN OUT UINTN   *ReadSize,\r
-  OUT    VOID    *Buffer\r
+  IN     VOID   *FileHandle,\r
+  IN     UINTN  FileOffset,\r
+  IN OUT UINTN  *ReadSize,\r
+  OUT    VOID   *Buffer\r
   )\r
+\r
 /*++\r
 \r
 Routine Description:\r
@@ -756,13 +844,13 @@ Returns:
 \r
 --*/\r
 {\r
-  CHAR8 *Destination8;\r
-  CHAR8 *Source8;\r
-  UINTN Length;\r
+  CHAR8  *Destination8;\r
+  CHAR8  *Source8;\r
+  UINTN  Length;\r
 \r
-  Destination8  = Buffer;\r
-  Source8       = (CHAR8 *) ((UINTN) FileHandle + FileOffset);\r
-  Length        = *ReadSize;\r
+  Destination8 = Buffer;\r
+  Source8      = (CHAR8 *)((UINTN)FileHandle + FileOffset);\r
+  Length       = *ReadSize;\r
   while (Length--) {\r
     *(Destination8++) = *(Source8++);\r
   }\r
@@ -772,9 +860,10 @@ Returns:
 \r
 CHAR16 *\r
 AsciiToUnicode (\r
-  IN  CHAR8   *Ascii,\r
-  IN  UINTN   *StrLen OPTIONAL\r
+  IN  CHAR8  *Ascii,\r
+  IN  UINTN  *StrLen OPTIONAL\r
   )\r
+\r
 /*++\r
 \r
 Routine Description:\r
@@ -796,15 +885,16 @@ Returns:
   //\r
   // Allocate a buffer for unicode string\r
   //\r
-  for (Index = 0; Ascii[Index] != '\0'; Index++)\r
-    ;\r
+  for (Index = 0; Ascii[Index] != '\0'; Index++) {\r
+  }\r
+\r
   Unicode = malloc ((Index + 1) * sizeof (CHAR16));\r
   if (Unicode == NULL) {\r
     return NULL;\r
   }\r
 \r
   for (Index = 0; Ascii[Index] != '\0'; Index++) {\r
-    Unicode[Index] = (CHAR16) Ascii[Index];\r
+    Unicode[Index] = (CHAR16)Ascii[Index];\r
   }\r
 \r
   Unicode[Index] = '\0';\r
@@ -818,9 +908,10 @@ Returns:
 \r
 UINTN\r
 CountSeparatorsInString (\r
-  IN  CONST CHAR16   *String,\r
-  IN  CHAR16         Separator\r
+  IN  CONST CHAR16  *String,\r
+  IN  CHAR16        Separator\r
   )\r
+\r
 /*++\r
 \r
 Routine Description:\r
@@ -835,7 +926,7 @@ Returns:
 \r
 --*/\r
 {\r
-  UINTN Count;\r
+  UINTN  Count;\r
 \r
   for (Count = 0; *String != '\0'; String++) {\r
     if (*String == Separator) {\r
@@ -846,26 +937,142 @@ Returns:
   return Count;\r
 }\r
 \r
+/**\r
+  Store the ModHandle in an array indexed by the Pdb File name.\r
+  The ModHandle is needed to unload the image.\r
+  @param ImageContext - Input data returned from PE Laoder Library. Used to find the\r
+                 .PDB file name of the PE Image.\r
+  @param ModHandle    - Returned from LoadLibraryEx() and stored for call to\r
+                 FreeLibrary().\r
+  @return   return EFI_SUCCESS when ModHandle was stored.\r
+--*/\r
+EFI_STATUS\r
+AddModHandle (\r
+  IN  PE_COFF_LOADER_IMAGE_CONTEXT  *ImageContext,\r
+  IN  VOID                          *ModHandle\r
+  )\r
+\r
+{\r
+  UINTN                   Index;\r
+  PDB_NAME_TO_MOD_HANDLE  *Array;\r
+  UINTN                   PreviousSize;\r
+  PDB_NAME_TO_MOD_HANDLE  *TempArray;\r
+  HANDLE                  Handle;\r
+  UINTN                   Size;\r
+\r
+  //\r
+  // Return EFI_ALREADY_STARTED if this DLL has already been loaded\r
+  //\r
+  Array = mPdbNameModHandleArray;\r
+  for (Index = 0; Index < mPdbNameModHandleArraySize; Index++, Array++) {\r
+    if ((Array->PdbPointer != NULL) && (Array->ModHandle == ModHandle)) {\r
+      return EFI_ALREADY_STARTED;\r
+    }\r
+  }\r
+\r
+  Array = mPdbNameModHandleArray;\r
+  for (Index = 0; Index < mPdbNameModHandleArraySize; Index++, Array++) {\r
+    if (Array->PdbPointer == NULL) {\r
+      //\r
+      // Make a copy of the stirng and store the ModHandle\r
+      //\r
+      Handle            = GetProcessHeap ();\r
+      Size              = AsciiStrLen (ImageContext->PdbPointer) + 1;\r
+      Array->PdbPointer = HeapAlloc (Handle, HEAP_ZERO_MEMORY, Size);\r
+      ASSERT (Array->PdbPointer != NULL);\r
+\r
+      AsciiStrCpyS (Array->PdbPointer, Size, ImageContext->PdbPointer);\r
+      Array->ModHandle = ModHandle;\r
+      return EFI_SUCCESS;\r
+    }\r
+  }\r
+\r
+  //\r
+  // No free space in mPdbNameModHandleArray so grow it by\r
+  // MAX_PDB_NAME_TO_MOD_HANDLE_ARRAY_SIZE entires.\r
+  //\r
+  PreviousSize                = mPdbNameModHandleArraySize * sizeof (PDB_NAME_TO_MOD_HANDLE);\r
+  mPdbNameModHandleArraySize += MAX_PDB_NAME_TO_MOD_HANDLE_ARRAY_SIZE;\r
+  //\r
+  // re-allocate a new buffer and copy the old values to the new locaiton.\r
+  //\r
+  TempArray = HeapAlloc (\r
+                GetProcessHeap (),\r
+                HEAP_ZERO_MEMORY,\r
+                mPdbNameModHandleArraySize * sizeof (PDB_NAME_TO_MOD_HANDLE)\r
+                );\r
+\r
+  CopyMem ((VOID *)(UINTN)TempArray, (VOID *)(UINTN)mPdbNameModHandleArray, PreviousSize);\r
+\r
+  HeapFree (GetProcessHeap (), 0, mPdbNameModHandleArray);\r
+\r
+  mPdbNameModHandleArray = TempArray;\r
+  if (mPdbNameModHandleArray == NULL) {\r
+    ASSERT (FALSE);\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  return AddModHandle (ImageContext, ModHandle);\r
+}\r
+\r
+/**\r
+  Return the ModHandle and delete the entry in the array.\r
+   @param  ImageContext - Input data returned from PE Laoder Library. Used to find the\r
+                 .PDB file name of the PE Image.\r
+  @return\r
+    ModHandle - ModHandle assoicated with ImageContext is returned\r
+    NULL      - No ModHandle associated with ImageContext\r
+**/\r
+VOID *\r
+RemoveModHandle (\r
+  IN  PE_COFF_LOADER_IMAGE_CONTEXT  *ImageContext\r
+  )\r
+{\r
+  UINTN                   Index;\r
+  PDB_NAME_TO_MOD_HANDLE  *Array;\r
+\r
+  if (ImageContext->PdbPointer == NULL) {\r
+    //\r
+    // If no PDB pointer there is no ModHandle so return NULL\r
+    //\r
+    return NULL;\r
+  }\r
+\r
+  Array = mPdbNameModHandleArray;\r
+  for (Index = 0; Index < mPdbNameModHandleArraySize; Index++, Array++) {\r
+    if ((Array->PdbPointer != NULL) && (AsciiStrCmp (Array->PdbPointer, ImageContext->PdbPointer) == 0)) {\r
+      //\r
+      // If you find a match return it and delete the entry\r
+      //\r
+      HeapFree (GetProcessHeap (), 0, Array->PdbPointer);\r
+      Array->PdbPointer = NULL;\r
+      return Array->ModHandle;\r
+    }\r
+  }\r
+\r
+  return NULL;\r
+}\r
 \r
 VOID\r
 EFIAPI\r
 PeCoffLoaderRelocateImageExtraAction (\r
-  IN OUT PE_COFF_LOADER_IMAGE_CONTEXT         *ImageContext\r
+  IN OUT PE_COFF_LOADER_IMAGE_CONTEXT  *ImageContext\r
   )\r
 {\r
-  VOID              *DllEntryPoint;\r
-  CHAR16            *DllFileName;\r
-  HMODULE           Library;\r
-  UINTN             Index;\r
+  EFI_STATUS  Status;\r
+  VOID        *DllEntryPoint;\r
+  CHAR16      *DllFileName;\r
+  HMODULE     Library;\r
+  UINTN       Index;\r
 \r
   ASSERT (ImageContext != NULL);\r
   //\r
   // If we load our own PE COFF images the Windows debugger can not source\r
-  //  level debug our code. If a valid PDB pointer exists usw it to load\r
+  //  level debug our code. If a valid PDB pointer exists use it to load\r
   //  the *.dll file as a library using Windows* APIs. This allows\r
   //  source level debug. The image is still loaded and relocated\r
   //  in the Framework memory space like on a real system (by the code above),\r
-  //  but the entry point points into the DLL loaded by the code bellow.\r
+  //  but the entry point points into the DLL loaded by the code below.\r
   //\r
 \r
   DllEntryPoint = NULL;\r
@@ -874,7 +1081,8 @@ PeCoffLoaderRelocateImageExtraAction (
   // Load the DLL if it's not an EBC image.\r
   //\r
   if ((ImageContext->PdbPointer != NULL) &&\r
-      (ImageContext->Machine != EFI_IMAGE_MACHINE_EBC)) {\r
+      (ImageContext->Machine != EFI_IMAGE_MACHINE_EBC))\r
+  {\r
     //\r
     // Convert filename from ASCII to Unicode\r
     //\r
@@ -883,7 +1091,7 @@ PeCoffLoaderRelocateImageExtraAction (
     //\r
     // Check that we have a valid filename\r
     //\r
-    if (Index < 5 || DllFileName[Index - 4] != '.') {\r
+    if ((Index < 5) || (DllFileName[Index - 4] != '.')) {\r
       free (DllFileName);\r
 \r
       //\r
@@ -893,12 +1101,13 @@ PeCoffLoaderRelocateImageExtraAction (
       //\r
       return;\r
     }\r
+\r
     //\r
     // Replace .PDB with .DLL on the filename\r
     //\r
-    DllFileName[Index - 3]  = 'D';\r
-    DllFileName[Index - 2]  = 'L';\r
-    DllFileName[Index - 1]  = 'L';\r
+    DllFileName[Index - 3] = 'D';\r
+    DllFileName[Index - 2] = 'L';\r
+    DllFileName[Index - 1] = 'L';\r
 \r
     //\r
     // Load the .DLL file into the user process's address space for source\r
@@ -914,15 +1123,26 @@ PeCoffLoaderRelocateImageExtraAction (
       // checking as the we can point to the PE32 image loaded by Tiano. This\r
       // step is only needed for source level debugging\r
       //\r
-      DllEntryPoint = (VOID *) (UINTN) GetProcAddress (Library, "InitializeDriver");\r
-\r
+      DllEntryPoint = (VOID *)(UINTN)GetProcAddress (Library, "InitializeDriver");\r
     }\r
 \r
     if ((Library != NULL) && (DllEntryPoint != NULL)) {\r
-      ImageContext->EntryPoint  = (EFI_PHYSICAL_ADDRESS) (UINTN) DllEntryPoint;\r
-      SecPrint ("LoadLibraryEx (%S,\n               NULL, DONT_RESOLVE_DLL_REFERENCES)\n", DllFileName);\r
+      Status = AddModHandle (ImageContext, Library);\r
+      if (Status == EFI_ALREADY_STARTED) {\r
+        //\r
+        // If the DLL has already been loaded before, then this instance of the DLL can not be debugged.\r
+        //\r
+        ImageContext->PdbPointer = NULL;\r
+        SecPrint ("WARNING: DLL already loaded.  No source level debug %S.\n\r", DllFileName);\r
+      } else {\r
+        //\r
+        // This DLL is not already loaded, so source level debugging is supported.\r
+        //\r
+        ImageContext->EntryPoint = (EFI_PHYSICAL_ADDRESS)(UINTN)DllEntryPoint;\r
+        SecPrint ("LoadLibraryEx (\n\r  %S,\n\r  NULL, DONT_RESOLVE_DLL_REFERENCES)\n\r", DllFileName);\r
+      }\r
     } else {\r
-      SecPrint ("WARNING: No source level debug %S. \n", DllFileName);\r
+      SecPrint ("WARNING: No source level debug %S. \n\r", DllFileName);\r
     }\r
 \r
     free (DllFileName);\r
@@ -932,12 +1152,21 @@ PeCoffLoaderRelocateImageExtraAction (
 VOID\r
 EFIAPI\r
 PeCoffLoaderUnloadImageExtraAction (\r
-  IN PE_COFF_LOADER_IMAGE_CONTEXT         *ImageContext\r
-)\r
+  IN PE_COFF_LOADER_IMAGE_CONTEXT  *ImageContext\r
+  )\r
 {\r
+  VOID  *ModHandle;\r
+\r
   ASSERT (ImageContext != NULL);\r
-}\r
 \r
+  ModHandle = RemoveModHandle (ImageContext);\r
+  if (ModHandle != NULL) {\r
+    FreeLibrary (ModHandle);\r
+    SecPrint ("FreeLibrary (\n\r  %s)\n\r", ImageContext->PdbPointer);\r
+  } else {\r
+    SecPrint ("WARNING: Unload image without source level debug\n\r");\r
+  }\r
+}\r
 \r
 VOID\r
 _ModuleEntryPoint (\r