/** @file Memory Debug Log PEIM Copyright (C) 2025, Oracle and/or its affiliates. SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include #include #include #include #include #include #include #include EFI_STATUS EFIAPI MemDebugLogMemAvailCB ( IN EFI_PEI_SERVICES **PeiServices, IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor, IN VOID *Ppi ); CONST EFI_PEI_NOTIFY_DESCRIPTOR mMemAvailNotifyList[] = { { (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_DISPATCH | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), &gEfiPeiMemoryDiscoveredPpiGuid, MemDebugLogMemAvailCB } }; EFI_STATUS EFIAPI MemDebugLogMemAvailCB ( IN EFI_PEI_SERVICES **PeiServices, IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor, IN VOID *Ppi ) { UINT32 MemDebugLogBufPages; EFI_PHYSICAL_ADDRESS MemDebugLogBufAddr; EFI_HOB_GUID_TYPE *GuidHob; MEM_DEBUG_LOG_HOB_DATA *HobData; EFI_STATUS Status; MemDebugLogBufPages = MemDebugLogPages (); // // Buffer size of 0 disables memory debug logging. // if (!MemDebugLogBufPages) { MemDebugLogBufAddr = 0; Status = EFI_SUCCESS; goto done; } // // Allocate the memory debug log buffer. // NOTE: We allocate the buffer as type EfiRuntimeServicesData // as this seems to allow the buffer to persist and be // accessible/modifiable throughout runtime (i.e. and avoid // being locked down by the MemoryAttributesTable code). // Status = PeiServicesAllocatePages ( EfiRuntimeServicesData, MemDebugLogBufPages, &MemDebugLogBufAddr ); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "%a: Failed to allocate Memory Debug Log buffer: %r. Logging disabled\n", __func__, Status)); MemDebugLogBufAddr = 0; goto done; } // // Init the debug log buffer // Status = MemDebugLogInit (MemDebugLogBufAddr, (UINT32)EFI_PAGES_TO_SIZE ((UINTN)MemDebugLogBufPages)); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "%a: Failed to init Memory Debug Log buffer: %r. Logging disabled\n", __func__, Status)); PeiServicesFreePages (MemDebugLogBufAddr, MemDebugLogBufPages); MemDebugLogBufAddr = 0; goto done; } // // Copy over the messages from the Early Debug Log buffer. // if (FixedPcdGet32 (PcdOvmfEarlyMemDebugLogBase) != 0) { MemDebugLogCopy (MemDebugLogBufAddr, (EFI_PHYSICAL_ADDRESS)(UINTN)FixedPcdGet32 (PcdOvmfEarlyMemDebugLogBase)); } done: // // Zero the early buffer if we successfully // created the main memory log buffer. // if ((Status == EFI_SUCCESS) && (FixedPcdGet32 (PcdOvmfEarlyMemDebugLogBase) != 0)) { ZeroMem ( (VOID *)(UINTN)FixedPcdGet32 (PcdOvmfEarlyMemDebugLogBase), (UINT32)FixedPcdGet32 (PcdOvmfEarlyMemDebugLogSize) ); } // // Create HOB to pass mem debug log buffer addr // Status = PeiServicesCreateHob ( EFI_HOB_TYPE_GUID_EXTENSION, (UINT16)(sizeof (EFI_HOB_GUID_TYPE) + sizeof (MEM_DEBUG_LOG_HOB_DATA)), (VOID **)&GuidHob ); if (EFI_ERROR (Status)) { if (MemDebugLogBufAddr) { PeiServicesFreePages (MemDebugLogBufAddr, MemDebugLogBufPages); } } else { // // Populate the HOB // CopyGuid (&GuidHob->Name, &gMemDebugLogHobGuid); HobData = (MEM_DEBUG_LOG_HOB_DATA *)GET_GUID_HOB_DATA (GuidHob); HobData->MemDebugLogBufAddr = MemDebugLogBufAddr; } return Status; } EFI_STATUS EFIAPI MemDebugLogEntry ( IN EFI_PEI_FILE_HANDLE FileHandle, IN CONST EFI_PEI_SERVICES **PeiServices ) { EFI_STATUS Status; // // Setup callback for memory available notification // Status = PeiServicesNotifyPpi (mMemAvailNotifyList); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "%a: Failed to create MemDebugLog PEIM Callback: %r. Logging disabled\n", __func__, Status)); } return Status; }