/** @file Memory Detection for Virtual Machines. Copyright (c) 2024 Loongson Technology Corporation Limited. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ // // The package level header files this module uses // #include // // The Library classes this module consumes // #include #include #include #include #include #include #include #include #include #include "Platform.h" #define MAX_VIRTUAL_MEMORY_MAP_DESCRIPTORS (128) #define LOONGARCH_FW_RAM_TOP BASE_256MB /** Publish PEI core memory @return EFI_SUCCESS The PEIM initialized successfully. **/ EFI_STATUS PublishPeiMemory ( VOID ) { EFI_STATUS Status; UINT64 Base; UINT64 Size; UINT64 RamTop; FIRMWARE_CONFIG_ITEM FwCfgItem; UINTN FwCfgSize; UINTN Processed; MEMMAP_ENTRY MemoryMapEntry; // // Determine the range of memory to use during PEI // Base = FixedPcdGet64 (PcdOvmfSecPeiTempRamBase) + FixedPcdGet32 (PcdOvmfSecPeiTempRamSize); RamTop = 0; Status = QemuFwCfgFindFile ("etc/memmap", &FwCfgItem, &FwCfgSize); if (EFI_ERROR (Status)) { return Status; } if (FwCfgSize % sizeof MemoryMapEntry != 0) { return EFI_PROTOCOL_ERROR; } QemuFwCfgSelectItem (FwCfgItem); for (Processed = 0; Processed < FwCfgSize; Processed += sizeof MemoryMapEntry) { QemuFwCfgReadBytes (sizeof MemoryMapEntry, &MemoryMapEntry); if (MemoryMapEntry.Type != EfiAcpiAddressRangeMemory) { continue; } // // Find memory map entry where PEI temp stack is located // if ((MemoryMapEntry.BaseAddr <= Base) && (Base < (MemoryMapEntry.BaseAddr + MemoryMapEntry.Length))) { RamTop = MemoryMapEntry.BaseAddr + MemoryMapEntry.Length; break; } } if (RamTop == 0) { DEBUG ((DEBUG_ERROR, "ERROR: No memory map entry contains temp stack \n")); ASSERT (FALSE); } Size = RamTop - Base; // // Publish this memory to the PEI Core // Status = PublishSystemMemory (Base, Size); ASSERT_EFI_ERROR (Status); DEBUG ((DEBUG_INFO, "Publish Memory Initialize done.\n")); return Status; } /** Peform Memory Detection Publish system RAM and reserve memory regions **/ VOID InitializeRamRegions ( VOID ) { EFI_STATUS Status; FIRMWARE_CONFIG_ITEM FwCfgItem; UINTN FwCfgSize; MEMMAP_ENTRY MemoryMapEntry; MEMMAP_ENTRY *StartEntry; MEMMAP_ENTRY *pEntry; UINTN Processed; Status = QemuFwCfgFindFile ("etc/memmap", &FwCfgItem, &FwCfgSize); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "%a %d read etc/memmap error Status %d \n", __func__, __LINE__, Status)); return; } if (FwCfgSize % sizeof MemoryMapEntry != 0) { DEBUG ((DEBUG_ERROR, "no MemoryMapEntry FwCfgSize:%d\n", FwCfgSize)); return; } QemuFwCfgSelectItem (FwCfgItem); StartEntry = AllocatePages (EFI_SIZE_TO_PAGES (FwCfgSize)); QemuFwCfgReadBytes (FwCfgSize, StartEntry); for (Processed = 0; Processed < (FwCfgSize / sizeof MemoryMapEntry); Processed++) { pEntry = StartEntry + Processed; if (pEntry->Length == 0) { continue; } DEBUG ((DEBUG_INFO, "MemmapEntry Base %p length %p type %d\n", pEntry->BaseAddr, pEntry->Length, pEntry->Type)); if (pEntry->Type != EfiAcpiAddressRangeMemory) { continue; } AddMemoryRangeHob (pEntry->BaseAddr, pEntry->BaseAddr + pEntry->Length); } // // When 0 address protection is enabled, // 0-4k memory needs to be preallocated to prevent UEFI applications from allocating use, // such as grub // if (PcdGet8 (PcdNullPointerDetectionPropertyMask) & BIT0) { BuildMemoryAllocationHob ( 0, EFI_PAGE_SIZE, EfiBootServicesData ); } } /** Gets the Virtual Memory Map of corresponding platforms. This Virtual Memory Map is used by initialize the MMU on corresponding platforms. @param[out] MemoryTable Array of EFI_MEMORY_DESCRIPTOR describing a Physical-to-Virtual Memory mapping. This array must be ended by a zero-filled entry. The allocated memory will not be freed. **/ VOID EFIAPI GetMemoryMapPolicy ( OUT EFI_MEMORY_DESCRIPTOR **MemoryTable ) { EFI_STATUS Status; FIRMWARE_CONFIG_ITEM FwCfgItem; UINTN FwCfgSize; MEMMAP_ENTRY MemoryMapEntry; MEMMAP_ENTRY *StartEntry; MEMMAP_ENTRY *pEntry; UINTN Processed; EFI_MEMORY_DESCRIPTOR *VirtualMemoryTable; UINTN Index = 0; ASSERT (MemoryTable != NULL); VirtualMemoryTable = AllocatePool ( sizeof (EFI_MEMORY_DESCRIPTOR) * MAX_VIRTUAL_MEMORY_MAP_DESCRIPTORS ); // // Add the 0x10000000-0x20000000. In the virtual machine, this area use for CPU UART, flash, PIC etc. // VirtualMemoryTable[Index].PhysicalStart = BASE_256MB; VirtualMemoryTable[Index].VirtualStart = VirtualMemoryTable[Index].PhysicalStart; VirtualMemoryTable[Index].NumberOfPages = EFI_SIZE_TO_PAGES (SIZE_256MB); VirtualMemoryTable[Index].Attribute = EFI_MEMORY_UC; ++Index; Status = QemuFwCfgFindFile ("etc/memmap", &FwCfgItem, &FwCfgSize); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "%a %d read etc/memmap error Status %d \n", __func__, __LINE__, Status)); ZeroMem (&VirtualMemoryTable[Index], sizeof (EFI_MEMORY_DESCRIPTOR)); *MemoryTable = VirtualMemoryTable; return; } if (FwCfgSize % sizeof MemoryMapEntry != 0) { DEBUG ((DEBUG_ERROR, "no MemoryMapEntry FwCfgSize:%d\n", FwCfgSize)); } QemuFwCfgSelectItem (FwCfgItem); StartEntry = AllocatePages (EFI_SIZE_TO_PAGES (FwCfgSize)); QemuFwCfgReadBytes (FwCfgSize, StartEntry); for (Processed = 0; Processed < (FwCfgSize / sizeof MemoryMapEntry); Processed++) { pEntry = StartEntry + Processed; if (pEntry->Length == 0) { continue; } DEBUG ((DEBUG_INFO, "MemmapEntry Base %p length %p type %d\n", pEntry->BaseAddr, pEntry->Length, pEntry->Type)); VirtualMemoryTable[Index].PhysicalStart = pEntry->BaseAddr; VirtualMemoryTable[Index].VirtualStart = VirtualMemoryTable[Index].PhysicalStart; VirtualMemoryTable[Index].NumberOfPages = EFI_SIZE_TO_PAGES (pEntry->Length); VirtualMemoryTable[Index].Attribute = EFI_MEMORY_WB; ++Index; } FreePages (StartEntry, EFI_SIZE_TO_PAGES (FwCfgSize)); // End of Table ZeroMem (&VirtualMemoryTable[Index], sizeof (EFI_MEMORY_DESCRIPTOR)); *MemoryTable = VirtualMemoryTable; }