Skip to content

Commit

Permalink
OvmfPkg/RiscVVirt: Support multiple reserved memory ranges
Browse files Browse the repository at this point in the history
M-mode firmware ranges should not be used by EDK2/OS.
Currently, we search for mmode_resv0 node in FDT and mark it as the
reserved memory in EFI memory map. However, if there are multiple
M-mode firmware ranges, then this will miss those extra ranges
allowing the OS to access the memory and hit a fault.

This issue is exposed since recent opensbi started creating
two ranges for text and data.

Fix this by searching for all reserved memory nodes and marking
them as reserved in the EFI memory map.

Cc: Ard Biesheuvel <[email protected]>
Cc: Jiewen Yao <[email protected]>
Cc: Jordan Justen <[email protected]>
Cc: Gerd Hoffmann <[email protected]>
Cc: Andrei Warkentin <[email protected]>
Signed-off-by: Sunil V L <[email protected]>
Reviewed-by: Andrei Warkentin <[email protected]>
  • Loading branch information
vlsunil authored and mergify[bot] committed Mar 28, 2023
1 parent 1440286 commit 71fd87e
Showing 1 changed file with 149 additions and 77 deletions.
226 changes: 149 additions & 77 deletions OvmfPkg/RiscVVirt/Sec/Memory.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,31 +38,6 @@ BuildMemoryTypeInformationHob (
VOID
);

/**
Build reserved memory range resource HOB.
@param MemoryBase Reserved memory range base address.
@param MemorySize Reserved memory range size.
**/
STATIC
VOID
AddReservedMemoryBaseSizeHob (
EFI_PHYSICAL_ADDRESS MemoryBase,
UINT64 MemorySize
)
{
BuildResourceDescriptorHob (
EFI_RESOURCE_MEMORY_RESERVED,
EFI_RESOURCE_ATTRIBUTE_PRESENT |
EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |
EFI_RESOURCE_ATTRIBUTE_TESTED,
MemoryBase,
MemorySize
);
}

/**
Create memory range resource HOB using the memory base
address and size.
Expand All @@ -74,8 +49,8 @@ AddReservedMemoryBaseSizeHob (
STATIC
VOID
AddMemoryBaseSizeHob (
EFI_PHYSICAL_ADDRESS MemoryBase,
UINT64 MemorySize
IN EFI_PHYSICAL_ADDRESS MemoryBase,
IN UINT64 MemorySize
)
{
BuildResourceDescriptorHob (
Expand Down Expand Up @@ -103,8 +78,8 @@ AddMemoryBaseSizeHob (
STATIC
VOID
AddMemoryRangeHob (
EFI_PHYSICAL_ADDRESS MemoryBase,
EFI_PHYSICAL_ADDRESS MemoryLimit
IN EFI_PHYSICAL_ADDRESS MemoryBase,
IN EFI_PHYSICAL_ADDRESS MemoryLimit
)
{
AddMemoryBaseSizeHob (MemoryBase, (UINT64)(MemoryLimit - MemoryBase));
Expand Down Expand Up @@ -132,39 +107,152 @@ InitMmu (
STATIC
VOID
InitializeRamRegions (
EFI_PHYSICAL_ADDRESS SystemMemoryBase,
UINT64 SystemMemorySize,
EFI_PHYSICAL_ADDRESS MmodeResvBase,
UINT64 MmodeResvSize
IN EFI_PHYSICAL_ADDRESS SystemMemoryBase,
IN UINT64 SystemMemorySize
)
{
/*
* M-mode FW can be loaded anywhere in memory but should not overlap
* with the EDK2. This can happen if some other boot code loads the
* M-mode firmware.
*
* The M-mode firmware memory should be marked as reserved memory
* so that OS doesn't use it.
*/
DEBUG ((
DEBUG_INFO,
"%a: M-mode FW Memory Start:0x%lx End:0x%lx\n",
__FUNCTION__,
MmodeResvBase,
MmodeResvBase + MmodeResvSize
));
AddReservedMemoryBaseSizeHob (MmodeResvBase, MmodeResvSize);

if (MmodeResvBase > SystemMemoryBase) {
AddMemoryRangeHob (SystemMemoryBase, MmodeResvBase);
}

AddMemoryRangeHob (
MmodeResvBase + MmodeResvSize,
SystemMemoryBase,
SystemMemoryBase + SystemMemorySize
);
}

/** Get the number of cells for a given property
@param[in] Fdt Pointer to Device Tree (DTB)
@param[in] Node Node
@param[in] Name Name of the property
@return Number of cells.
**/
STATIC
INT32
GetNumCells (
IN VOID *Fdt,
IN INT32 Node,
IN CONST CHAR8 *Name
)
{
CONST INT32 *Prop;
INT32 Len;
UINT32 Val;

Prop = fdt_getprop (Fdt, Node, Name, &Len);
if (Prop == NULL) {
return Len;
}

if (Len != sizeof (*Prop)) {
return -FDT_ERR_BADNCELLS;
}

Val = fdt32_to_cpu (*Prop);
if (Val > FDT_MAX_NCELLS) {
return -FDT_ERR_BADNCELLS;
}

return (INT32)Val;
}

/** Mark reserved memory ranges in the EFI memory map
The M-mode firmware ranges should not be used by the
EDK2/OS. These ranges are passed via device tree using reserved
memory nodes. Parse the DT and mark those ranges as of
type EfiReservedMemoryType.
NOTE: Device Tree spec section 3.5.4 says reserved memory regions
without no-map property should be installed as EfiBootServicesData.
As per UEFI spec, memory of type EfiBootServicesData can be used
by the OS after ExitBootServices().
This is not an issue for DT since OS can parse the DT also along
with EFI memory map and avoid using these ranges. But with ACPI,
there is no such mechanisms possible.
Since EDK2 needs to support both DT and ACPI, we are deviating
from the DT spec and marking all reserved memory ranges as
EfiReservedMemoryType itself irrespective of no-map.
@param FdtPointer Pointer to FDT
**/
STATIC
VOID
AddReservedMemoryMap (
IN VOID *FdtPointer
)
{
CONST INT32 *RegProp;
INT32 Node;
INT32 SubNode;
INT32 Len;
EFI_PHYSICAL_ADDRESS Addr;
UINT64 Size;
INTN NumRsv, i;
INT32 NumAddrCells, NumSizeCells;

NumRsv = fdt_num_mem_rsv (FdtPointer);

/* Look for an existing entry and add it to the efi mem map. */
for (i = 0; i < NumRsv; i++) {
if (fdt_get_mem_rsv (FdtPointer, i, &Addr, &Size) != 0) {
continue;
}

BuildMemoryAllocationHob (
Addr,
Size,
EfiReservedMemoryType
);
}

/* process reserved-memory */
Node = fdt_subnode_offset (FdtPointer, 0, "reserved-memory");
if (Node >= 0) {
NumAddrCells = GetNumCells (FdtPointer, Node, "#address-cells");
if (NumAddrCells <= 0) {
return;
}

NumSizeCells = GetNumCells (FdtPointer, Node, "#size-cells");
if (NumSizeCells <= 0) {
return;
}

fdt_for_each_subnode (SubNode, FdtPointer, Node) {
RegProp = fdt_getprop (FdtPointer, SubNode, "reg", &Len);

if ((RegProp != 0) && (Len == ((NumAddrCells + NumSizeCells) * sizeof (INT32)))) {
Addr = fdt32_to_cpu (RegProp[0]);

if (NumAddrCells > 1) {
Addr = (Addr << 32) | fdt32_to_cpu (RegProp[1]);
}

RegProp += NumAddrCells;
Size = fdt32_to_cpu (RegProp[0]);

if (NumSizeCells > 1) {
Size = (Size << 32) | fdt32_to_cpu (RegProp[1]);
}

DEBUG ((
DEBUG_INFO,
"%a: Adding Reserved Memory Addr = 0x%llx, Size = 0x%llx\n",
__func__,
Addr,
Size
));

BuildMemoryAllocationHob (
Addr,
Size,
EfiReservedMemoryType
);
}
}
}
}

/**
Initialize memory hob based on the DTB information.
Expand All @@ -183,8 +271,6 @@ MemoryPeimInitialization (
INT32 Node, Prev;
INT32 Len;
VOID *FdtPointer;
EFI_PHYSICAL_ADDRESS MmodeResvBase;
UINT64 MmodeResvSize;

FirmwareContext = NULL;
GetFirmwareContextPointer (&FirmwareContext);
Expand All @@ -200,16 +286,6 @@ MemoryPeimInitialization (
return EFI_UNSUPPORTED;
}

/* try to locate the reserved memory opensbi node */
Node = fdt_path_offset (FdtPointer, "/reserved-memory/mmode_resv0");
if (Node >= 0) {
RegProp = fdt_getprop (FdtPointer, Node, "reg", &Len);
if ((RegProp != 0) && (Len == (2 * sizeof (UINT64)))) {
MmodeResvBase = fdt64_to_cpu (ReadUnaligned64 (RegProp));
MmodeResvSize = fdt64_to_cpu (ReadUnaligned64 (RegProp + 1));
}
}

// Look for the lowest memory node
for (Prev = 0; ; Prev = Node) {
Node = fdt_next_node (FdtPointer, Prev, NULL);
Expand All @@ -235,16 +311,10 @@ MemoryPeimInitialization (
CurBase + CurSize - 1
));

if ((MmodeResvBase >= CurBase) && ((MmodeResvBase + MmodeResvSize) <= (CurBase + CurSize))) {
InitializeRamRegions (
CurBase,
CurSize,
MmodeResvBase,
MmodeResvSize
);
} else {
AddMemoryBaseSizeHob (CurBase, CurSize);
}
InitializeRamRegions (
CurBase,
CurSize
);
} else {
DEBUG ((
DEBUG_ERROR,
Expand All @@ -255,6 +325,8 @@ MemoryPeimInitialization (
}
}

AddReservedMemoryMap (FdtPointer);

InitMmu ();

BuildMemoryTypeInformationHob ();
Expand Down

0 comments on commit 71fd87e

Please sign in to comment.