/** @file * * Copyright (c) 2019, Pete Batard * Copyright (c) 2017-2018, Andrey Warkentin * Copyright (c) 2014, Linaro Limited. All rights reserved. * Copyright (c) 2013-2018, ARM Limited. All rights reserved. * * SPDX-License-Identifier: BSD-2-Clause-Patent * **/ #include #include #include #include #include #include #include UINT64 mSystemMemoryBase; extern UINT64 mSystemMemoryEnd; UINT64 mVideoCoreBase; UINT64 mVideoCoreSize; UINT32 mBoardRevision; // The total number of descriptors, including the final "end-of-table" descriptor. #define MAX_VIRTUAL_MEMORY_MAP_DESCRIPTORS 11 STATIC BOOLEAN VirtualMemoryInfoInitialized = FALSE; STATIC RPI_MEMORY_REGION_INFO VirtualMemoryInfo[MAX_VIRTUAL_MEMORY_MAP_DESCRIPTORS]; #define VariablesSize (FixedPcdGet32(PcdFlashNvStorageVariableSize) + \ FixedPcdGet32(PcdFlashNvStorageFtwWorkingSize) + \ FixedPcdGet32(PcdFlashNvStorageFtwSpareSize) + \ FixedPcdGet32(PcdNvStorageEventLogSize)) #define VariablesBase (FixedPcdGet64(PcdFdBaseAddress) + \ FixedPcdGet32(PcdFdSize) - \ VariablesSize) /** Return the Virtual Memory Map of your platform This Virtual Memory Map is used by MemoryInitPei Module to initialize the MMU on your platform. @param[out] VirtualMemoryMap Array of ARM_MEMORY_REGION_DESCRIPTOR describing a Physical-to-Virtual Memory mapping. This array must be ended by a zero-filled entry **/ VOID ArmPlatformGetVirtualMemoryMap ( IN ARM_MEMORY_REGION_DESCRIPTOR** VirtualMemoryMap ) { UINTN Index = 0; INT64 TotalMemorySize; INT64 MemorySizeBelow3GB; INT64 MemorySizeBelow4GB; ARM_MEMORY_REGION_DESCRIPTOR *VirtualMemoryTable; // Early output of the info we got from VideoCore can prove valuable. DEBUG ((DEBUG_INFO, "Board Rev: 0x%lX\n", mBoardRevision)); DEBUG ((DEBUG_INFO, "RAM < 1GB: 0x%ll08X (Size 0x%ll08X)\n", mSystemMemoryBase, mSystemMemoryEnd + 1)); DEBUG ((DEBUG_INFO, "VideoCore: 0x%ll08X (Size 0x%ll08X)\n", mVideoCoreBase, mVideoCoreSize)); ASSERT (mSystemMemoryBase == 0); ASSERT (VirtualMemoryMap != NULL); // Compute the total RAM size available on this platform TotalMemorySize = SIZE_256MB; TotalMemorySize <<= (mBoardRevision >> 20) & 0x07; DEBUG ((DEBUG_INFO, "Total RAM: 0x%ll08X\n", TotalMemorySize)); // // Ensure that what we declare as System Memory doesn't overlap with the // SoC MMIO registers. This can be achieved through a MIN () with the // base address since SystemMemoryBase is 0 (we assert if it isn't). // ASSERT (BCM2836_SOC_REGISTERS < 4UL * SIZE_1GB); MemorySizeBelow4GB = MIN(TotalMemorySize, 4UL * SIZE_1GB); MemorySizeBelow4GB = MIN(MemorySizeBelow4GB, BCM2836_SOC_REGISTERS); if (BCM2711_SOC_REGISTERS > 0) { ASSERT (BCM2836_SOC_REGISTERS < 4UL * SIZE_1GB); MemorySizeBelow4GB = MIN(MemorySizeBelow4GB, BCM2711_SOC_REGISTERS); } // // By default we limit the memory to 3 GB to work around OS support for // DMA bugs in the SoC, for OSes that don't support _DMA range descriptors. // On boards with more RAM (4GB, 8GB), the extra memory is added by ConfigDxe // provided the configuration setting for 3GB limit is off. // MemorySizeBelow3GB = MIN(MemorySizeBelow4GB, 3UL * SIZE_1GB); // // On Pi 3 we've seen SoC registers may overlap the reported VideoCore range, // so clamp that down as well. // if (mVideoCoreBase + mVideoCoreSize > BCM2836_SOC_REGISTERS) { mVideoCoreSize = BCM2836_SOC_REGISTERS - mVideoCoreBase; DEBUG ((DEBUG_WARN, "VideoCore range overlapped SoC MMIO, now 0x%ll08X (Size 0x%ll08X)\n", mVideoCoreBase, mVideoCoreSize)); } VirtualMemoryTable = (ARM_MEMORY_REGION_DESCRIPTOR*)AllocatePages (EFI_SIZE_TO_PAGES (sizeof (ARM_MEMORY_REGION_DESCRIPTOR) * MAX_VIRTUAL_MEMORY_MAP_DESCRIPTORS)); if (VirtualMemoryTable == NULL) { return; } // Firmware Volume VirtualMemoryTable[Index].PhysicalBase = FixedPcdGet64 (PcdFdBaseAddress); VirtualMemoryTable[Index].VirtualBase = VirtualMemoryTable[Index].PhysicalBase; VirtualMemoryTable[Index].Length = FixedPcdGet32 (PcdFdSize) - VariablesSize; VirtualMemoryTable[Index].Attributes = ARM_MEMORY_REGION_ATTRIBUTE_WRITE_BACK; VirtualMemoryInfo[Index].Type = RPI_MEM_RESERVED_REGION; VirtualMemoryInfo[Index++].Name = L"FD"; // Variable Volume VirtualMemoryTable[Index].PhysicalBase = VariablesBase; VirtualMemoryTable[Index].VirtualBase = VirtualMemoryTable[Index].PhysicalBase; VirtualMemoryTable[Index].Length = VariablesSize; VirtualMemoryTable[Index].Attributes = ARM_MEMORY_REGION_ATTRIBUTE_WRITE_BACK; VirtualMemoryInfo[Index].Type = RPI_MEM_RUNTIME_REGION; VirtualMemoryInfo[Index++].Name = L"FD Variables"; // // Both the the Pi 4 and Pi 3 implementations expect the DTB to directly follow the FD. // VirtualMemoryTable[Index].PhysicalBase = FixedPcdGet32 (PcdFdtBaseAddress); VirtualMemoryTable[Index].VirtualBase = VirtualMemoryTable[Index].PhysicalBase; VirtualMemoryTable[Index].Length = FixedPcdGet32 (PcdFdtSize);; VirtualMemoryTable[Index].Attributes = ARM_MEMORY_REGION_ATTRIBUTE_WRITE_BACK; VirtualMemoryInfo[Index].Type = RPI_MEM_RESERVED_REGION; VirtualMemoryInfo[Index++].Name = L"Flattened Device Tree"; if (BCM2711_SOC_REGISTERS == 0) { // // TF-A reserved RAM only exists for the Pi 3 TF-A. // // This is 2MB that directly follows the FD. // VirtualMemoryTable[Index].PhysicalBase = (FixedPcdGet64(PcdFdBaseAddress) + FixedPcdGet32(PcdFdSize)); VirtualMemoryTable[Index].VirtualBase = VirtualMemoryTable[Index].PhysicalBase; VirtualMemoryTable[Index].Length = FixedPcdGet64 (PcdSystemMemoryBase) - VirtualMemoryTable[Index].PhysicalBase; VirtualMemoryTable[Index].Attributes = ARM_MEMORY_REGION_ATTRIBUTE_WRITE_BACK; VirtualMemoryInfo[Index].Type = RPI_MEM_RESERVED_REGION; VirtualMemoryInfo[Index++].Name = L"TF-A RAM"; } // Base System RAM VirtualMemoryTable[Index].PhysicalBase = FixedPcdGet64 (PcdSystemMemoryBase); VirtualMemoryTable[Index].VirtualBase = VirtualMemoryTable[Index].PhysicalBase; VirtualMemoryTable[Index].Length = mSystemMemoryEnd + 1 - FixedPcdGet64 (PcdSystemMemoryBase); VirtualMemoryTable[Index].Attributes = ARM_MEMORY_REGION_ATTRIBUTE_WRITE_BACK; VirtualMemoryInfo[Index].Type = RPI_MEM_BASIC_REGION; VirtualMemoryInfo[Index++].Name = L"System RAM < 1GB"; // GPU Reserved VirtualMemoryTable[Index].PhysicalBase = mVideoCoreBase; VirtualMemoryTable[Index].VirtualBase = VirtualMemoryTable[Index].PhysicalBase; VirtualMemoryTable[Index].Length = mVideoCoreSize; VirtualMemoryTable[Index].Attributes = ARM_MEMORY_REGION_ATTRIBUTE_DEVICE; VirtualMemoryInfo[Index].Type = RPI_MEM_UNMAPPED_REGION; VirtualMemoryInfo[Index++].Name = L"GPU Reserved"; // Extended SoC registers (PCIe, genet, ...) if (BCM2711_SOC_REGISTERS > 0) { VirtualMemoryTable[Index].PhysicalBase = BCM2711_SOC_REGISTERS; VirtualMemoryTable[Index].VirtualBase = VirtualMemoryTable[Index].PhysicalBase; VirtualMemoryTable[Index].Length = BCM2711_SOC_REGISTER_LENGTH; VirtualMemoryTable[Index].Attributes = ARM_MEMORY_REGION_ATTRIBUTE_DEVICE; VirtualMemoryInfo[Index].Type = RPI_MEM_UNMAPPED_REGION; VirtualMemoryInfo[Index++].Name = L"SoC Reserved (27xx)"; } // Base SoC registers VirtualMemoryTable[Index].PhysicalBase = BCM2836_SOC_REGISTERS; VirtualMemoryTable[Index].VirtualBase = VirtualMemoryTable[Index].PhysicalBase; VirtualMemoryTable[Index].Length = BCM2836_SOC_REGISTER_LENGTH; VirtualMemoryTable[Index].Attributes = ARM_MEMORY_REGION_ATTRIBUTE_DEVICE; VirtualMemoryInfo[Index].Type = RPI_MEM_UNMAPPED_REGION; VirtualMemoryInfo[Index++].Name = L"SoC Reserved (283x)"; // Memory in the 1GB - 3GB range is always available. if (MemorySizeBelow3GB > SIZE_1GB) { VirtualMemoryTable[Index].PhysicalBase = SIZE_1GB; VirtualMemoryTable[Index].VirtualBase = VirtualMemoryTable[Index].PhysicalBase; VirtualMemoryTable[Index].Length = MemorySizeBelow3GB - VirtualMemoryTable[Index].PhysicalBase; VirtualMemoryTable[Index].Attributes = ARM_MEMORY_REGION_ATTRIBUTE_WRITE_BACK; VirtualMemoryInfo[Index].Type = RPI_MEM_BASIC_REGION; VirtualMemoryInfo[Index++].Name = L"Extended System RAM < 3GB"; } // // If we have RAM in the 3GB - 4GB range, declare it as mapped, but don't // add it to the memory map. This is done later by ConfigDxe if necessary. // if (MemorySizeBelow4GB > 3UL * SIZE_1GB) { VirtualMemoryTable[Index].PhysicalBase = 3UL * SIZE_1GB; VirtualMemoryTable[Index].VirtualBase = VirtualMemoryTable[Index].PhysicalBase; VirtualMemoryTable[Index].Length = MemorySizeBelow4GB - VirtualMemoryTable[Index].PhysicalBase; VirtualMemoryTable[Index].Attributes = ARM_MEMORY_REGION_ATTRIBUTE_WRITE_BACK; VirtualMemoryInfo[Index].Type = RPI_MEM_UNMAPPED_REGION; VirtualMemoryInfo[Index++].Name = L"Extended System RAM < 4GB"; } // Same treatment for the memory above 4GB. if (TotalMemorySize > 4UL * SIZE_1GB) { VirtualMemoryTable[Index].PhysicalBase = 4UL * SIZE_1GB; VirtualMemoryTable[Index].VirtualBase = VirtualMemoryTable[Index].PhysicalBase; VirtualMemoryTable[Index].Length = TotalMemorySize - VirtualMemoryTable[Index].PhysicalBase; VirtualMemoryTable[Index].Attributes = ARM_MEMORY_REGION_ATTRIBUTE_WRITE_BACK; VirtualMemoryInfo[Index].Type = RPI_MEM_UNMAPPED_REGION; VirtualMemoryInfo[Index++].Name = L"Extended System RAM >= 4GB"; } // End of Table VirtualMemoryTable[Index].PhysicalBase = 0; VirtualMemoryTable[Index].VirtualBase = 0; VirtualMemoryTable[Index].Length = 0; VirtualMemoryTable[Index++].Attributes = (ARM_MEMORY_REGION_ATTRIBUTES)0; ASSERT(Index <= MAX_VIRTUAL_MEMORY_MAP_DESCRIPTORS); *VirtualMemoryMap = VirtualMemoryTable; VirtualMemoryInfoInitialized = TRUE; } /** Return additional memory info not populated by the above call. This call should follow the one to ArmPlatformGetVirtualMemoryMap (). **/ VOID RpiPlatformGetVirtualMemoryInfo ( IN RPI_MEMORY_REGION_INFO** MemoryInfo ) { ASSERT (VirtualMemoryInfo != NULL); if (!VirtualMemoryInfoInitialized) { DEBUG ((DEBUG_ERROR, "ArmPlatformGetVirtualMemoryMap must be called before RpiPlatformGetVirtualMemoryInfo.\n")); return; } *MemoryInfo = VirtualMemoryInfo; }