From 878ddf1fc3540a715f63594ed22b6929e881afb4 Mon Sep 17 00:00:00 2001 From: bbahnsen Date: Fri, 21 Apr 2006 22:54:32 +0000 Subject: Initial import. git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@3 6f19259b-4bc3-4df7-8a09-765794883524 --- .../EdkMemoryStatusCodeLib/MemoryStatusCode.c | 498 +++++++++++++++++++++ 1 file changed, 498 insertions(+) create mode 100644 EdkModulePkg/Library/EdkMemoryStatusCodeLib/MemoryStatusCode.c (limited to 'EdkModulePkg/Library/EdkMemoryStatusCodeLib/MemoryStatusCode.c') diff --git a/EdkModulePkg/Library/EdkMemoryStatusCodeLib/MemoryStatusCode.c b/EdkModulePkg/Library/EdkMemoryStatusCodeLib/MemoryStatusCode.c new file mode 100644 index 0000000000..1661d7753c --- /dev/null +++ b/EdkModulePkg/Library/EdkMemoryStatusCodeLib/MemoryStatusCode.c @@ -0,0 +1,498 @@ +/*++ + +Copyright (c) 2006, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + MemoryStatusCode.c + +Abstract: + + Lib to provide memory journal status code reporting Routines. + +--*/ +#include "MemoryStatusCode.h" + +// +// Global variable. Not accessible while running from flash. +// After we relocate ourselves into memory, we update this +// and use it to determine if we are running from flash or memory. +// + +// +// Global variable used to replace the PPI once we start running from memory. +// +PEI_STATUS_CODE_MEMORY_PPI mStatusCodeMemoryPpi = { 0, 0, 0, 0 }; + +// +// PPI descriptor for the MonoStatusCode PEIM, see MonoStatusCode.c +// +extern EFI_PEI_PPI_DESCRIPTOR mPpiListStatusCode; + +EFI_STATUS +EFIAPI +MemoryStatusCodeInitialize ( + IN EFI_FFS_FILE_HEADER *FfsHeader, + IN EFI_PEI_SERVICES **PeiServices + ) +/*++ + +Routine Description: + + Initialization routine. + Allocates heap space for storing Status Codes. + Installs a PPI to point to that heap space. + Installs a callback to switch to memory. + Installs a callback to + +Arguments: + + FfsHeader - FV this PEIM was loaded from. + PeiServices - General purpose services available to every PEIM. + +Returns: + + None + +--*/ +{ + EFI_STATUS Status; + MEMORY_STATUS_CODE_INSTANCE *PrivateData; + PEI_STATUS_CODE_MEMORY_PPI *StatusCodeMemoryPpi; + EFI_PEI_PROGRESS_CODE_PPI *ReportStatusCodePpi; + EFI_PHYSICAL_ADDRESS Buffer; + VOID *StartPointer; + UINTN Length; + UINTN LastEntry; + EFI_PEI_PPI_DESCRIPTOR *ReportStatusCodeDescriptor; + EFI_PEI_PPI_DESCRIPTOR *StatusCodeMemoryDescriptor; + + // + // Determine if we are being called after relocation into memory. + // + if (!gRunningFromMemory) { + // + // If we are not running from memory, we need to allocate some heap and + // install the PPI + // + // + // Allocate heap storage for the journal + // + Status = (*PeiServices)->AllocatePool ( + PeiServices, + PEI_STATUS_CODE_HEAP_LENGTH, + &StartPointer + ); + + // + // This is not a required feature to boot. + // + if (EFI_ERROR (Status)) { + return Status; + } + // + // Allocate heap storage for private data + // The private data contains the FFS header for this PEIM, + // a PPI containing information about the status code journal, and + // a notification for the LoadFile service, to relocate the PEIM into + // memory. + // + Status = (*PeiServices)->AllocatePool ( + PeiServices, + sizeof (MEMORY_STATUS_CODE_INSTANCE), + (VOID **) &PrivateData + ); + + // + // This is not a required feature to boot. + // + if (EFI_ERROR (Status)) { + return Status; + } + // + // Update the contents of the private data. + // + PrivateData->Signature = MEMORY_STATUS_CODE_SIGNATURE; + PrivateData->This = PrivateData; + PrivateData->FfsHeader = FfsHeader; + PrivateData->PpiDescriptor.Flags = (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST); + PrivateData->PpiDescriptor.Guid = &gPeiStatusCodeMemoryPpiGuid; + PrivateData->PpiDescriptor.Ppi = &PrivateData->StatusCodeMemoryPpi; + PrivateData->StatusCodeMemoryPpi.FirstEntry = 0; + PrivateData->StatusCodeMemoryPpi.LastEntry = 0; + PrivateData->StatusCodeMemoryPpi.Address = (EFI_PHYSICAL_ADDRESS) (UINTN) StartPointer; + PrivateData->StatusCodeMemoryPpi.Length = PEI_STATUS_CODE_HEAP_LENGTH; + PrivateData->NotifyDescriptor.Flags = + ( + EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | + EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST + ); + PrivateData->NotifyDescriptor.Guid = &gEfiPeiFvFileLoaderPpiGuid; + PrivateData->NotifyDescriptor.Notify = LoadImageCallback; + + // + // Publish the PPI + // + Status = (*PeiServices)->InstallPpi (PeiServices, &PrivateData->PpiDescriptor); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Post a callback to relocate to memory + // + Status = (**PeiServices).NotifyPpi (PeiServices, &PrivateData->NotifyDescriptor); + if (EFI_ERROR (Status)) { + return Status; + } + } else { + // + // If we are running from memory, we need to copy from the heap to a RT + // memory buffer. + // + // + // Locate Journal + // + Status = (*PeiServices)->LocatePpi ( + PeiServices, + &gPeiStatusCodeMemoryPpiGuid, + 0, + &StatusCodeMemoryDescriptor, + (VOID **) &StatusCodeMemoryPpi + ); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Get private data + // + PrivateData = _CR (StatusCodeMemoryDescriptor, MEMORY_STATUS_CODE_INSTANCE, PpiDescriptor); + // + // At this point, we need to fix up any addresses that we have as the heap + // has moved. + // + PrivateData->PpiDescriptor.Ppi = &PrivateData->StatusCodeMemoryPpi; + PrivateData->PpiDescriptor.Guid = &gPeiStatusCodeMemoryPpiGuid; + PrivateData->StatusCodeMemoryPpi.Address = PrivateData->StatusCodeMemoryPpi.Address + + (UINTN) PrivateData - (UINTN) PrivateData->This; + PrivateData->NotifyDescriptor.Guid = &gEfiPeiFvFileLoaderPpiGuid; + PrivateData->NotifyDescriptor.Notify = LoadImageCallback; + PrivateData->This = PrivateData; + + // + // Allocate RT memory. + // + Status = (*PeiServices)->AllocatePages ( + PeiServices, + EfiRuntimeServicesData, + PEI_STATUS_CODE_RT_PAGES, + &Buffer + ); + if (EFI_ERROR (Status)) { + return Status; + } + + DEBUG_CODE ( + ZeroMem ((VOID *) (UINTN) Buffer, PEI_STATUS_CODE_RT_LENGTH); + ); + + // + // Copy the heap to the allocated memory. + // Unwind the rolling queue to start at 0 in the new space. We need to do + // this because the new queue is much bigger than the heap allocation. + // + if (PEI_STATUS_CODE_RT_LENGTH <= PEI_STATUS_CODE_HEAP_LENGTH) { + return Status; + } + + if (StatusCodeMemoryPpi->LastEntry >= StatusCodeMemoryPpi->FirstEntry) { + LastEntry = StatusCodeMemoryPpi->LastEntry - StatusCodeMemoryPpi->FirstEntry; + StartPointer = (VOID *) ((UINTN) StatusCodeMemoryPpi->Address + (StatusCodeMemoryPpi->FirstEntry * sizeof (EFI_STATUS_CODE_ENTRY))); + Length = (StatusCodeMemoryPpi->LastEntry - StatusCodeMemoryPpi->FirstEntry) * sizeof (EFI_STATUS_CODE_ENTRY); + (*PeiServices)->CopyMem ((VOID *) (UINTN) Buffer, StartPointer, Length); + } else { + // + // The last entry will be the new last entry after moving heap to buffer + // + LastEntry = (PEI_STATUS_CODE_MAX_HEAP_ENTRY - StatusCodeMemoryPpi->FirstEntry) + StatusCodeMemoryPpi->LastEntry; + // + // Copy from the first entry to the end of the heap + // + StartPointer = (VOID *) ((UINTN) StatusCodeMemoryPpi->Address + (StatusCodeMemoryPpi->FirstEntry * sizeof (EFI_STATUS_CODE_ENTRY))); + Length = PEI_STATUS_CODE_HEAP_LENGTH - (StatusCodeMemoryPpi->FirstEntry * sizeof (EFI_STATUS_CODE_ENTRY)); + (*PeiServices)->CopyMem ((VOID *) (UINTN) Buffer, StartPointer, Length); + // + // Copy from the start to the heap to the last entry + // + StartPointer = (VOID *) (UINTN) StatusCodeMemoryPpi->Address; + (*PeiServices)->CopyMem ( + (VOID *) (UINTN) (Buffer + Length), + StartPointer, + (StatusCodeMemoryPpi->LastEntry * sizeof (EFI_STATUS_CODE_ENTRY)) + ); + }; + + // + // Update the PPI to NULL, so it will not be used. + // + StatusCodeMemoryPpi->FirstEntry = 0; + StatusCodeMemoryPpi->LastEntry = 0; + StatusCodeMemoryPpi->Address = 0; + StatusCodeMemoryPpi->Length = 0; + + // + // Update in memory version of PPI that will be used. + // + mStatusCodeMemoryPpi.FirstEntry = 0; + mStatusCodeMemoryPpi.LastEntry = LastEntry; + mStatusCodeMemoryPpi.Address = (EFI_PHYSICAL_ADDRESS) (UINTN) Buffer; + mStatusCodeMemoryPpi.Length = PEI_STATUS_CODE_RT_LENGTH; + + // + // Reinstall the report status code function + // + // + // Locate status code PPI + // + Status = (*PeiServices)->LocatePpi ( + PeiServices, + &gEfiPeiStatusCodePpiGuid, + 0, + &ReportStatusCodeDescriptor, + (VOID **) &ReportStatusCodePpi + ); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Reinstall the ReportStatusCode interface using the memory-based + // descriptor + // + Status = (*PeiServices)->ReInstallPpi ( + PeiServices, + ReportStatusCodeDescriptor, + &mPpiListStatusCode + ); + if (EFI_ERROR (Status)) { + CpuBreakpoint (); + return Status; + } + // + // Publish a GUIDed HOB that contains a pointer to the status code PPI + // structure. This is a bit of a short cut as I just used the PPI GUID to + // identify the HOB. This HOB is caught by the DXE status code memory + // listener and used to find the journal. + // + StatusCodeMemoryPpi = &mStatusCodeMemoryPpi; + + BuildGuidDataHob ( + &gPeiStatusCodeMemoryPpiGuid, + &StatusCodeMemoryPpi, + sizeof (VOID *) + ); + } + return EFI_SUCCESS; +} + +EFI_STATUS +MemoryReportStatusCode ( + IN EFI_STATUS_CODE_TYPE CodeType, + IN EFI_STATUS_CODE_VALUE Value, + IN UINT32 Instance, + IN EFI_GUID * CallerId, + IN EFI_STATUS_CODE_DATA * Data OPTIONAL + ) +/*++ + +Routine Description: + + Provide a memory status code + +Arguments: + + Same as ReportStatusCode PPI + +Returns: + + EFI_SUCCESS This function always returns success + +--*/ +{ + EFI_STATUS Status; + PEI_STATUS_CODE_MEMORY_PPI *StatusCodeMemoryPpi; + EFI_STATUS_CODE_ENTRY *CurrentEntry; + UINTN LastEntry; + MEMORY_STATUS_CODE_INSTANCE *PrivateData; + EFI_PEI_PPI_DESCRIPTOR *StatusCodeMemoryDescriptor; + EFI_PEI_SERVICES **PeiServices; + + PeiServices = GetPeiServicesTablePointer (); + // + // We don't care to log debug codes. + // + if ((CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_DEBUG_CODE) { + return EFI_SUCCESS; + } + + if (!gRunningFromMemory) { + // + // If we are called from DXE and have not been reinstalled into memory, we + // can no longer locate the journal, so we can no longer log status codes. + // + if (!PeiServices) { + return EFI_SUCCESS; + } + // + // Locate Journal + // + Status = (*PeiServices)->LocatePpi ( + PeiServices, + &gPeiStatusCodeMemoryPpiGuid, + 0, + &StatusCodeMemoryDescriptor, + (VOID **) &StatusCodeMemoryPpi + ); + if (EFI_ERROR (Status)) { + return EFI_SUCCESS; + } + // + // Determine the last entry in the journal. + // This is needed to properly implement the rolling queue. + // + LastEntry = PEI_STATUS_CODE_MAX_HEAP_ENTRY; + + // + // Get private data + // + PrivateData = _CR (StatusCodeMemoryDescriptor, MEMORY_STATUS_CODE_INSTANCE, PpiDescriptor); + + // + // Once memory gets installed, heap gets moved to real memory. + // We need to fix up the pointers to match the move. + // + PrivateData->PpiDescriptor.Ppi = &PrivateData->StatusCodeMemoryPpi; + PrivateData->PpiDescriptor.Guid = &gPeiStatusCodeMemoryPpiGuid; + PrivateData->StatusCodeMemoryPpi.Address = PrivateData->StatusCodeMemoryPpi.Address + + (UINTN) PrivateData - (UINTN) PrivateData->This; + PrivateData->NotifyDescriptor.Guid = &gEfiPeiFvFileLoaderPpiGuid; + PrivateData->NotifyDescriptor.Notify = LoadImageCallback; + PrivateData->This = PrivateData; + + StatusCodeMemoryPpi = PrivateData->PpiDescriptor.Ppi; + } else { + // + // Use global/memory copy of the PPI + // + StatusCodeMemoryPpi = &mStatusCodeMemoryPpi; + + // + // Determine the last entry in the journal. + // This is needed to properly implement the rolling queue. + // + LastEntry = PEI_STATUS_CODE_MAX_RT_ENTRY; + } + // + // Return if we are using a cleared PPI somehow + // + if (!StatusCodeMemoryPpi->Address || !StatusCodeMemoryPpi->Length) { + return EFI_SUCCESS; + } + // + // Update the latest entry in the journal (may actually be first due to rolling + // queue). + // + CurrentEntry = (EFI_STATUS_CODE_ENTRY *) (UINTN) (StatusCodeMemoryPpi->Address + (StatusCodeMemoryPpi->LastEntry * sizeof (EFI_STATUS_CODE_ENTRY))); + + StatusCodeMemoryPpi->LastEntry = (StatusCodeMemoryPpi->LastEntry + 1) % LastEntry; + if (StatusCodeMemoryPpi->LastEntry == StatusCodeMemoryPpi->FirstEntry) { + StatusCodeMemoryPpi->FirstEntry = (StatusCodeMemoryPpi->FirstEntry + 1) % LastEntry; + } + + CurrentEntry->Type = CodeType; + CurrentEntry->Value = Value; + CurrentEntry->Instance = Instance; + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +LoadImageCallback ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor, + IN VOID *Ppi + ) +/*++ + +Routine Description: + + Relocate the PEIM into memory. + + Once load protocol becomes available, relocate our PEIM into memory. + The primary benefit is to eliminate the blackout window that we would have in + the memory log between the end of PEI and the status code DXE driver taking + control. If we don't do this, we cannot determine where our memory journal + is located and cannot function. + + A second benefit is speed optimization throughout DXE. + +Arguments: + + PeiServices - General purpose services available to every PEIM. + NotifyDescriptor - Information about the notify event. + Ppi - Context + +Returns: + + EFI_SUCCESS This function always returns success. + +--*/ +{ + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS ImageAddress; + EFI_PHYSICAL_ADDRESS EntryPoint; + UINT64 ImageSize; + MEMORY_STATUS_CODE_INSTANCE *PrivateData; + + // + // Relocate to memory + // + if (!gRunningFromMemory) { + // + // Use the callback descriptor to get the FfsHeader + // + PrivateData = _CR (NotifyDescriptor, MEMORY_STATUS_CODE_INSTANCE, NotifyDescriptor); + + Status = ((EFI_PEI_FV_FILE_LOADER_PPI *) Ppi)->FvLoadFile ( + Ppi, + PrivateData->FfsHeader, + &ImageAddress, + &ImageSize, + &EntryPoint + ); + if (EFI_ERROR (Status)) { + return EFI_SUCCESS; + } + // + // Set the flag in the loaded image that indicates the PEIM is executing + // from memory. + // +#ifdef EFI_NT_EMULATOR + gRunningFromMemory = TRUE; +#else + * (BOOLEAN *) ((UINTN) &gRunningFromMemory + (UINTN) EntryPoint - (UINTN) InstallMonoStatusCode) = TRUE; +#endif + Status = ((EFI_PEIM_ENTRY_POINT )(UINTN) EntryPoint) (PrivateData->FfsHeader, PeiServices); + if (EFI_ERROR (Status)) { + return EFI_SUCCESS; + } + } + + return EFI_SUCCESS; +} -- cgit v1.2.3