/** @file | |
* High memory node enumeration DXE driver for ARM Virtual Machines | |
* | |
* Copyright (c) 2015-2016, Linaro Ltd. 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. | |
* | |
**/ | |
#include <Library/BaseLib.h> | |
#include <Library/DebugLib.h> | |
#include <Library/DxeServicesTableLib.h> | |
#include <Library/PcdLib.h> | |
#include <Library/UefiBootServicesTableLib.h> | |
#include <Protocol/Cpu.h> | |
#include <Protocol/FdtClient.h> | |
EFI_STATUS | |
EFIAPI | |
InitializeHighMemDxe ( | |
IN EFI_HANDLE ImageHandle, | |
IN EFI_SYSTEM_TABLE *SystemTable | |
) | |
{ | |
FDT_CLIENT_PROTOCOL *FdtClient; | |
EFI_CPU_ARCH_PROTOCOL *Cpu; | |
EFI_STATUS Status, FindNodeStatus; | |
INT32 Node; | |
CONST UINT32 *Reg; | |
UINT32 RegSize; | |
UINTN AddressCells, SizeCells; | |
UINT64 CurBase; | |
UINT64 CurSize; | |
UINT64 Attributes; | |
EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdDescriptor; | |
Status = gBS->LocateProtocol (&gFdtClientProtocolGuid, NULL, | |
(VOID **)&FdtClient); | |
ASSERT_EFI_ERROR (Status); | |
Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, | |
(VOID **)&Cpu); | |
ASSERT_EFI_ERROR (Status); | |
// | |
// Check for memory node and add the memory spaces except the lowest one | |
// | |
for (FindNodeStatus = FdtClient->FindMemoryNodeReg (FdtClient, &Node, | |
(CONST VOID **) &Reg, &AddressCells, | |
&SizeCells, &RegSize); | |
!EFI_ERROR (FindNodeStatus); | |
FindNodeStatus = FdtClient->FindNextMemoryNodeReg (FdtClient, Node, | |
&Node, (CONST VOID **) &Reg, &AddressCells, | |
&SizeCells, &RegSize)) { | |
ASSERT (AddressCells <= 2); | |
ASSERT (SizeCells <= 2); | |
while (RegSize > 0) { | |
CurBase = SwapBytes32 (*Reg++); | |
if (AddressCells > 1) { | |
CurBase = (CurBase << 32) | SwapBytes32 (*Reg++); | |
} | |
CurSize = SwapBytes32 (*Reg++); | |
if (SizeCells > 1) { | |
CurSize = (CurSize << 32) | SwapBytes32 (*Reg++); | |
} | |
RegSize -= (AddressCells + SizeCells) * sizeof (UINT32); | |
Status = gDS->GetMemorySpaceDescriptor (CurBase, &GcdDescriptor); | |
if (EFI_ERROR (Status)) { | |
DEBUG ((DEBUG_WARN, | |
"%a: Region 0x%lx - 0x%lx not found in the GCD memory space map\n", | |
__FUNCTION__, CurBase, CurBase + CurSize - 1)); | |
continue; | |
} | |
if (GcdDescriptor.GcdMemoryType == EfiGcdMemoryTypeNonExistent) { | |
Status = gDS->AddMemorySpace (EfiGcdMemoryTypeSystemMemory, CurBase, | |
CurSize, EFI_MEMORY_WB); | |
if (EFI_ERROR (Status)) { | |
DEBUG ((EFI_D_ERROR, | |
"%a: Failed to add System RAM @ 0x%lx - 0x%lx (%r)\n", | |
__FUNCTION__, CurBase, CurBase + CurSize - 1, Status)); | |
continue; | |
} | |
Status = gDS->SetMemorySpaceAttributes (CurBase, CurSize, | |
EFI_MEMORY_WB); | |
if (EFI_ERROR (Status)) { | |
DEBUG ((DEBUG_WARN, | |
"%a: gDS->SetMemorySpaceAttributes() failed on region 0x%lx - 0x%lx (%r)\n", | |
__FUNCTION__, CurBase, CurBase + CurSize - 1, Status)); | |
} | |
// | |
// Due to the ambiguous nature of the RO/XP GCD memory space attributes, | |
// it is impossible to add a memory space with the XP attribute in a way | |
// that does not result in the XP attribute being set on *all* UEFI | |
// memory map entries that are carved from it, including code regions | |
// that require executable permissions. | |
// | |
// So instead, we never set the RO/XP attributes in the GCD memory space | |
// capabilities or attribute fields, and apply any protections directly | |
// on the page table mappings by going through the cpu arch protocol. | |
// | |
Attributes = EFI_MEMORY_WB; | |
if ((PcdGet64 (PcdDxeNxMemoryProtectionPolicy) & | |
(1U << (UINT32)EfiConventionalMemory)) != 0) { | |
Attributes |= EFI_MEMORY_XP; | |
} | |
Status = Cpu->SetMemoryAttributes (Cpu, CurBase, CurSize, Attributes); | |
if (EFI_ERROR (Status)) { | |
DEBUG ((EFI_D_ERROR, | |
"%a: Failed to set System RAM @ 0x%lx - 0x%lx attribute (%r)\n", | |
__FUNCTION__, CurBase, CurBase + CurSize - 1, Status)); | |
} else { | |
DEBUG ((EFI_D_INFO, "%a: Add System RAM @ 0x%lx - 0x%lx\n", | |
__FUNCTION__, CurBase, CurBase + CurSize - 1)); | |
} | |
} | |
} | |
} | |
return EFI_SUCCESS; | |
} |