-/*++\r
-\r
-Copyright (c) 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
-#include "MemoryStatusCode.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
-\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
-EFI_STATUS\r
-EFIAPI\r
-MemoryStatusCodeInitialize (\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
- EFI_PEI_PROGRESS_CODE_PPI *ReportStatusCodePpi;\r
- EFI_PHYSICAL_ADDRESS Buffer;\r
- VOID *StartPointer;\r
- UINT32 Length;\r
- UINT32 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 (!gRunningFromMemory) {\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 Status;\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
- (VOID **) &PrivateData\r
- );\r
-\r
- //\r
- // This is not a required feature to boot.\r
- //\r
- if (EFI_ERROR (Status)) {\r
- return Status;\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
- PrivateData->NotifyDescriptor.Flags =\r
- (\r
- EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK |\r
- EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST\r
- );\r
- PrivateData->NotifyDescriptor.Guid = &gEfiPeiFvFileLoaderPpiGuid;\r
- PrivateData->NotifyDescriptor.Notify = LoadImageCallback;\r
-\r
- //\r
- // Publish the PPI\r
- //\r
- Status = (*PeiServices)->InstallPpi (PeiServices, &PrivateData->PpiDescriptor);\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
- //\r
- // Post a callback to relocate to memory\r
- //\r
- Status = (**PeiServices).NotifyPpi (PeiServices, &PrivateData->NotifyDescriptor);\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\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
- (VOID **) &StatusCodeMemoryPpi\r
- );\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
- //\r
- // Get private data\r
- //\r
- PrivateData = _CR (StatusCodeMemoryDescriptor, MEMORY_STATUS_CODE_INSTANCE, PpiDescriptor);\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->NotifyDescriptor.Guid = &gEfiPeiFvFileLoaderPpiGuid;\r
- PrivateData->NotifyDescriptor.Notify = LoadImageCallback;\r
- PrivateData->This = PrivateData;\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 Status;\r
- }\r
-\r
- DEBUG_CODE (\r
- ZeroMem ((VOID *) (UINTN) Buffer, PEI_STATUS_CODE_RT_LENGTH);\r
- );\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 Status;\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
- &gEfiPeiStatusCodePpiGuid,\r
- 0,\r
- &ReportStatusCodeDescriptor,\r
- (VOID **) &ReportStatusCodePpi\r
- );\r
- if (EFI_ERROR (Status)) {\r
- return Status;\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
- CpuBreakpoint ();\r
- return Status;\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
-\r
- BuildGuidDataHob (\r
- &gPeiStatusCodeMemoryPpiGuid,\r
- &StatusCodeMemoryPpi,\r
- sizeof (VOID *)\r
- );\r
- }\r
- return EFI_SUCCESS;\r
-}\r
-\r
-EFI_STATUS\r
-MemoryReportStatusCode (\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
- UINT32 LastEntry;\r
- MEMORY_STATUS_CODE_INSTANCE *PrivateData;\r
- EFI_PEI_PPI_DESCRIPTOR *StatusCodeMemoryDescriptor;\r
- EFI_PEI_SERVICES **PeiServices;\r
-\r
- PeiServices = GetPeiServicesTablePointer ();\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 (!gRunningFromMemory) {\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
- (VOID **) &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 = _CR (StatusCodeMemoryDescriptor, MEMORY_STATUS_CODE_INSTANCE, PpiDescriptor);\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->NotifyDescriptor.Guid = &gEfiPeiFvFileLoaderPpiGuid;\r
- PrivateData->NotifyDescriptor.Notify = LoadImageCallback;\r
- PrivateData->This = PrivateData;\r
-\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
-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 (!gRunningFromMemory) {\r
- //\r
- // Use the callback descriptor to get the FfsHeader\r
- //\r
- PrivateData = _CR (NotifyDescriptor, MEMORY_STATUS_CODE_INSTANCE, 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
- gRunningFromMemory = TRUE;\r
-#else\r
- * (BOOLEAN *) ((UINTN) &gRunningFromMemory + (UINTN) EntryPoint - (UINTN) _ModuleEntryPoint) = 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