]> git.proxmox.com Git - mirror_edk2.git/blobdiff - EdkCompatibilityPkg/Sample/Platform/Generic/MonoStatusCode/Library/Pei/MemoryStatusCode/MemoryStatusCode.c
Add in more library for ECP.
[mirror_edk2.git] / EdkCompatibilityPkg / Sample / Platform / Generic / MonoStatusCode / Library / Pei / MemoryStatusCode / MemoryStatusCode.c
diff --git a/EdkCompatibilityPkg/Sample/Platform/Generic/MonoStatusCode/Library/Pei/MemoryStatusCode/MemoryStatusCode.c b/EdkCompatibilityPkg/Sample/Platform/Generic/MonoStatusCode/Library/Pei/MemoryStatusCode/MemoryStatusCode.c
new file mode 100644 (file)
index 0000000..be82428
--- /dev/null
@@ -0,0 +1,521 @@
+/*++\r
+\r
+Copyright (c) 2004 - 2006, Intel Corporation                                                         \r
+All rights reserved. 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
+\r
+Module Name:\r
+  \r
+  MemoryStatusCode.c\r
+   \r
+Abstract:\r
+\r
+  Lib to provide memory journal status code reporting Routines.\r
+\r
+--*/\r
+\r
+#include "MemoryStatusCode.h"\r
+#include "PeiLib.h"\r
+#include "MonoStatusCode.h"\r
+\r
+//\r
+// Global variable.  Not accessible while running from flash.\r
+// After we relocate ourselves into memory, we update this\r
+// and use it to determine if we are running from flash or memory.\r
+//\r
+BOOLEAN                       mRunningFromMemory = FALSE;\r
+\r
+//\r
+// Global variable used to replace the PPI once we start running from memory.\r
+//\r
+PEI_STATUS_CODE_MEMORY_PPI    mStatusCodeMemoryPpi = { 0, 0, 0, 0 };\r
+\r
+//\r
+// PPI descriptor for the MonoStatusCode PEIM, see MonoStatusCode.c\r
+//\r
+extern EFI_PEI_PPI_DESCRIPTOR mPpiListStatusCode;\r
+\r
+VOID\r
+EFIAPI\r
+MemoryInitializeStatusCode (\r
+  IN EFI_FFS_FILE_HEADER       *FfsHeader,\r
+  IN EFI_PEI_SERVICES          **PeiServices\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Initialization routine.\r
+  Allocates heap space for storing Status Codes.\r
+  Installs a PPI to point to that heap space.\r
+  Installs a callback to switch to memory.\r
+  Installs a callback to \r
+\r
+Arguments: \r
+\r
+  FfsHeader   - FV this PEIM was loaded from.\r
+  PeiServices - General purpose services available to every PEIM.\r
+\r
+Returns: \r
+\r
+  None\r
+\r
+--*/\r
+{\r
+  EFI_STATUS                  Status;\r
+  MEMORY_STATUS_CODE_INSTANCE *PrivateData;\r
+  PEI_STATUS_CODE_MEMORY_PPI  *StatusCodeMemoryPpi;\r
+  PEI_STATUS_CODE_PPI         *ReportStatusCodePpi;\r
+  EFI_PHYSICAL_ADDRESS        Buffer;\r
+  VOID                        *StartPointer;\r
+  UINTN                       Length;\r
+  UINTN                       LastEntry;\r
+  EFI_PEI_PPI_DESCRIPTOR      *ReportStatusCodeDescriptor;\r
+  EFI_PEI_PPI_DESCRIPTOR      *StatusCodeMemoryDescriptor;\r
+\r
+  //\r
+  // Determine if we are being called after relocation into memory.\r
+  //\r
+  if (!mRunningFromMemory) {\r
+    //\r
+    // If we are not running from memory, we need to allocate some heap and\r
+    // install the PPI\r
+    //\r
+    //\r
+    // Allocate heap storage for the journal\r
+    //\r
+    Status = (*PeiServices)->AllocatePool (\r
+                              PeiServices,\r
+                              PEI_STATUS_CODE_HEAP_LENGTH,\r
+                              &StartPointer\r
+                              );\r
+\r
+    //\r
+    // This is not a required feature to boot.\r
+    //\r
+    if (EFI_ERROR (Status)) {\r
+      return ;\r
+    }\r
+    //\r
+    // Allocate heap storage for private data\r
+    // The private data contains the FFS header for this PEIM,\r
+    // a PPI containing information about the status code journal, and\r
+    // a notification for the LoadFile service, to relocate the PEIM into\r
+    // memory.\r
+    //\r
+    Status = (*PeiServices)->AllocatePool (\r
+                              PeiServices,\r
+                              sizeof (MEMORY_STATUS_CODE_INSTANCE),\r
+                              &PrivateData\r
+                              );\r
+\r
+    //\r
+    // This is not a required feature to boot.\r
+    //\r
+    if (EFI_ERROR (Status)) {\r
+      return ;\r
+    }\r
+    //\r
+    // Update the contents of the private data.\r
+    //\r
+    PrivateData->Signature                      = MEMORY_STATUS_CODE_SIGNATURE;\r
+    PrivateData->This = PrivateData;\r
+    PrivateData->FfsHeader = FfsHeader;\r
+    PrivateData->PpiDescriptor.Flags = (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST);\r
+    PrivateData->PpiDescriptor.Guid = &gPeiStatusCodeMemoryPpiGuid;\r
+    PrivateData->PpiDescriptor.Ppi = &PrivateData->StatusCodeMemoryPpi;\r
+    PrivateData->StatusCodeMemoryPpi.FirstEntry = 0;\r
+    PrivateData->StatusCodeMemoryPpi.LastEntry = 0;\r
+    PrivateData->StatusCodeMemoryPpi.Address = (EFI_PHYSICAL_ADDRESS) (UINTN) StartPointer;\r
+    PrivateData->StatusCodeMemoryPpi.Length = PEI_STATUS_CODE_HEAP_LENGTH;\r
+#if (PI_SPECIFICATION_VERSION < 0x00010000)\r
+    PrivateData->NotifyDescriptor.Flags =\r
+      (\r
+        EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK |\r
+        EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST\r
+      );\r
+    PrivateData->NotifyDescriptor.Guid    = &gPeiFvFileLoaderPpiGuid;\r
+    PrivateData->NotifyDescriptor.Notify  = LoadImageCallback;\r
+#endif\r
+    //\r
+    // Publish the PPI\r
+    //\r
+    Status = (*PeiServices)->InstallPpi (PeiServices, &PrivateData->PpiDescriptor);\r
+    if (EFI_ERROR (Status)) {\r
+      return ;\r
+    }\r
+    //\r
+    // Post a callback to relocate to memory\r
+    //\r
+#if (PI_SPECIFICATION_VERSION < 0x00010000)\r
+    Status = (**PeiServices).NotifyPpi (PeiServices, &PrivateData->NotifyDescriptor);\r
+    if (EFI_ERROR (Status)) {\r
+      return ;\r
+    }\r
+#endif\r
+  } else {\r
+    //\r
+    // If we are running from memory, we need to copy from the heap to a RT\r
+    // memory buffer.\r
+    //\r
+    //\r
+    // Locate Journal\r
+    //\r
+    Status = (*PeiServices)->LocatePpi (\r
+                              PeiServices,\r
+                              &gPeiStatusCodeMemoryPpiGuid,\r
+                              0,\r
+                              &StatusCodeMemoryDescriptor,\r
+                              &StatusCodeMemoryPpi\r
+                              );\r
+    if (EFI_ERROR (Status)) {\r
+      return ;\r
+    }\r
+    //\r
+    // Get private data\r
+    //\r
+    PrivateData = MEMORY_STATUS_CODE_FROM_DESCRIPTOR_THIS (StatusCodeMemoryDescriptor);\r
+\r
+    //\r
+    // At this point, we need to fix up any addresses that we have as the heap\r
+    // has moved.\r
+    //\r
+    PrivateData->PpiDescriptor.Ppi  = &PrivateData->StatusCodeMemoryPpi;\r
+    PrivateData->PpiDescriptor.Guid = &gPeiStatusCodeMemoryPpiGuid;\r
+    PrivateData->StatusCodeMemoryPpi.Address = PrivateData->StatusCodeMemoryPpi.Address +\r
+      (UINTN) PrivateData - (UINTN) PrivateData->This;\r
+    PrivateData->This                     = PrivateData;\r
+#if (PI_SPECIFICATION_VERSION < 0x00010000)\r
+    PrivateData->NotifyDescriptor.Guid    = &gPeiFvFileLoaderPpiGuid;\r
+    PrivateData->NotifyDescriptor.Notify  = LoadImageCallback;\r
+#endif\r
+\r
+    //\r
+    // Allocate RT memory.\r
+    //\r
+    Status = (*PeiServices)->AllocatePages (\r
+                              PeiServices,\r
+                              EfiRuntimeServicesData,\r
+                              PEI_STATUS_CODE_RT_PAGES,\r
+                              &Buffer\r
+                              );\r
+    if (EFI_ERROR (Status)) {\r
+      return ;\r
+    }\r
+\r
+    DEBUG_CODE (\r
+      EfiCommonLibZeroMem ((VOID *) (UINTN) Buffer, PEI_STATUS_CODE_RT_LENGTH);\r
+    )\r
+    //\r
+    // Copy the heap to the allocated memory.\r
+    // Unwind the rolling queue to start at 0 in the new space.  We need to do\r
+    // this because the new queue is much bigger than the heap allocation.\r
+    //\r
+    if (PEI_STATUS_CODE_RT_LENGTH <= PEI_STATUS_CODE_HEAP_LENGTH) {\r
+      return ;\r
+    }\r
+\r
+    if (StatusCodeMemoryPpi->LastEntry >= StatusCodeMemoryPpi->FirstEntry) {\r
+      LastEntry = StatusCodeMemoryPpi->LastEntry - StatusCodeMemoryPpi->FirstEntry;\r
+      StartPointer = (VOID *) ((UINTN) StatusCodeMemoryPpi->Address + (StatusCodeMemoryPpi->FirstEntry * sizeof (EFI_STATUS_CODE_ENTRY)));\r
+      Length = (StatusCodeMemoryPpi->LastEntry - StatusCodeMemoryPpi->FirstEntry) * sizeof (EFI_STATUS_CODE_ENTRY);\r
+      (*PeiServices)->CopyMem ((VOID *) (UINTN) Buffer, StartPointer, Length);\r
+    } else {\r
+      //\r
+      // The last entry will be the new last entry after moving heap to buffer\r
+      //\r
+      LastEntry = (PEI_STATUS_CODE_MAX_HEAP_ENTRY - StatusCodeMemoryPpi->FirstEntry) + StatusCodeMemoryPpi->LastEntry;\r
+      //\r
+      // Copy from the first entry to the end of the heap\r
+      //\r
+      StartPointer = (VOID *) ((UINTN) StatusCodeMemoryPpi->Address + (StatusCodeMemoryPpi->FirstEntry * sizeof (EFI_STATUS_CODE_ENTRY)));\r
+      Length = PEI_STATUS_CODE_HEAP_LENGTH - (StatusCodeMemoryPpi->FirstEntry * sizeof (EFI_STATUS_CODE_ENTRY));\r
+      (*PeiServices)->CopyMem ((VOID *) (UINTN) Buffer, StartPointer, Length);\r
+      //\r
+      // Copy from the start to the heap to the last entry\r
+      //\r
+      StartPointer = (VOID *) (UINTN) StatusCodeMemoryPpi->Address;\r
+      (*PeiServices)->CopyMem (\r
+                        (VOID *) (UINTN) (Buffer + Length),\r
+                        StartPointer,\r
+                        (StatusCodeMemoryPpi->LastEntry * sizeof (EFI_STATUS_CODE_ENTRY))\r
+                        );\r
+    };\r
+\r
+    //\r
+    // Update the PPI to NULL, so it will not be used.\r
+    //\r
+    StatusCodeMemoryPpi->FirstEntry = 0;\r
+    StatusCodeMemoryPpi->LastEntry  = 0;\r
+    StatusCodeMemoryPpi->Address    = 0;\r
+    StatusCodeMemoryPpi->Length     = 0;\r
+\r
+    //\r
+    // Update in memory version of PPI that will be used.\r
+    //\r
+    mStatusCodeMemoryPpi.FirstEntry = 0;\r
+    mStatusCodeMemoryPpi.LastEntry  = LastEntry;\r
+    mStatusCodeMemoryPpi.Address    = (EFI_PHYSICAL_ADDRESS) (UINTN) Buffer;\r
+    mStatusCodeMemoryPpi.Length     = PEI_STATUS_CODE_RT_LENGTH;\r
+\r
+    //\r
+    // Reinstall the report status code function\r
+    //\r
+    //\r
+    // Locate status code PPI\r
+    //\r
+    Status = (*PeiServices)->LocatePpi (\r
+                              PeiServices,\r
+                              &gPeiStatusCodePpiGuid,\r
+                              0,\r
+                              &ReportStatusCodeDescriptor,\r
+                              &ReportStatusCodePpi\r
+                              );\r
+    if (EFI_ERROR (Status)) {\r
+      return ;\r
+    }\r
+    //\r
+    // Reinstall the ReportStatusCode interface using the memory-based\r
+    // descriptor\r
+    //\r
+    Status = (*PeiServices)->ReInstallPpi (\r
+                              PeiServices,\r
+                              ReportStatusCodeDescriptor,\r
+                              &mPpiListStatusCode\r
+                              );\r
+    if (EFI_ERROR (Status)) {\r
+      EFI_BREAKPOINT ();\r
+      return ;\r
+    }\r
+    //\r
+    // Publish a GUIDed HOB that contains a pointer to the status code PPI\r
+    // structure.  This is a bit of a short cut as I just used the PPI GUID to\r
+    // identify the HOB.  This HOB is caught by the DXE status code memory\r
+    // listener and used to find the journal.\r
+    //\r
+    StatusCodeMemoryPpi = &mStatusCodeMemoryPpi;\r
+    Status = PeiBuildHobGuidData (\r
+              PeiServices,\r
+              &gPeiStatusCodeMemoryPpiGuid,\r
+              &StatusCodeMemoryPpi,\r
+              sizeof (VOID *)\r
+              );\r
+    if (EFI_ERROR (Status)) {\r
+      EFI_BREAKPOINT ();\r
+      return ;\r
+    }\r
+  }\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+MemoryReportStatusCode (\r
+  IN EFI_PEI_SERVICES         **PeiServices,\r
+  IN EFI_STATUS_CODE_TYPE     CodeType,\r
+  IN EFI_STATUS_CODE_VALUE    Value,\r
+  IN UINT32                   Instance,\r
+  IN EFI_GUID                 * CallerId ,\r
+  IN EFI_STATUS_CODE_DATA     * Data OPTIONAL\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Provide a memory status code\r
+\r
+Arguments:\r
+\r
+  Same as ReportStatusCode PPI\r
+    \r
+Returns:\r
+\r
+  EFI_SUCCESS   This function always returns success\r
+\r
+--*/\r
+{\r
+  EFI_STATUS                  Status;\r
+  PEI_STATUS_CODE_MEMORY_PPI  *StatusCodeMemoryPpi;\r
+  EFI_STATUS_CODE_ENTRY       *CurrentEntry;\r
+  UINTN                       LastEntry;\r
+  MEMORY_STATUS_CODE_INSTANCE *PrivateData;\r
+  EFI_PEI_PPI_DESCRIPTOR      *StatusCodeMemoryDescriptor;\r
+\r
+  //\r
+  // We don't care to log debug codes.\r
+  //\r
+  if ((CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_DEBUG_CODE) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  if (!mRunningFromMemory) {\r
+    //\r
+    // If we are called from DXE and have not been reinstalled into memory, we\r
+    // can no longer locate the journal, so we can no longer log status codes.\r
+    //\r
+    if (!PeiServices) {\r
+      return EFI_SUCCESS;\r
+    }\r
+    //\r
+    // Locate Journal\r
+    //\r
+    Status = (*PeiServices)->LocatePpi (\r
+                              PeiServices,\r
+                              &gPeiStatusCodeMemoryPpiGuid,\r
+                              0,\r
+                              &StatusCodeMemoryDescriptor,\r
+                              &StatusCodeMemoryPpi\r
+                              );\r
+    if (EFI_ERROR (Status)) {\r
+      return EFI_SUCCESS;\r
+    }\r
+    //\r
+    // Determine the last entry in the journal.\r
+    // This is needed to properly implement the rolling queue.\r
+    //\r
+    LastEntry = PEI_STATUS_CODE_MAX_HEAP_ENTRY;\r
+\r
+    //\r
+    // Get private data\r
+    //\r
+    PrivateData = MEMORY_STATUS_CODE_FROM_DESCRIPTOR_THIS (StatusCodeMemoryDescriptor);\r
+\r
+    //\r
+    // Once memory gets installed, heap gets moved to real memory.\r
+    // We need to fix up the pointers to match the move.\r
+    //\r
+    PrivateData->PpiDescriptor.Ppi  = &PrivateData->StatusCodeMemoryPpi;\r
+    PrivateData->PpiDescriptor.Guid = &gPeiStatusCodeMemoryPpiGuid;\r
+    PrivateData->StatusCodeMemoryPpi.Address = PrivateData->StatusCodeMemoryPpi.Address +\r
+      (UINTN) PrivateData - (UINTN) PrivateData->This;\r
+    PrivateData->This                     = PrivateData;\r
+#if (PI_SPECIFICATION_VERSION < 0x00010000)\r
+    PrivateData->NotifyDescriptor.Guid    = &gPeiFvFileLoaderPpiGuid;\r
+    PrivateData->NotifyDescriptor.Notify  = LoadImageCallback;\r
+#endif\r
+    StatusCodeMemoryPpi                   = PrivateData->PpiDescriptor.Ppi;\r
+  } else {\r
+    //\r
+    // Use global/memory copy of the PPI\r
+    //\r
+    StatusCodeMemoryPpi = &mStatusCodeMemoryPpi;\r
+\r
+    //\r
+    // Determine the last entry in the journal.\r
+    // This is needed to properly implement the rolling queue.\r
+    //\r
+    LastEntry = PEI_STATUS_CODE_MAX_RT_ENTRY;\r
+  }\r
+  //\r
+  // Return if we are using a cleared PPI somehow\r
+  //\r
+  if (!StatusCodeMemoryPpi->Address || !StatusCodeMemoryPpi->Length) {\r
+    return EFI_SUCCESS;\r
+  }\r
+  //\r
+  // Update the latest entry in the journal (may actually be first due to rolling\r
+  // queue).\r
+  //\r
+  CurrentEntry = (EFI_STATUS_CODE_ENTRY *) (UINTN) (StatusCodeMemoryPpi->Address + (StatusCodeMemoryPpi->LastEntry * sizeof (EFI_STATUS_CODE_ENTRY)));\r
+\r
+  StatusCodeMemoryPpi->LastEntry = (StatusCodeMemoryPpi->LastEntry + 1) % LastEntry;\r
+  if (StatusCodeMemoryPpi->LastEntry == StatusCodeMemoryPpi->FirstEntry) {\r
+    StatusCodeMemoryPpi->FirstEntry = (StatusCodeMemoryPpi->FirstEntry + 1) % LastEntry;\r
+  }\r
+\r
+  CurrentEntry->Type      = CodeType;\r
+  CurrentEntry->Value     = Value;\r
+  CurrentEntry->Instance  = Instance;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+#if (PI_SPECIFICATION_VERSION < 0x00010000)\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+LoadImageCallback (\r
+  IN EFI_PEI_SERVICES           **PeiServices,\r
+  IN EFI_PEI_NOTIFY_DESCRIPTOR  *NotifyDescriptor,\r
+  IN VOID                       *Ppi\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Relocate the PEIM into memory.\r
+\r
+  Once load protocol becomes available, relocate our PEIM into memory.\r
+  The primary benefit is to eliminate the blackout window that we would have in\r
+  the memory log between the end of PEI and the status code DXE driver taking\r
+  control.  If we don't do this, we cannot determine where our memory journal\r
+  is located and cannot function.\r
+\r
+  A second benefit is speed optimization throughout DXE.\r
+\r
+Arguments:\r
+\r
+  PeiServices      - General purpose services available to every PEIM.\r
+  NotifyDescriptor - Information about the notify event.\r
+  Ppi              - Context\r
+    \r
+Returns:\r
+\r
+  EFI_SUCCESS   This function always returns success.\r
+\r
+--*/\r
+{\r
+  EFI_STATUS                  Status;\r
+  EFI_PHYSICAL_ADDRESS        ImageAddress;\r
+  EFI_PHYSICAL_ADDRESS        EntryPoint;\r
+  UINT64                      ImageSize;\r
+  MEMORY_STATUS_CODE_INSTANCE *PrivateData;\r
+\r
+  //\r
+  // Relocate to memory\r
+  //\r
+  if (!mRunningFromMemory) {\r
+    //\r
+    // Use the callback descriptor to get the FfsHeader\r
+    //\r
+    PrivateData = MEMORY_STATUS_CODE_FROM_NOTIFY_THIS (NotifyDescriptor);\r
+\r
+    Status = ((EFI_PEI_FV_FILE_LOADER_PPI *) Ppi)->FvLoadFile (\r
+                                                    Ppi,\r
+                                                    PrivateData->FfsHeader,\r
+                                                    &ImageAddress,\r
+                                                    &ImageSize,\r
+                                                    &EntryPoint\r
+                                                    );\r
+    if (EFI_ERROR (Status)) {\r
+      return EFI_SUCCESS;\r
+    }\r
+    //\r
+    // Set the flag in the loaded image that indicates the PEIM is executing\r
+    // from memory.\r
+    //\r
+#ifdef EFI_NT_EMULATOR\r
+    //\r
+    // For NT32, we should also relocate image here, because if the DLL\r
+    // is already load, we will NOT load it twice. This feature is added to\r
+    // prevent loading driver twice in DXE phase cause system crash.\r
+    //\r
+    * (BOOLEAN *) ((UINTN) &mRunningFromMemory + (UINTN) EntryPoint - (UINTN) InstallMonoStatusCode) = TRUE;\r
+#else\r
+    * (BOOLEAN *) ((UINTN) &mRunningFromMemory + (UINTN) EntryPoint - (UINTN) InstallMonoStatusCode) = TRUE;\r
+#endif\r
+    Status = ((EFI_PEIM_ENTRY_POINT )(UINTN) EntryPoint) (PrivateData->FfsHeader, PeiServices);\r
+    if (EFI_ERROR (Status)) {\r
+      return EFI_SUCCESS;\r
+    }\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+#endif\r
+\r