diff --git a/OvmfPkg/XenPlatformPei/MemDetect.c b/OvmfPkg/XenPlatformPei/MemDetect.c index cf95f9c474..1f81eee407 100644 --- a/OvmfPkg/XenPlatformPei/MemDetect.c +++ b/OvmfPkg/XenPlatformPei/MemDetect.c @@ -96,6 +96,45 @@ Q35TsegMbytesInitialization ( mQ35TsegMbytes = ExtendedTsegMbytes; } +STATIC +UINT64 +GetHighestSystemMemoryAddress ( + BOOLEAN Below4gb + ) +{ + EFI_E820_ENTRY64 *E820Map; + UINT32 E820EntriesCount; + EFI_E820_ENTRY64 *Entry; + EFI_STATUS Status; + UINT32 Loop; + UINT64 HighestAddress; + UINT64 EntryEnd; + + HighestAddress = 0; + + Status = XenGetE820Map (&E820Map, &E820EntriesCount); + ASSERT_EFI_ERROR (Status); + + for (Loop = 0; Loop < E820EntriesCount; Loop++) { + Entry = E820Map + Loop; + EntryEnd = Entry->BaseAddr + Entry->Length; + + if (Entry->Type == EfiAcpiAddressRangeMemory && + EntryEnd > HighestAddress) { + + if (Below4gb && (EntryEnd <= BASE_4GB)) { + HighestAddress = EntryEnd; + } else if (!Below4gb && (EntryEnd >= BASE_4GB)) { + HighestAddress = EntryEnd; + } + } + } + + // + // Round down the end address. + // + return HighestAddress & ~(UINT64)EFI_PAGE_MASK; +} UINT32 GetSystemMemorySizeBelow4gb ( @@ -105,6 +144,19 @@ GetSystemMemorySizeBelow4gb ( UINT8 Cmos0x34; UINT8 Cmos0x35; + // + // In PVH case, there is no CMOS, we have to calculate the memory size + // from parsing the E820 + // + if (XenPvhDetected ()) { + UINT64 HighestAddress; + + HighestAddress = GetHighestSystemMemoryAddress (TRUE); + ASSERT (HighestAddress > 0 && HighestAddress <= BASE_4GB); + + return HighestAddress; + } + // // CMOS 0x34/0x35 specifies the system memory above 16 MB. // * CMOS(0x35) is the high byte @@ -129,6 +181,23 @@ GetSystemMemorySizeAbove4gb ( UINT32 Size; UINTN CmosIndex; + // + // In PVH case, there is no CMOS, we have to calculate the memory size + // from parsing the E820 + // + if (XenPvhDetected ()) { + UINT64 HighestAddress; + + HighestAddress = GetHighestSystemMemoryAddress (FALSE); + ASSERT (HighestAddress == 0 || HighestAddress >= BASE_4GB); + + if (HighestAddress >= BASE_4GB) { + HighestAddress -= BASE_4GB; + } + + return HighestAddress; + } + // // CMOS 0x5b-0x5d specifies the system memory above 4GB MB. // * CMOS(0x5d) is the most significant size byte diff --git a/OvmfPkg/XenPlatformPei/Platform.c b/OvmfPkg/XenPlatformPei/Platform.c index 6aaafc3ee9..2f42ca6ccd 100644 --- a/OvmfPkg/XenPlatformPei/Platform.c +++ b/OvmfPkg/XenPlatformPei/Platform.c @@ -102,6 +102,17 @@ AddReservedMemoryBaseSizeHob ( ); } +VOID +AddReservedMemoryRangeHob ( + EFI_PHYSICAL_ADDRESS MemoryBase, + EFI_PHYSICAL_ADDRESS MemoryLimit, + BOOLEAN Cacheable + ) +{ + AddReservedMemoryBaseSizeHob (MemoryBase, + (UINT64)(MemoryLimit - MemoryBase), Cacheable); +} + VOID AddIoMemoryRangeHob ( EFI_PHYSICAL_ADDRESS MemoryBase, diff --git a/OvmfPkg/XenPlatformPei/Platform.h b/OvmfPkg/XenPlatformPei/Platform.h index db9a62572f..7661f4a8de 100644 --- a/OvmfPkg/XenPlatformPei/Platform.h +++ b/OvmfPkg/XenPlatformPei/Platform.h @@ -44,6 +44,13 @@ AddReservedMemoryBaseSizeHob ( BOOLEAN Cacheable ); +VOID +AddReservedMemoryRangeHob ( + EFI_PHYSICAL_ADDRESS MemoryBase, + EFI_PHYSICAL_ADDRESS MemoryLimit, + BOOLEAN Cacheable + ); + VOID AddressWidthInitialization ( VOID @@ -114,6 +121,12 @@ XenPublishRamRegions ( VOID ); +EFI_STATUS +XenGetE820Map ( + EFI_E820_ENTRY64 **Entries, + UINT32 *Count + ); + extern EFI_BOOT_MODE mBootMode; extern UINT8 mPhysMemAddressWidth; diff --git a/OvmfPkg/XenPlatformPei/Xen.c b/OvmfPkg/XenPlatformPei/Xen.c index 72f6f37b46..c4506def9a 100644 --- a/OvmfPkg/XenPlatformPei/Xen.c +++ b/OvmfPkg/XenPlatformPei/Xen.c @@ -276,9 +276,14 @@ XenPublishRamRegions ( VOID ) { - EFI_E820_ENTRY64 *E820Map; - UINT32 E820EntriesCount; - EFI_STATUS Status; + EFI_E820_ENTRY64 *E820Map; + UINT32 E820EntriesCount; + EFI_STATUS Status; + EFI_E820_ENTRY64 *Entry; + UINTN Index; + UINT64 LapicBase; + UINT64 LapicEnd; + DEBUG ((DEBUG_INFO, "Using memory map provided by Xen\n")); @@ -287,26 +292,60 @@ XenPublishRamRegions ( // E820EntriesCount = 0; Status = XenGetE820Map (&E820Map, &E820EntriesCount); - ASSERT_EFI_ERROR (Status); - if (E820EntriesCount > 0) { - EFI_E820_ENTRY64 *Entry; - UINT32 Loop; + LapicBase = PcdGet32 (PcdCpuLocalApicBaseAddress); + LapicEnd = LapicBase + SIZE_1MB; + AddIoMemoryRangeHob (LapicBase, LapicEnd); - for (Loop = 0; Loop < E820EntriesCount; Loop++) { - Entry = E820Map + Loop; + for (Index = 0; Index < E820EntriesCount; Index++) { + UINT64 Base; + UINT64 End; + UINT64 ReservedBase; + UINT64 ReservedEnd; + + Entry = &E820Map[Index]; + + // + // Round up the start address, and round down the end address. + // + Base = ALIGN_VALUE (Entry->BaseAddr, (UINT64)EFI_PAGE_SIZE); + End = (Entry->BaseAddr + Entry->Length) & ~(UINT64)EFI_PAGE_MASK; + + switch (Entry->Type) { + case EfiAcpiAddressRangeMemory: + AddMemoryRangeHob (Base, End); + break; + case EfiAcpiAddressRangeACPI: + AddReservedMemoryRangeHob (Base, End, FALSE); + break; + case EfiAcpiAddressRangeReserved: + // + // hvmloader marks a range that overlaps with the local APIC memory + // mapped region as reserved, but CpuDxe wants it as mapped IO. We + // have already added it as mapped IO, so skip it here. + // // - // Only care about RAM + // add LAPIC predecessor range, if any // - if (Entry->Type != EfiAcpiAddressRangeMemory) { - continue; + ReservedBase = Base; + ReservedEnd = MIN (End, LapicBase); + if (ReservedBase < ReservedEnd) { + AddReservedMemoryRangeHob (ReservedBase, ReservedEnd, FALSE); } - AddMemoryBaseSizeHob (Entry->BaseAddr, Entry->Length); - - MtrrSetMemoryAttribute (Entry->BaseAddr, Entry->Length, CacheWriteBack); + // + // add LAPIC successor range, if any + // + ReservedBase = MAX (Base, LapicEnd); + ReservedEnd = End; + if (ReservedBase < ReservedEnd) { + AddReservedMemoryRangeHob (ReservedBase, ReservedEnd, FALSE); + } + break; + default: + break; } } } @@ -326,12 +365,6 @@ InitializeXen ( { RETURN_STATUS PcdStatus; - // - // Reserve away HVMLOADER reserved memory [0xFC000000,0xFD000000). - // This needs to match HVMLOADER RESERVED_MEMBASE/RESERVED_MEMSIZE. - // - AddReservedMemoryBaseSizeHob (0xFC000000, 0x1000000, FALSE); - PcdStatus = PcdSetBoolS (PcdPciDisableBusEnumeration, TRUE); ASSERT_RETURN_ERROR (PcdStatus);