* [PATCH v2 0/4] OvmfPkg: check 64bit mmio window for resource conflicts @ 2023-01-10 8:21 Gerd Hoffmann 2023-01-10 8:21 ` [PATCH v2 1/4] OvmfPkg/PlatformInitLib: Add PlatformScanE820 and GetFirstNonAddressCB Gerd Hoffmann ` (3 more replies) 0 siblings, 4 replies; 19+ messages in thread From: Gerd Hoffmann @ 2023-01-10 8:21 UTC (permalink / raw) To: devel Cc: Pawel Polawski, Jiewen Yao, Oliver Steffen, Jordan Justen, László Érsek, Ard Biesheuvel, Gerd Hoffmann v2: - split up PlatformScanOrAdd64BitE820Ram() into scan function with callbacks, store results in PlatformInfoHob struct. Gerd Hoffmann (4): OvmfPkg/PlatformInitLib: Add PlatformScanE820 and GetFirstNonAddressCB OvmfPkg/PlatformInitLib: Add PlatformGetLowMemoryCB OvmfPkg/PlatformInitLib: Add PlatformAddHobCB OvmfPkg/PlatformInitLib: Add PlatformReservationConflictCB OvmfPkg/Include/Library/PlatformInitLib.h | 3 +- OvmfPkg/Library/PeilessStartupLib/Hob.c | 3 +- .../PeilessStartupLib/PeilessStartup.c | 7 +- OvmfPkg/Library/PlatformInitLib/MemDetect.c | 328 ++++++++++-------- OvmfPkg/Library/PlatformInitLib/Platform.c | 7 +- OvmfPkg/PlatformPei/MemDetect.c | 3 +- 6 files changed, 192 insertions(+), 159 deletions(-) -- 2.39.0 ^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH v2 1/4] OvmfPkg/PlatformInitLib: Add PlatformScanE820 and GetFirstNonAddressCB 2023-01-10 8:21 [PATCH v2 0/4] OvmfPkg: check 64bit mmio window for resource conflicts Gerd Hoffmann @ 2023-01-10 8:21 ` Gerd Hoffmann 2023-01-10 15:41 ` Laszlo Ersek 2023-01-10 8:21 ` [PATCH v2 2/4] OvmfPkg/PlatformInitLib: Add PlatformGetLowMemoryCB Gerd Hoffmann ` (2 subsequent siblings) 3 siblings, 1 reply; 19+ messages in thread From: Gerd Hoffmann @ 2023-01-10 8:21 UTC (permalink / raw) To: devel Cc: Pawel Polawski, Jiewen Yao, Oliver Steffen, Jordan Justen, László Érsek, Ard Biesheuvel, Gerd Hoffmann First step replacing the PlatformScanOrAdd64BitE820Ram() function. Add a PlatformScanE820() function which loops over the e280 entries from FwCfg and calls a callback for each of them. Add a GetFirstNonAddressCB() function which will store the first free address (right after the last RAM block) in PlatformInfoHob->FirstNonAddress. This replaces calls to PlatformScanOrAdd64BitE820Ram() with non-NULL MaxAddress. Also drop local FirstNonAddress variables and use PlatformInfoHob->FirstNonAddress instead everywhere. Signed-off-by: Gerd Hoffmann <kraxel@redhat.com> --- OvmfPkg/Library/PlatformInitLib/MemDetect.c | 114 ++++++++++++++++---- 1 file changed, 91 insertions(+), 23 deletions(-) diff --git a/OvmfPkg/Library/PlatformInitLib/MemDetect.c b/OvmfPkg/Library/PlatformInitLib/MemDetect.c index 0c4956852689..a2a4dc043f2e 100644 --- a/OvmfPkg/Library/PlatformInitLib/MemDetect.c +++ b/OvmfPkg/Library/PlatformInitLib/MemDetect.c @@ -251,6 +251,83 @@ PlatformScanOrAdd64BitE820Ram ( return EFI_SUCCESS; } +typedef VOID (*E820_SCAN_CALLBACK) ( + EFI_E820_ENTRY64 *E820Entry, + EFI_HOB_PLATFORM_INFO *PlatformInfoHob + ); + +/** + Store first address not used by e820 RAM entries in + PlatformInfoHob->FirstNonAddress +**/ +VOID +PlatformGetFirstNonAddressCB ( + IN EFI_E820_ENTRY64 *E820Entry, + IN OUT EFI_HOB_PLATFORM_INFO *PlatformInfoHob + ) +{ + UINT64 Candidate; + + if (E820Entry->Type != EfiAcpiAddressRangeMemory) { + return; + } + + Candidate = E820Entry->BaseAddr + E820Entry->Length; + if (PlatformInfoHob->FirstNonAddress < Candidate) { + DEBUG ((DEBUG_INFO, "%a: FirstNonAddress=0x%Lx\n", __FUNCTION__, Candidate)); + PlatformInfoHob->FirstNonAddress = Candidate; + } +} + +/** + Iterate over the RAM entries in QEMU's fw_cfg E820 RAM map, call the + passed callback for each entry. + + @param[in] Callback The callback function to be called. + + @param[in out] PlatformInfoHob PlatformInfo struct which is passed + through to the callback. + + @retval EFI_SUCCESS The fw_cfg E820 RAM map was found and processed. + + @retval EFI_PROTOCOL_ERROR The RAM map was found, but its size wasn't a + whole multiple of sizeof(EFI_E820_ENTRY64). No + RAM entry was processed. + + @return Error codes from QemuFwCfgFindFile(). No RAM + entry was processed. +**/ +STATIC +EFI_STATUS +PlatformScanE820 ( + IN E820_SCAN_CALLBACK Callback, + IN OUT EFI_HOB_PLATFORM_INFO *PlatformInfoHob + ) +{ + EFI_STATUS Status; + FIRMWARE_CONFIG_ITEM FwCfgItem; + UINTN FwCfgSize; + EFI_E820_ENTRY64 E820Entry; + UINTN Processed; + + Status = QemuFwCfgFindFile ("etc/e820", &FwCfgItem, &FwCfgSize); + if (EFI_ERROR (Status)) { + return Status; + } + + if (FwCfgSize % sizeof E820Entry != 0) { + return EFI_PROTOCOL_ERROR; + } + + QemuFwCfgSelectItem (FwCfgItem); + for (Processed = 0; Processed < FwCfgSize; Processed += sizeof E820Entry) { + QemuFwCfgReadBytes (sizeof E820Entry, &E820Entry); + Callback (&E820Entry, PlatformInfoHob); + } + + return EFI_SUCCESS; +} + /** Returns PVH memmap @@ -384,23 +461,17 @@ PlatformGetSystemMemorySizeAbove4gb ( Return the highest address that DXE could possibly use, plus one. **/ STATIC -UINT64 +VOID PlatformGetFirstNonAddress ( IN OUT EFI_HOB_PLATFORM_INFO *PlatformInfoHob ) { - UINT64 FirstNonAddress; UINT32 FwCfgPciMmio64Mb; EFI_STATUS Status; FIRMWARE_CONFIG_ITEM FwCfgItem; UINTN FwCfgSize; UINT64 HotPlugMemoryEnd; - // - // set FirstNonAddress to suppress incorrect compiler/analyzer warnings - // - FirstNonAddress = 0; - // // If QEMU presents an E820 map, then get the highest exclusive >=4GB RAM // address from it. This can express an address >= 4GB+1TB. @@ -408,9 +479,9 @@ PlatformGetFirstNonAddress ( // Otherwise, get the flat size of the memory above 4GB from the CMOS (which // can only express a size smaller than 1TB), and add it to 4GB. // - Status = PlatformScanOrAdd64BitE820Ram (FALSE, NULL, &FirstNonAddress); + Status = PlatformScanE820 (PlatformGetFirstNonAddressCB, PlatformInfoHob); if (EFI_ERROR (Status)) { - FirstNonAddress = BASE_4GB + PlatformGetSystemMemorySizeAbove4gb (); + PlatformInfoHob->FirstNonAddress = BASE_4GB + PlatformGetSystemMemorySizeAbove4gb (); } // @@ -420,7 +491,7 @@ PlatformGetFirstNonAddress ( // #ifdef MDE_CPU_IA32 if (!FeaturePcdGet (PcdDxeIplSwitchToLongMode)) { - return FirstNonAddress; + return; } #endif @@ -473,7 +544,7 @@ PlatformGetFirstNonAddress ( // determines the highest address plus one. The memory hotplug area (see // below) plays no role for the firmware in this case. // - return FirstNonAddress; + return; } // @@ -497,15 +568,15 @@ PlatformGetFirstNonAddress ( HotPlugMemoryEnd )); - ASSERT (HotPlugMemoryEnd >= FirstNonAddress); - FirstNonAddress = HotPlugMemoryEnd; + ASSERT (HotPlugMemoryEnd >= PlatformInfoHob->FirstNonAddress); + PlatformInfoHob->FirstNonAddress = HotPlugMemoryEnd; } // // SeaBIOS aligns both boundaries of the 64-bit PCI host aperture to 1GB, so // that the host can map it with 1GB hugepages. Follow suit. // - PlatformInfoHob->PcdPciMmio64Base = ALIGN_VALUE (FirstNonAddress, (UINT64)SIZE_1GB); + PlatformInfoHob->PcdPciMmio64Base = ALIGN_VALUE (PlatformInfoHob->FirstNonAddress, (UINT64)SIZE_1GB); PlatformInfoHob->PcdPciMmio64Size = ALIGN_VALUE (PlatformInfoHob->PcdPciMmio64Size, (UINT64)SIZE_1GB); // @@ -519,8 +590,8 @@ PlatformGetFirstNonAddress ( // // The useful address space ends with the 64-bit PCI host aperture. // - FirstNonAddress = PlatformInfoHob->PcdPciMmio64Base + PlatformInfoHob->PcdPciMmio64Size; - return FirstNonAddress; + PlatformInfoHob->FirstNonAddress = PlatformInfoHob->PcdPciMmio64Base + PlatformInfoHob->PcdPciMmio64Size; + return; } /* @@ -781,7 +852,6 @@ PlatformAddressWidthInitialization ( IN OUT EFI_HOB_PLATFORM_INFO *PlatformInfoHob ) { - UINT64 FirstNonAddress; UINT8 PhysMemAddressWidth; EFI_STATUS Status; @@ -794,7 +864,7 @@ PlatformAddressWidthInitialization ( // First scan host-provided hardware information to assess if the address // space is already known. If so, guest must use those values. // - Status = PlatformScanHostProvided64BitPciMmioEnd (&FirstNonAddress); + Status = PlatformScanHostProvided64BitPciMmioEnd (&PlatformInfoHob->FirstNonAddress); if (EFI_ERROR (Status)) { // @@ -806,13 +876,12 @@ PlatformAddressWidthInitialization ( // The DXL IPL keys off of the physical address bits advertized in the CPU // HOB. To conserve memory, we calculate the minimum address width here. // - FirstNonAddress = PlatformGetFirstNonAddress (PlatformInfoHob); + PlatformGetFirstNonAddress (PlatformInfoHob); } PlatformAddressWidthFromCpuid (PlatformInfoHob, TRUE); if (PlatformInfoHob->PhysMemAddressWidth != 0) { // physical address width is known - PlatformInfoHob->FirstNonAddress = FirstNonAddress; PlatformDynamicMmioWindow (PlatformInfoHob); return; } @@ -823,13 +892,13 @@ PlatformAddressWidthInitialization ( // -> try be conservstibe to stay below the guaranteed minimum of // 36 phys bits (aka 64 GB). // - PhysMemAddressWidth = (UINT8)HighBitSet64 (FirstNonAddress); + PhysMemAddressWidth = (UINT8)HighBitSet64 (PlatformInfoHob->FirstNonAddress); // // If FirstNonAddress is not an integral power of two, then we need an // additional bit. // - if ((FirstNonAddress & (FirstNonAddress - 1)) != 0) { + if ((PlatformInfoHob->FirstNonAddress & (PlatformInfoHob->FirstNonAddress - 1)) != 0) { ++PhysMemAddressWidth; } @@ -857,7 +926,6 @@ PlatformAddressWidthInitialization ( ASSERT (PhysMemAddressWidth <= 48); #endif - PlatformInfoHob->FirstNonAddress = FirstNonAddress; PlatformInfoHob->PhysMemAddressWidth = PhysMemAddressWidth; } -- 2.39.0 ^ permalink raw reply related [flat|nested] 19+ messages in thread
* Re: [PATCH v2 1/4] OvmfPkg/PlatformInitLib: Add PlatformScanE820 and GetFirstNonAddressCB 2023-01-10 8:21 ` [PATCH v2 1/4] OvmfPkg/PlatformInitLib: Add PlatformScanE820 and GetFirstNonAddressCB Gerd Hoffmann @ 2023-01-10 15:41 ` Laszlo Ersek 0 siblings, 0 replies; 19+ messages in thread From: Laszlo Ersek @ 2023-01-10 15:41 UTC (permalink / raw) To: Gerd Hoffmann, devel Cc: Pawel Polawski, Jiewen Yao, Oliver Steffen, Jordan Justen, Ard Biesheuvel On 1/10/23 09:21, Gerd Hoffmann wrote: > First step replacing the PlatformScanOrAdd64BitE820Ram() function. > > Add a PlatformScanE820() function which loops over the e280 entries > from FwCfg and calls a callback for each of them. > > Add a GetFirstNonAddressCB() function which will store the first free > address (right after the last RAM block) in > PlatformInfoHob->FirstNonAddress. This replaces calls to > PlatformScanOrAdd64BitE820Ram() with non-NULL MaxAddress. > > Also drop local FirstNonAddress variables and use > PlatformInfoHob->FirstNonAddress instead everywhere. > > Signed-off-by: Gerd Hoffmann <kraxel@redhat.com> > --- > OvmfPkg/Library/PlatformInitLib/MemDetect.c | 114 ++++++++++++++++---- > 1 file changed, 91 insertions(+), 23 deletions(-) > > diff --git a/OvmfPkg/Library/PlatformInitLib/MemDetect.c b/OvmfPkg/Library/PlatformInitLib/MemDetect.c > index 0c4956852689..a2a4dc043f2e 100644 > --- a/OvmfPkg/Library/PlatformInitLib/MemDetect.c > +++ b/OvmfPkg/Library/PlatformInitLib/MemDetect.c > @@ -251,6 +251,83 @@ PlatformScanOrAdd64BitE820Ram ( > return EFI_SUCCESS; > } > > +typedef VOID (*E820_SCAN_CALLBACK) ( > + EFI_E820_ENTRY64 *E820Entry, > + EFI_HOB_PLATFORM_INFO *PlatformInfoHob > + ); > + > +/** > + Store first address not used by e820 RAM entries in > + PlatformInfoHob->FirstNonAddress > +**/ > +VOID > +PlatformGetFirstNonAddressCB ( > + IN EFI_E820_ENTRY64 *E820Entry, > + IN OUT EFI_HOB_PLATFORM_INFO *PlatformInfoHob > + ) > +{ > + UINT64 Candidate; > + > + if (E820Entry->Type != EfiAcpiAddressRangeMemory) { > + return; > + } > + > + Candidate = E820Entry->BaseAddr + E820Entry->Length; > + if (PlatformInfoHob->FirstNonAddress < Candidate) { > + DEBUG ((DEBUG_INFO, "%a: FirstNonAddress=0x%Lx\n", __FUNCTION__, Candidate)); > + PlatformInfoHob->FirstNonAddress = Candidate; > + } > +} > + > +/** > + Iterate over the RAM entries in QEMU's fw_cfg E820 RAM map, call the > + passed callback for each entry. > + > + @param[in] Callback The callback function to be called. > + > + @param[in out] PlatformInfoHob PlatformInfo struct which is passed > + through to the callback. > + > + @retval EFI_SUCCESS The fw_cfg E820 RAM map was found and processed. > + > + @retval EFI_PROTOCOL_ERROR The RAM map was found, but its size wasn't a > + whole multiple of sizeof(EFI_E820_ENTRY64). No > + RAM entry was processed. > + > + @return Error codes from QemuFwCfgFindFile(). No RAM > + entry was processed. > +**/ (1) I suggest removing the "RAM" references from the above, now that the type checking is being moved to the callbacks. I think we can just say "entries" and "entry", without "RAM". Not a huge deal though. > +STATIC > +EFI_STATUS > +PlatformScanE820 ( > + IN E820_SCAN_CALLBACK Callback, > + IN OUT EFI_HOB_PLATFORM_INFO *PlatformInfoHob > + ) > +{ > + EFI_STATUS Status; > + FIRMWARE_CONFIG_ITEM FwCfgItem; > + UINTN FwCfgSize; > + EFI_E820_ENTRY64 E820Entry; > + UINTN Processed; > + > + Status = QemuFwCfgFindFile ("etc/e820", &FwCfgItem, &FwCfgSize); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + > + if (FwCfgSize % sizeof E820Entry != 0) { > + return EFI_PROTOCOL_ERROR; > + } > + > + QemuFwCfgSelectItem (FwCfgItem); > + for (Processed = 0; Processed < FwCfgSize; Processed += sizeof E820Entry) { > + QemuFwCfgReadBytes (sizeof E820Entry, &E820Entry); > + Callback (&E820Entry, PlatformInfoHob); > + } > + > + return EFI_SUCCESS; > +} > + > /** > Returns PVH memmap > > @@ -384,23 +461,17 @@ PlatformGetSystemMemorySizeAbove4gb ( > Return the highest address that DXE could possibly use, plus one. > **/ > STATIC > -UINT64 > +VOID > PlatformGetFirstNonAddress ( > IN OUT EFI_HOB_PLATFORM_INFO *PlatformInfoHob > ) > { > - UINT64 FirstNonAddress; > UINT32 FwCfgPciMmio64Mb; > EFI_STATUS Status; > FIRMWARE_CONFIG_ITEM FwCfgItem; > UINTN FwCfgSize; > UINT64 HotPlugMemoryEnd; > > - // > - // set FirstNonAddress to suppress incorrect compiler/analyzer warnings > - // > - FirstNonAddress = 0; > - > // > // If QEMU presents an E820 map, then get the highest exclusive >=4GB RAM > // address from it. This can express an address >= 4GB+1TB. > @@ -408,9 +479,9 @@ PlatformGetFirstNonAddress ( > // Otherwise, get the flat size of the memory above 4GB from the CMOS (which > // can only express a size smaller than 1TB), and add it to 4GB. > // > - Status = PlatformScanOrAdd64BitE820Ram (FALSE, NULL, &FirstNonAddress); > + Status = PlatformScanE820 (PlatformGetFirstNonAddressCB, PlatformInfoHob); (2) There is one omission in this patch. Namely, we're performing a conditional maximum search, and because it is conditional, it is possible that we find zero candidates. In that case, we still need to have "PlatformInfoHob->FirstNonAddress" set to a sane value. The original code handles this by initializing FirstNonAddress to 4GB: if (MaxAddress != NULL) { *MaxAddress = BASE_4GB; } Which is consistent with the comments that *remain* in the code now. So my request is that, right before this call to PlatformScanE820(), please set PlatformInfoHob->FirstNonAddress = BASE_4GB; With (2) updated, and (1) updated or not: Reviewed-by: Laszlo Ersek <lersek@redhat.com> Thanks, Laszlo > if (EFI_ERROR (Status)) { > - FirstNonAddress = BASE_4GB + PlatformGetSystemMemorySizeAbove4gb (); > + PlatformInfoHob->FirstNonAddress = BASE_4GB + PlatformGetSystemMemorySizeAbove4gb (); > } > > // > @@ -420,7 +491,7 @@ PlatformGetFirstNonAddress ( > // > #ifdef MDE_CPU_IA32 > if (!FeaturePcdGet (PcdDxeIplSwitchToLongMode)) { > - return FirstNonAddress; > + return; > } > > #endif > @@ -473,7 +544,7 @@ PlatformGetFirstNonAddress ( > // determines the highest address plus one. The memory hotplug area (see > // below) plays no role for the firmware in this case. > // > - return FirstNonAddress; > + return; > } > > // > @@ -497,15 +568,15 @@ PlatformGetFirstNonAddress ( > HotPlugMemoryEnd > )); > > - ASSERT (HotPlugMemoryEnd >= FirstNonAddress); > - FirstNonAddress = HotPlugMemoryEnd; > + ASSERT (HotPlugMemoryEnd >= PlatformInfoHob->FirstNonAddress); > + PlatformInfoHob->FirstNonAddress = HotPlugMemoryEnd; > } > > // > // SeaBIOS aligns both boundaries of the 64-bit PCI host aperture to 1GB, so > // that the host can map it with 1GB hugepages. Follow suit. > // > - PlatformInfoHob->PcdPciMmio64Base = ALIGN_VALUE (FirstNonAddress, (UINT64)SIZE_1GB); > + PlatformInfoHob->PcdPciMmio64Base = ALIGN_VALUE (PlatformInfoHob->FirstNonAddress, (UINT64)SIZE_1GB); > PlatformInfoHob->PcdPciMmio64Size = ALIGN_VALUE (PlatformInfoHob->PcdPciMmio64Size, (UINT64)SIZE_1GB); > > // > @@ -519,8 +590,8 @@ PlatformGetFirstNonAddress ( > // > // The useful address space ends with the 64-bit PCI host aperture. > // > - FirstNonAddress = PlatformInfoHob->PcdPciMmio64Base + PlatformInfoHob->PcdPciMmio64Size; > - return FirstNonAddress; > + PlatformInfoHob->FirstNonAddress = PlatformInfoHob->PcdPciMmio64Base + PlatformInfoHob->PcdPciMmio64Size; > + return; > } > > /* > @@ -781,7 +852,6 @@ PlatformAddressWidthInitialization ( > IN OUT EFI_HOB_PLATFORM_INFO *PlatformInfoHob > ) > { > - UINT64 FirstNonAddress; > UINT8 PhysMemAddressWidth; > EFI_STATUS Status; > > @@ -794,7 +864,7 @@ PlatformAddressWidthInitialization ( > // First scan host-provided hardware information to assess if the address > // space is already known. If so, guest must use those values. > // > - Status = PlatformScanHostProvided64BitPciMmioEnd (&FirstNonAddress); > + Status = PlatformScanHostProvided64BitPciMmioEnd (&PlatformInfoHob->FirstNonAddress); > > if (EFI_ERROR (Status)) { > // > @@ -806,13 +876,12 @@ PlatformAddressWidthInitialization ( > // The DXL IPL keys off of the physical address bits advertized in the CPU > // HOB. To conserve memory, we calculate the minimum address width here. > // > - FirstNonAddress = PlatformGetFirstNonAddress (PlatformInfoHob); > + PlatformGetFirstNonAddress (PlatformInfoHob); > } > > PlatformAddressWidthFromCpuid (PlatformInfoHob, TRUE); > if (PlatformInfoHob->PhysMemAddressWidth != 0) { > // physical address width is known > - PlatformInfoHob->FirstNonAddress = FirstNonAddress; > PlatformDynamicMmioWindow (PlatformInfoHob); > return; > } > @@ -823,13 +892,13 @@ PlatformAddressWidthInitialization ( > // -> try be conservstibe to stay below the guaranteed minimum of > // 36 phys bits (aka 64 GB). > // > - PhysMemAddressWidth = (UINT8)HighBitSet64 (FirstNonAddress); > + PhysMemAddressWidth = (UINT8)HighBitSet64 (PlatformInfoHob->FirstNonAddress); > > // > // If FirstNonAddress is not an integral power of two, then we need an > // additional bit. > // > - if ((FirstNonAddress & (FirstNonAddress - 1)) != 0) { > + if ((PlatformInfoHob->FirstNonAddress & (PlatformInfoHob->FirstNonAddress - 1)) != 0) { > ++PhysMemAddressWidth; > } > > @@ -857,7 +926,6 @@ PlatformAddressWidthInitialization ( > ASSERT (PhysMemAddressWidth <= 48); > #endif > > - PlatformInfoHob->FirstNonAddress = FirstNonAddress; > PlatformInfoHob->PhysMemAddressWidth = PhysMemAddressWidth; > } > ^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH v2 2/4] OvmfPkg/PlatformInitLib: Add PlatformGetLowMemoryCB 2023-01-10 8:21 [PATCH v2 0/4] OvmfPkg: check 64bit mmio window for resource conflicts Gerd Hoffmann 2023-01-10 8:21 ` [PATCH v2 1/4] OvmfPkg/PlatformInitLib: Add PlatformScanE820 and GetFirstNonAddressCB Gerd Hoffmann @ 2023-01-10 8:21 ` Gerd Hoffmann 2023-01-10 16:53 ` Laszlo Ersek 2023-01-10 8:21 ` [PATCH v2 3/4] OvmfPkg/PlatformInitLib: Add PlatformAddHobCB Gerd Hoffmann 2023-01-10 8:21 ` [PATCH v2 4/4] OvmfPkg/PlatformInitLib: Add PlatformReservationConflictCB Gerd Hoffmann 3 siblings, 1 reply; 19+ messages in thread From: Gerd Hoffmann @ 2023-01-10 8:21 UTC (permalink / raw) To: devel Cc: Pawel Polawski, Jiewen Yao, Oliver Steffen, Jordan Justen, László Érsek, Ard Biesheuvel, Gerd Hoffmann Add PlatformGetLowMemoryCB() callback function for use with PlatformScanE820(). It stores the low memory size in PlatformInfoHob->LowMemory. This replaces calls to PlatformScanOrAdd64BitE820Ram() with non-NULL LowMemory. Also change PlatformGetSystemMemorySizeBelow4gb() to likewise set PlatformInfoHob->LowMemory instead of returning the value. Update all Callers to the new convention. Signed-off-by: Gerd Hoffmann <kraxel@redhat.com> --- OvmfPkg/Include/Library/PlatformInitLib.h | 3 +- OvmfPkg/Library/PeilessStartupLib/Hob.c | 3 +- .../PeilessStartupLib/PeilessStartup.c | 7 +- OvmfPkg/Library/PlatformInitLib/MemDetect.c | 69 +++++++++++++------ OvmfPkg/Library/PlatformInitLib/Platform.c | 7 +- OvmfPkg/PlatformPei/MemDetect.c | 3 +- 6 files changed, 59 insertions(+), 33 deletions(-) diff --git a/OvmfPkg/Include/Library/PlatformInitLib.h b/OvmfPkg/Include/Library/PlatformInitLib.h index bf6f90a5761c..051b31191194 100644 --- a/OvmfPkg/Include/Library/PlatformInitLib.h +++ b/OvmfPkg/Include/Library/PlatformInitLib.h @@ -26,6 +26,7 @@ typedef struct { BOOLEAN Q35SmramAtDefaultSmbase; UINT16 Q35TsegMbytes; + UINT32 LowMemory; UINT64 FirstNonAddress; UINT8 PhysMemAddressWidth; UINT32 Uc32Base; @@ -144,7 +145,7 @@ PlatformQemuUc32BaseInitialization ( IN OUT EFI_HOB_PLATFORM_INFO *PlatformInfoHob ); -UINT32 +VOID EFIAPI PlatformGetSystemMemorySizeBelow4gb ( IN EFI_HOB_PLATFORM_INFO *PlatformInfoHob diff --git a/OvmfPkg/Library/PeilessStartupLib/Hob.c b/OvmfPkg/Library/PeilessStartupLib/Hob.c index 630ce445ebec..784a8ba194de 100644 --- a/OvmfPkg/Library/PeilessStartupLib/Hob.c +++ b/OvmfPkg/Library/PeilessStartupLib/Hob.c @@ -41,8 +41,9 @@ ConstructSecHobList ( EFI_HOB_PLATFORM_INFO PlatformInfoHob; ZeroMem (&PlatformInfoHob, sizeof (PlatformInfoHob)); + PlatformGetSystemMemorySizeBelow4gb (&PlatformInfoHob); PlatformInfoHob.HostBridgeDevId = PciRead16 (OVMF_HOSTBRIDGE_DID); - LowMemorySize = PlatformGetSystemMemorySizeBelow4gb (&PlatformInfoHob); + LowMemorySize = PlatformInfoHob.LowMemory; ASSERT (LowMemorySize != 0); LowMemoryStart = FixedPcdGet32 (PcdOvmfDxeMemFvBase) + FixedPcdGet32 (PcdOvmfDxeMemFvSize); LowMemorySize -= LowMemoryStart; diff --git a/OvmfPkg/Library/PeilessStartupLib/PeilessStartup.c b/OvmfPkg/Library/PeilessStartupLib/PeilessStartup.c index 380e71597206..928120d183ba 100644 --- a/OvmfPkg/Library/PeilessStartupLib/PeilessStartup.c +++ b/OvmfPkg/Library/PeilessStartupLib/PeilessStartup.c @@ -41,8 +41,7 @@ InitializePlatform ( EFI_HOB_PLATFORM_INFO *PlatformInfoHob ) { - UINT32 LowerMemorySize; - VOID *VariableStore; + VOID *VariableStore; DEBUG ((DEBUG_INFO, "InitializePlatform in Pei-less boot\n")); PlatformDebugDumpCmos (); @@ -70,14 +69,14 @@ InitializePlatform ( PlatformInfoHob->PcdCpuBootLogicalProcessorNumber )); - LowerMemorySize = PlatformGetSystemMemorySizeBelow4gb (PlatformInfoHob); + PlatformGetSystemMemorySizeBelow4gb (PlatformInfoHob); PlatformQemuUc32BaseInitialization (PlatformInfoHob); DEBUG (( DEBUG_INFO, "Uc32Base = 0x%x, Uc32Size = 0x%x, LowerMemorySize = 0x%x\n", PlatformInfoHob->Uc32Base, PlatformInfoHob->Uc32Size, - LowerMemorySize + PlatformInfoHob->LowMemory )); VariableStore = PlatformReserveEmuVariableNvStore (); diff --git a/OvmfPkg/Library/PlatformInitLib/MemDetect.c b/OvmfPkg/Library/PlatformInitLib/MemDetect.c index a2a4dc043f2e..63329c4e796a 100644 --- a/OvmfPkg/Library/PlatformInitLib/MemDetect.c +++ b/OvmfPkg/Library/PlatformInitLib/MemDetect.c @@ -51,18 +51,16 @@ PlatformQemuUc32BaseInitialization ( IN OUT EFI_HOB_PLATFORM_INFO *PlatformInfoHob ) { - UINT32 LowerMemorySize; - if (PlatformInfoHob->HostBridgeDevId == 0xffff /* microvm */) { return; } if (PlatformInfoHob->HostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) { - LowerMemorySize = PlatformGetSystemMemorySizeBelow4gb (PlatformInfoHob); + PlatformGetSystemMemorySizeBelow4gb (PlatformInfoHob); ASSERT (PcdGet64 (PcdPciExpressBaseAddress) <= MAX_UINT32); - ASSERT (PcdGet64 (PcdPciExpressBaseAddress) >= LowerMemorySize); + ASSERT (PcdGet64 (PcdPciExpressBaseAddress) >= PlatformInfoHob->LowMemory); - if (LowerMemorySize <= BASE_2GB) { + if (PlatformInfoHob->LowMemory <= BASE_2GB) { // Newer qemu with gigabyte aligned memory, // 32-bit pci mmio window is 2G -> 4G then. PlatformInfoHob->Uc32Base = BASE_2GB; @@ -92,8 +90,8 @@ PlatformQemuUc32BaseInitialization ( // variable MTRR suffices by truncating the size to a whole power of two, // while keeping the end affixed to 4GB. This will round the base up. // - LowerMemorySize = PlatformGetSystemMemorySizeBelow4gb (PlatformInfoHob); - PlatformInfoHob->Uc32Size = GetPowerOfTwo32 ((UINT32)(SIZE_4GB - LowerMemorySize)); + PlatformGetSystemMemorySizeBelow4gb (PlatformInfoHob); + PlatformInfoHob->Uc32Size = GetPowerOfTwo32 ((UINT32)(SIZE_4GB - PlatformInfoHob->LowMemory)); PlatformInfoHob->Uc32Base = (UINT32)(SIZE_4GB - PlatformInfoHob->Uc32Size); // // Assuming that LowerMemorySize is at least 1 byte, Uc32Size is at most 2GB. @@ -101,13 +99,13 @@ PlatformQemuUc32BaseInitialization ( // ASSERT (PlatformInfoHob->Uc32Base >= BASE_2GB); - if (PlatformInfoHob->Uc32Base != LowerMemorySize) { + if (PlatformInfoHob->Uc32Base != PlatformInfoHob->LowMemory) { DEBUG (( DEBUG_VERBOSE, "%a: rounded UC32 base from 0x%x up to 0x%x, for " "an UC32 size of 0x%x\n", __FUNCTION__, - LowerMemorySize, + PlatformInfoHob->LowMemory, PlatformInfoHob->Uc32Base, PlatformInfoHob->Uc32Size )); @@ -279,6 +277,33 @@ PlatformGetFirstNonAddressCB ( } } +/** + Store the low (below 4G) memory size in + PlatformInfoHob->LowMemory +**/ +VOID +PlatformGetLowMemoryCB ( + IN EFI_E820_ENTRY64 *E820Entry, + IN OUT EFI_HOB_PLATFORM_INFO *PlatformInfoHob + ) +{ + UINT64 Candidate; + + if (E820Entry->Type != EfiAcpiAddressRangeMemory) { + return; + } + + Candidate = E820Entry->BaseAddr + E820Entry->Length; + if (Candidate >= BASE_4GB) { + return; + } + + if (PlatformInfoHob->LowMemory < Candidate) { + DEBUG ((DEBUG_INFO, "%a: LowMemory=0x%Lx\n", __FUNCTION__, Candidate)); + PlatformInfoHob->LowMemory = Candidate; + } +} + /** Iterate over the RAM entries in QEMU's fw_cfg E820 RAM map, call the passed callback for each entry. @@ -395,14 +420,13 @@ GetHighestSystemMemoryAddressFromPvhMemmap ( return HighestAddress; } -UINT32 +VOID EFIAPI PlatformGetSystemMemorySizeBelow4gb ( IN EFI_HOB_PLATFORM_INFO *PlatformInfoHob ) { EFI_STATUS Status; - UINT64 LowerMemorySize = 0; UINT8 Cmos0x34; UINT8 Cmos0x35; @@ -410,12 +434,13 @@ PlatformGetSystemMemorySizeBelow4gb ( (CcProbe () != CcGuestTypeIntelTdx)) { // Get the information from PVH memmap - return (UINT32)GetHighestSystemMemoryAddressFromPvhMemmap (TRUE); + PlatformInfoHob->LowMemory = GetHighestSystemMemoryAddressFromPvhMemmap (TRUE); + return; } - Status = PlatformScanOrAdd64BitE820Ram (FALSE, &LowerMemorySize, NULL); - if ((Status == EFI_SUCCESS) && (LowerMemorySize > 0)) { - return (UINT32)LowerMemorySize; + Status = PlatformScanE820 (PlatformGetLowMemoryCB, PlatformInfoHob); + if ((Status == EFI_SUCCESS) && (PlatformInfoHob->LowMemory > 0)) { + return; } // @@ -430,7 +455,7 @@ PlatformGetSystemMemorySizeBelow4gb ( Cmos0x34 = (UINT8)PlatformCmosRead8 (0x34); Cmos0x35 = (UINT8)PlatformCmosRead8 (0x35); - return (UINT32)(((UINTN)((Cmos0x35 << 8) + Cmos0x34) << 16) + SIZE_16MB); + PlatformInfoHob->LowMemory = ((((UINTN)Cmos0x35 << 8) + Cmos0x34) << 16) + SIZE_16MB; } STATIC @@ -965,7 +990,6 @@ PlatformQemuInitializeRam ( IN EFI_HOB_PLATFORM_INFO *PlatformInfoHob ) { - UINT64 LowerMemorySize; UINT64 UpperMemorySize; MTRR_SETTINGS MtrrSettings; EFI_STATUS Status; @@ -975,7 +999,7 @@ PlatformQemuInitializeRam ( // // Determine total memory size available // - LowerMemorySize = PlatformGetSystemMemorySizeBelow4gb (PlatformInfoHob); + PlatformGetSystemMemorySizeBelow4gb (PlatformInfoHob); if (PlatformInfoHob->BootMode == BOOT_ON_S3_RESUME) { // @@ -1009,14 +1033,14 @@ PlatformQemuInitializeRam ( UINT32 TsegSize; TsegSize = PlatformInfoHob->Q35TsegMbytes * SIZE_1MB; - PlatformAddMemoryRangeHob (BASE_1MB, LowerMemorySize - TsegSize); + PlatformAddMemoryRangeHob (BASE_1MB, PlatformInfoHob->LowMemory - TsegSize); PlatformAddReservedMemoryBaseSizeHob ( - LowerMemorySize - TsegSize, + PlatformInfoHob->LowMemory - TsegSize, TsegSize, TRUE ); } else { - PlatformAddMemoryRangeHob (BASE_1MB, LowerMemorySize); + PlatformAddMemoryRangeHob (BASE_1MB, PlatformInfoHob->LowMemory); } // @@ -1194,9 +1218,10 @@ PlatformQemuInitializeRamForS3 ( // Make sure the TSEG area that we reported as a reserved memory resource // cannot be used for reserved memory allocations. // + PlatformGetSystemMemorySizeBelow4gb (PlatformInfoHob); TsegSize = PlatformInfoHob->Q35TsegMbytes * SIZE_1MB; BuildMemoryAllocationHob ( - PlatformGetSystemMemorySizeBelow4gb (PlatformInfoHob) - TsegSize, + PlatformInfoHob->LowMemory - TsegSize, TsegSize, EfiReservedMemoryType ); diff --git a/OvmfPkg/Library/PlatformInitLib/Platform.c b/OvmfPkg/Library/PlatformInitLib/Platform.c index 3e13c5d4b34f..9ab0342fd8c0 100644 --- a/OvmfPkg/Library/PlatformInitLib/Platform.c +++ b/OvmfPkg/Library/PlatformInitLib/Platform.c @@ -128,7 +128,6 @@ PlatformMemMapInitialization ( { UINT64 PciIoBase; UINT64 PciIoSize; - UINT32 TopOfLowRam; UINT64 PciExBarBase; UINT32 PciBase; UINT32 PciSize; @@ -150,7 +149,7 @@ PlatformMemMapInitialization ( return; } - TopOfLowRam = PlatformGetSystemMemorySizeBelow4gb (PlatformInfoHob); + PlatformGetSystemMemorySizeBelow4gb (PlatformInfoHob); PciExBarBase = 0; if (PlatformInfoHob->HostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) { // @@ -158,11 +157,11 @@ PlatformMemMapInitialization ( // the base of the 32-bit PCI host aperture. // PciExBarBase = PcdGet64 (PcdPciExpressBaseAddress); - ASSERT (TopOfLowRam <= PciExBarBase); + ASSERT (PlatformInfoHob->LowMemory <= PciExBarBase); ASSERT (PciExBarBase <= MAX_UINT32 - SIZE_256MB); PciBase = (UINT32)(PciExBarBase + SIZE_256MB); } else { - ASSERT (TopOfLowRam <= PlatformInfoHob->Uc32Base); + ASSERT (PlatformInfoHob->LowMemory <= PlatformInfoHob->Uc32Base); PciBase = PlatformInfoHob->Uc32Base; } diff --git a/OvmfPkg/PlatformPei/MemDetect.c b/OvmfPkg/PlatformPei/MemDetect.c index 3d8375320dcb..41d186986ba8 100644 --- a/OvmfPkg/PlatformPei/MemDetect.c +++ b/OvmfPkg/PlatformPei/MemDetect.c @@ -271,7 +271,8 @@ PublishPeiMemory ( UINT32 S3AcpiReservedMemoryBase; UINT32 S3AcpiReservedMemorySize; - LowerMemorySize = PlatformGetSystemMemorySizeBelow4gb (PlatformInfoHob); + PlatformGetSystemMemorySizeBelow4gb (PlatformInfoHob); + LowerMemorySize = PlatformInfoHob->LowMemory; if (PlatformInfoHob->SmmSmramRequire) { // // TSEG is chipped from the end of low RAM -- 2.39.0 ^ permalink raw reply related [flat|nested] 19+ messages in thread
* Re: [PATCH v2 2/4] OvmfPkg/PlatformInitLib: Add PlatformGetLowMemoryCB 2023-01-10 8:21 ` [PATCH v2 2/4] OvmfPkg/PlatformInitLib: Add PlatformGetLowMemoryCB Gerd Hoffmann @ 2023-01-10 16:53 ` Laszlo Ersek 2023-01-11 7:29 ` Gerd Hoffmann 0 siblings, 1 reply; 19+ messages in thread From: Laszlo Ersek @ 2023-01-10 16:53 UTC (permalink / raw) To: Gerd Hoffmann, devel Cc: Pawel Polawski, Jiewen Yao, Oliver Steffen, Jordan Justen, Ard Biesheuvel Quoting the hunks out of order: On 1/10/23 09:21, Gerd Hoffmann wrote: > Add PlatformGetLowMemoryCB() callback function for use with > PlatformScanE820(). It stores the low memory size in > PlatformInfoHob->LowMemory. This replaces calls to > PlatformScanOrAdd64BitE820Ram() with non-NULL LowMemory. > > Also change PlatformGetSystemMemorySizeBelow4gb() to likewise set > PlatformInfoHob->LowMemory instead of returning the value. Update > all Callers to the new convention. > > Signed-off-by: Gerd Hoffmann <kraxel@redhat.com> > --- > OvmfPkg/Include/Library/PlatformInitLib.h | 3 +- > OvmfPkg/Library/PeilessStartupLib/Hob.c | 3 +- > .../PeilessStartupLib/PeilessStartup.c | 7 +- > OvmfPkg/Library/PlatformInitLib/MemDetect.c | 69 +++++++++++++------ > OvmfPkg/Library/PlatformInitLib/Platform.c | 7 +- > OvmfPkg/PlatformPei/MemDetect.c | 3 +- > 6 files changed, 59 insertions(+), 33 deletions(-) > > diff --git a/OvmfPkg/Include/Library/PlatformInitLib.h b/OvmfPkg/Include/Library/PlatformInitLib.h > index bf6f90a5761c..051b31191194 100644 > --- a/OvmfPkg/Include/Library/PlatformInitLib.h > +++ b/OvmfPkg/Include/Library/PlatformInitLib.h > @@ -26,6 +26,7 @@ typedef struct { > BOOLEAN Q35SmramAtDefaultSmbase; > UINT16 Q35TsegMbytes; > > + UINT32 LowMemory; > UINT64 FirstNonAddress; > UINT8 PhysMemAddressWidth; > UINT32 Uc32Base; > @@ -144,7 +145,7 @@ PlatformQemuUc32BaseInitialization ( > IN OUT EFI_HOB_PLATFORM_INFO *PlatformInfoHob > ); > > -UINT32 > +VOID > EFIAPI > PlatformGetSystemMemorySizeBelow4gb ( > IN EFI_HOB_PLATFORM_INFO *PlatformInfoHob OK. > diff --git a/OvmfPkg/Library/PlatformInitLib/MemDetect.c b/OvmfPkg/Library/PlatformInitLib/MemDetect.c > index a2a4dc043f2e..63329c4e796a 100644 > --- a/OvmfPkg/Library/PlatformInitLib/MemDetect.c > +++ b/OvmfPkg/Library/PlatformInitLib/MemDetect.c > @@ -279,6 +277,33 @@ PlatformGetFirstNonAddressCB ( > } > } > > +/** > + Store the low (below 4G) memory size in > + PlatformInfoHob->LowMemory > +**/ > +VOID > +PlatformGetLowMemoryCB ( > + IN EFI_E820_ENTRY64 *E820Entry, > + IN OUT EFI_HOB_PLATFORM_INFO *PlatformInfoHob > + ) > +{ > + UINT64 Candidate; > + > + if (E820Entry->Type != EfiAcpiAddressRangeMemory) { > + return; > + } > + > + Candidate = E820Entry->BaseAddr + E820Entry->Length; > + if (Candidate >= BASE_4GB) { > + return; > + } > + > + if (PlatformInfoHob->LowMemory < Candidate) { > + DEBUG ((DEBUG_INFO, "%a: LowMemory=0x%Lx\n", __FUNCTION__, Candidate)); > + PlatformInfoHob->LowMemory = Candidate; > + } > +} > + > /** > Iterate over the RAM entries in QEMU's fw_cfg E820 RAM map, call the > passed callback for each entry. (1) This looks like a faithful conversion / extraction, but I'd vaguely noticed something earlier, in the original code. Namely, when the exclusive end of the range is exactly 4GB, that should still qualify as low memory, shouldn't it? Not that it matters in practice, because just below 4GB, we'll never ever have RAM on QEMU (pc or q35 -- I think even microvm, too). But, for clarity, changing the limit condition as a separate patch (afterwards) might make sense. For now, this conversion is faithful. > @@ -395,14 +420,13 @@ GetHighestSystemMemoryAddressFromPvhMemmap ( > return HighestAddress; > } > > -UINT32 > +VOID > EFIAPI > PlatformGetSystemMemorySizeBelow4gb ( > IN EFI_HOB_PLATFORM_INFO *PlatformInfoHob > ) > { > EFI_STATUS Status; > - UINT64 LowerMemorySize = 0; > UINT8 Cmos0x34; > UINT8 Cmos0x35; > > @@ -410,12 +434,13 @@ PlatformGetSystemMemorySizeBelow4gb ( > (CcProbe () != CcGuestTypeIntelTdx)) > { > // Get the information from PVH memmap > - return (UINT32)GetHighestSystemMemoryAddressFromPvhMemmap (TRUE); > + PlatformInfoHob->LowMemory = GetHighestSystemMemoryAddressFromPvhMemmap (TRUE); > + return; > } OK, so the way this function looks now is new to me. :) (2) Here you are converting a UINT64 from GetHighestSystemMemoryAddressFromPvhMemmap() to UINT32; I think that might trip up some MSVC compilers. I suggest preserving the cast. > > - Status = PlatformScanOrAdd64BitE820Ram (FALSE, &LowerMemorySize, NULL); > - if ((Status == EFI_SUCCESS) && (LowerMemorySize > 0)) { > - return (UINT32)LowerMemorySize; > + Status = PlatformScanE820 (PlatformGetLowMemoryCB, PlatformInfoHob); (3) Similar comment as under the previous patch: please set PlatformInfoHob->LowMemory = 0; before calling PlatformScanE820(), to preserve if (LowMemory != NULL) { *LowMemory = 0; } from PlatformScanOrAdd64BitE820Ram(). (I realize the platform info HOB could be zero-filled upon allocation -- but then at least for consistency with the 4GB+ search initialization, a comment could be justified.) > + if ((Status == EFI_SUCCESS) && (PlatformInfoHob->LowMemory > 0)) { > + return; > } (4) Side comment (for the future): Status == EFI_SUCCESS is more idiomatically written in edk2 as !EFI_ERROR (Status) > > // > @@ -430,7 +455,7 @@ PlatformGetSystemMemorySizeBelow4gb ( > Cmos0x34 = (UINT8)PlatformCmosRead8 (0x34); > Cmos0x35 = (UINT8)PlatformCmosRead8 (0x35); > > - return (UINT32)(((UINTN)((Cmos0x35 << 8) + Cmos0x34) << 16) + SIZE_16MB); > + PlatformInfoHob->LowMemory = ((((UINTN)Cmos0x35 << 8) + Cmos0x34) << 16) + SIZE_16MB; > } > (5) The UINT32 cast has been dropped; if UINTN is UINT64, this might again trigger a truncation warning from MSVC. (6) There is no need to change the scope that the original UINTN cast applies to. Pre-patch, the UINTN cast is bound to the following sub-expression: ((Cmos0x35 << 8) + Cmos0x34) here the variables are UINTN8, so they are promoted to INT32. The maximum mathematical value is 0xFFFF here, having with in INT32 is safe. We then cast it to UINTN (= at least UINT32) and then shift it further left by 16 bits (max: 0xFFFF_0000). The max value we may get after adding 16M is then 0x1_00FF_0000, which is above 4GB; it's up to QEMU not to provide such CMOS content then. Either way, there's no risk of INT32 overflow pre-patch. The post-patch code is certainly *easier to read*, so I don't have anything against re-binding the UINTN cast; but it should not be hidden in this patch. It makes it harder to verify the code refactoring. So anyway, what I need to remember from this point onward is that *each* call to PlatformGetSystemMemorySizeBelow4gb() doesn't just fetch and return a value, but *overwrites* "PlatformInfoHob->LowMemory". OK, let's continue with the callers of PlatformGetSystemMemorySizeBelow4gb() -- again, quoting hunks out of order: > diff --git a/OvmfPkg/PlatformPei/MemDetect.c b/OvmfPkg/PlatformPei/MemDetect.c > index 3d8375320dcb..41d186986ba8 100644 > --- a/OvmfPkg/PlatformPei/MemDetect.c > +++ b/OvmfPkg/PlatformPei/MemDetect.c > @@ -271,7 +271,8 @@ PublishPeiMemory ( > UINT32 S3AcpiReservedMemoryBase; > UINT32 S3AcpiReservedMemorySize; > > - LowerMemorySize = PlatformGetSystemMemorySizeBelow4gb (PlatformInfoHob); > + PlatformGetSystemMemorySizeBelow4gb (PlatformInfoHob); > + LowerMemorySize = PlatformInfoHob->LowMemory; > if (PlatformInfoHob->SmmSmramRequire) { > // > // TSEG is chipped from the end of low RAM So I really like how small this hunk is, and I wondered why it differed so much from the rest, where you removed the local variables. I understand now: because PublishPeiMemory() actually modifies "LowerMemorySize" in multiple steps. OK then, I see both points; here we need to keep "LowerMemorySize", because we can't modify the platform info HOB; but in the rest of the hunks, it's better if we just remove the useless locals. OK. > diff --git a/OvmfPkg/Library/PlatformInitLib/MemDetect.c b/OvmfPkg/Library/PlatformInitLib/MemDetect.c > index a2a4dc043f2e..63329c4e796a 100644 > --- a/OvmfPkg/Library/PlatformInitLib/MemDetect.c > +++ b/OvmfPkg/Library/PlatformInitLib/MemDetect.c > @@ -51,18 +51,16 @@ PlatformQemuUc32BaseInitialization ( > IN OUT EFI_HOB_PLATFORM_INFO *PlatformInfoHob > ) > { > - UINT32 LowerMemorySize; > - > if (PlatformInfoHob->HostBridgeDevId == 0xffff /* microvm */) { > return; > } > > if (PlatformInfoHob->HostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) { > - LowerMemorySize = PlatformGetSystemMemorySizeBelow4gb (PlatformInfoHob); > + PlatformGetSystemMemorySizeBelow4gb (PlatformInfoHob); > ASSERT (PcdGet64 (PcdPciExpressBaseAddress) <= MAX_UINT32); > - ASSERT (PcdGet64 (PcdPciExpressBaseAddress) >= LowerMemorySize); > + ASSERT (PcdGet64 (PcdPciExpressBaseAddress) >= PlatformInfoHob->LowMemory); > > - if (LowerMemorySize <= BASE_2GB) { > + if (PlatformInfoHob->LowMemory <= BASE_2GB) { > // Newer qemu with gigabyte aligned memory, > // 32-bit pci mmio window is 2G -> 4G then. > PlatformInfoHob->Uc32Base = BASE_2GB; OK. > @@ -92,8 +90,8 @@ PlatformQemuUc32BaseInitialization ( > // variable MTRR suffices by truncating the size to a whole power of two, > // while keeping the end affixed to 4GB. This will round the base up. > // > - LowerMemorySize = PlatformGetSystemMemorySizeBelow4gb (PlatformInfoHob); > - PlatformInfoHob->Uc32Size = GetPowerOfTwo32 ((UINT32)(SIZE_4GB - LowerMemorySize)); (7) Request for a *separate* follow-up patch: Commit 2a0bd3bffc80 ("OvmfPkg/PlatformInitLib: q35 mtrr setup fix", 2022-09-28) changed the structure of PlatformQemuUc32BaseInitialization() to the following one: - microvm: do nothing, just return - q35: depend on LowerMemorySize (change from 2a0bd3bffc80) - cloudhv: constant assignments, then return - i440fx: depend on LowerMemorySize Therefore we now have to branches (an explicit q35 branch and a "default" or "remaining" i440fx branch) that fetch LowerMemorySize. That code duplication is causing some churn for the present patch. I suggest reordering the branches as follows: - microvm: do nothing, just return - cloudhv: constant assignments, then return - grab LowerMemorySize -- commonly needed for the rest! - handle q35 - handle i440fx as default / fallback. This will centralize the LowerMemorySize fetching. > + PlatformGetSystemMemorySizeBelow4gb (PlatformInfoHob); > + PlatformInfoHob->Uc32Size = GetPowerOfTwo32 ((UINT32)(SIZE_4GB - PlatformInfoHob->LowMemory)); > PlatformInfoHob->Uc32Base = (UINT32)(SIZE_4GB - PlatformInfoHob->Uc32Size); > // > // Assuming that LowerMemorySize is at least 1 byte, Uc32Size is at most 2GB. > @@ -101,13 +99,13 @@ PlatformQemuUc32BaseInitialization ( > // > ASSERT (PlatformInfoHob->Uc32Base >= BASE_2GB); > > - if (PlatformInfoHob->Uc32Base != LowerMemorySize) { > + if (PlatformInfoHob->Uc32Base != PlatformInfoHob->LowMemory) { > DEBUG (( > DEBUG_VERBOSE, > "%a: rounded UC32 base from 0x%x up to 0x%x, for " > "an UC32 size of 0x%x\n", > __FUNCTION__, > - LowerMemorySize, > + PlatformInfoHob->LowMemory, > PlatformInfoHob->Uc32Base, > PlatformInfoHob->Uc32Size > )); OK. > STATIC > @@ -965,7 +990,6 @@ PlatformQemuInitializeRam ( > IN EFI_HOB_PLATFORM_INFO *PlatformInfoHob > ) > { > - UINT64 LowerMemorySize; > UINT64 UpperMemorySize; > MTRR_SETTINGS MtrrSettings; > EFI_STATUS Status; > @@ -975,7 +999,7 @@ PlatformQemuInitializeRam ( > // > // Determine total memory size available > // > - LowerMemorySize = PlatformGetSystemMemorySizeBelow4gb (PlatformInfoHob); > + PlatformGetSystemMemorySizeBelow4gb (PlatformInfoHob); > > if (PlatformInfoHob->BootMode == BOOT_ON_S3_RESUME) { > // > @@ -1009,14 +1033,14 @@ PlatformQemuInitializeRam ( > UINT32 TsegSize; > > TsegSize = PlatformInfoHob->Q35TsegMbytes * SIZE_1MB; > - PlatformAddMemoryRangeHob (BASE_1MB, LowerMemorySize - TsegSize); > + PlatformAddMemoryRangeHob (BASE_1MB, PlatformInfoHob->LowMemory - TsegSize); > PlatformAddReservedMemoryBaseSizeHob ( > - LowerMemorySize - TsegSize, > + PlatformInfoHob->LowMemory - TsegSize, > TsegSize, > TRUE > ); > } else { > - PlatformAddMemoryRangeHob (BASE_1MB, LowerMemorySize); > + PlatformAddMemoryRangeHob (BASE_1MB, PlatformInfoHob->LowMemory); > } > > // OK. I think I used UINT64 here because these HOB-adding functions take 64-bit params. But UINT32 should work fine too. (8) Note that a bit lower, we have a comment: // // We'd like to keep the following ranges uncached: // - [640 KB, 1 MB) // - [LowerMemorySize, 4 GB) // The "LowerMemorySize" reference in this commit is actually my fault; it's an oversight / omission from commit 49edde15230a ("OvmfPkg/PlatformPei: set 32-bit UC area at PciBase / PciExBarBase (pc/q35)", 2019-06-03). The comment should now say "PlatformInfoHob->Uc32Base". If you can submit a separate patch for that, that would be great; it's not too important though. (9) BTW, still regarding commit 2a0bd3bffc80 ("OvmfPkg/PlatformInitLib: q35 mtrr setup fix", 2022-09-28) -- does the following code comment still apply? // // Set the memory range from the start of the 32-bit MMIO area (32-bit PCI // MMIO aperture on i440fx, PCIEXBAR on q35) to 4GB as uncacheable. // Because, in case the new branch introduced by commit 2a0bd3bffc80 takes effect (namely, "Uc32Base = BASE_2GB"), I'm not sure where the PCIEXBAR starts, and then the above comment may no longer hold. > @@ -1194,9 +1218,10 @@ PlatformQemuInitializeRamForS3 ( > // Make sure the TSEG area that we reported as a reserved memory resource > // cannot be used for reserved memory allocations. > // > + PlatformGetSystemMemorySizeBelow4gb (PlatformInfoHob); > TsegSize = PlatformInfoHob->Q35TsegMbytes * SIZE_1MB; > BuildMemoryAllocationHob ( > - PlatformGetSystemMemorySizeBelow4gb (PlatformInfoHob) - TsegSize, > + PlatformInfoHob->LowMemory - TsegSize, > TsegSize, > EfiReservedMemoryType > ); OK. > diff --git a/OvmfPkg/Library/PeilessStartupLib/Hob.c b/OvmfPkg/Library/PeilessStartupLib/Hob.c > index 630ce445ebec..784a8ba194de 100644 > --- a/OvmfPkg/Library/PeilessStartupLib/Hob.c > +++ b/OvmfPkg/Library/PeilessStartupLib/Hob.c > @@ -41,8 +41,9 @@ ConstructSecHobList ( > EFI_HOB_PLATFORM_INFO PlatformInfoHob; > > ZeroMem (&PlatformInfoHob, sizeof (PlatformInfoHob)); > + PlatformGetSystemMemorySizeBelow4gb (&PlatformInfoHob); > PlatformInfoHob.HostBridgeDevId = PciRead16 (OVMF_HOSTBRIDGE_DID); > - LowMemorySize = PlatformGetSystemMemorySizeBelow4gb (&PlatformInfoHob); > + LowMemorySize = PlatformInfoHob.LowMemory; > ASSERT (LowMemorySize != 0); > LowMemoryStart = FixedPcdGet32 (PcdOvmfDxeMemFvBase) + FixedPcdGet32 (PcdOvmfDxeMemFvSize); > LowMemorySize -= LowMemoryStart; (10) I think this PlatformGetSystemMemorySizeBelow4gb() call is not placed correctly. PlatformGetSystemMemorySizeBelow4gb() depends on "HostBridgeDevId", but this hunk reorders the setting of "HostBridgeDevId" against the call to PlatformGetSystemMemorySizeBelow4gb(). > diff --git a/OvmfPkg/Library/PeilessStartupLib/PeilessStartup.c b/OvmfPkg/Library/PeilessStartupLib/PeilessStartup.c > index 380e71597206..928120d183ba 100644 > --- a/OvmfPkg/Library/PeilessStartupLib/PeilessStartup.c > +++ b/OvmfPkg/Library/PeilessStartupLib/PeilessStartup.c > @@ -41,8 +41,7 @@ InitializePlatform ( > EFI_HOB_PLATFORM_INFO *PlatformInfoHob > ) > { > - UINT32 LowerMemorySize; > - VOID *VariableStore; > + VOID *VariableStore; > > DEBUG ((DEBUG_INFO, "InitializePlatform in Pei-less boot\n")); > PlatformDebugDumpCmos (); > @@ -70,14 +69,14 @@ InitializePlatform ( > PlatformInfoHob->PcdCpuBootLogicalProcessorNumber > )); > > - LowerMemorySize = PlatformGetSystemMemorySizeBelow4gb (PlatformInfoHob); > + PlatformGetSystemMemorySizeBelow4gb (PlatformInfoHob); > PlatformQemuUc32BaseInitialization (PlatformInfoHob); > DEBUG (( > DEBUG_INFO, > "Uc32Base = 0x%x, Uc32Size = 0x%x, LowerMemorySize = 0x%x\n", > PlatformInfoHob->Uc32Base, > PlatformInfoHob->Uc32Size, > - LowerMemorySize > + PlatformInfoHob->LowMemory > )); > > VariableStore = PlatformReserveEmuVariableNvStore (); Seems OK. > diff --git a/OvmfPkg/Library/PlatformInitLib/Platform.c b/OvmfPkg/Library/PlatformInitLib/Platform.c > index 3e13c5d4b34f..9ab0342fd8c0 100644 > --- a/OvmfPkg/Library/PlatformInitLib/Platform.c > +++ b/OvmfPkg/Library/PlatformInitLib/Platform.c > @@ -128,7 +128,6 @@ PlatformMemMapInitialization ( > { > UINT64 PciIoBase; > UINT64 PciIoSize; > - UINT32 TopOfLowRam; > UINT64 PciExBarBase; > UINT32 PciBase; > UINT32 PciSize; > @@ -150,7 +149,7 @@ PlatformMemMapInitialization ( > return; > } > > - TopOfLowRam = PlatformGetSystemMemorySizeBelow4gb (PlatformInfoHob); > + PlatformGetSystemMemorySizeBelow4gb (PlatformInfoHob); > PciExBarBase = 0; > if (PlatformInfoHob->HostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) { > // > @@ -158,11 +157,11 @@ PlatformMemMapInitialization ( > // the base of the 32-bit PCI host aperture. > // > PciExBarBase = PcdGet64 (PcdPciExpressBaseAddress); > - ASSERT (TopOfLowRam <= PciExBarBase); > + ASSERT (PlatformInfoHob->LowMemory <= PciExBarBase); > ASSERT (PciExBarBase <= MAX_UINT32 - SIZE_256MB); > PciBase = (UINT32)(PciExBarBase + SIZE_256MB); This change looks OK, but, similarly to my question (9): (11) Is the following comment still up to date: // // The MMCONFIG area is expected to fall between the top of low RAM and // the base of the 32-bit PCI host aperture. // with regard to the new branch introduced by commit 2a0bd3bffc80 ("OvmfPkg/PlatformInitLib: q35 mtrr setup fix", 2022-09-28)? > } else { > - ASSERT (TopOfLowRam <= PlatformInfoHob->Uc32Base); > + ASSERT (PlatformInfoHob->LowMemory <= PlatformInfoHob->Uc32Base); > PciBase = PlatformInfoHob->Uc32Base; > } > OK. Thanks, Laszlo ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v2 2/4] OvmfPkg/PlatformInitLib: Add PlatformGetLowMemoryCB 2023-01-10 16:53 ` Laszlo Ersek @ 2023-01-11 7:29 ` Gerd Hoffmann 2023-01-11 13:56 ` Laszlo Ersek 0 siblings, 1 reply; 19+ messages in thread From: Gerd Hoffmann @ 2023-01-11 7:29 UTC (permalink / raw) To: Laszlo Ersek Cc: devel, Pawel Polawski, Jiewen Yao, Oliver Steffen, Jordan Justen, Ard Biesheuvel > > + Candidate = E820Entry->BaseAddr + E820Entry->Length; > > + if (Candidate >= BASE_4GB) { > > + return; > > + } > (1) This looks like a faithful conversion / extraction, but I'd vaguely > noticed something earlier, in the original code. Namely, when the > exclusive end of the range is exactly 4GB, that should still qualify as > low memory, shouldn't it? > > Not that it matters in practice, because just below 4GB, we'll never > ever have RAM on QEMU (pc or q35 -- I think even microvm, too). Yes. > But, for clarity, changing the limit condition as a separate patch > (afterwards) might make sense. Well, BASE_4GB-1 fits into LowMemory (which is UINT32) whereas BASE_4GB does not ... > > - return (UINT32)GetHighestSystemMemoryAddressFromPvhMemmap (TRUE); > > + PlatformInfoHob->LowMemory = GetHighestSystemMemoryAddressFromPvhMemmap (TRUE); > (2) Here you are converting a UINT64 from > GetHighestSystemMemoryAddressFromPvhMemmap() to UINT32; I think that > might trip up some MSVC compilers. I suggest preserving the cast. OK. > PlatformInfoHob->LowMemory = 0; > (I realize the platform info HOB could be zero-filled upon allocation -- > but then at least for consistency with the 4GB+ search initialization, a > comment could be justified.) It's explicitly cleared with ZeroMem (in BuildPlatformInfoHob), so there is no zero-initialize LowMemory again. > > diff --git a/OvmfPkg/PlatformPei/MemDetect.c b/OvmfPkg/PlatformPei/MemDetect.c > > index 3d8375320dcb..41d186986ba8 100644 > > --- a/OvmfPkg/PlatformPei/MemDetect.c > > +++ b/OvmfPkg/PlatformPei/MemDetect.c > > @@ -271,7 +271,8 @@ PublishPeiMemory ( > > UINT32 S3AcpiReservedMemoryBase; > > UINT32 S3AcpiReservedMemorySize; > > > > - LowerMemorySize = PlatformGetSystemMemorySizeBelow4gb (PlatformInfoHob); > > + PlatformGetSystemMemorySizeBelow4gb (PlatformInfoHob); > > + LowerMemorySize = PlatformInfoHob->LowMemory; > > if (PlatformInfoHob->SmmSmramRequire) { > > // > > // TSEG is chipped from the end of low RAM > > So I really like how small this hunk is, and I wondered why it differed > so much from the rest, where you removed the local variables. > > I understand now: because PublishPeiMemory() actually modifies > "LowerMemorySize" in multiple steps. OK then, I see both points; here we > need to keep "LowerMemorySize", because we can't modify the platform > info HOB; but in the rest of the hunks, it's better if we just remove > the useless locals. OK. Yes, that is the pattern. LowMemory holds the memory installed. PublishPeiMemory calculates how edk2 uses that memory, which is something different. > code duplication is causing some churn for the present patch. I suggest > reordering the branches as follows: > > - microvm: do nothing, just return > - cloudhv: constant assignments, then return > - grab LowerMemorySize -- commonly needed for the rest! > - handle q35 > - handle i440fx as default / fallback. Makes sense indeed. > (9) BTW, still regarding commit 2a0bd3bffc80 ("OvmfPkg/PlatformInitLib: > q35 mtrr setup fix", 2022-09-28) -- does the following code comment > still apply? > > // > // Set the memory range from the start of the 32-bit MMIO area (32-bit PCI > // MMIO aperture on i440fx, PCIEXBAR on q35) to 4GB as uncacheable. > // > > Because, in case the new branch introduced by commit 2a0bd3bffc80 takes > effect (namely, "Uc32Base = BASE_2GB"), I'm not sure where the PCIEXBAR > starts, and then the above comment may no longer hold. PCIEXBAR location doesn't change, it's still at 0xb0000000. > > ZeroMem (&PlatformInfoHob, sizeof (PlatformInfoHob)); > > + PlatformGetSystemMemorySizeBelow4gb (&PlatformInfoHob); > > PlatformInfoHob.HostBridgeDevId = PciRead16 (OVMF_HOSTBRIDGE_DID); > > - LowMemorySize = PlatformGetSystemMemorySizeBelow4gb (&PlatformInfoHob); > > + LowMemorySize = PlatformInfoHob.LowMemory; > > ASSERT (LowMemorySize != 0); > > LowMemoryStart = FixedPcdGet32 (PcdOvmfDxeMemFvBase) + FixedPcdGet32 (PcdOvmfDxeMemFvSize); > > LowMemorySize -= LowMemoryStart; > > (10) I think this PlatformGetSystemMemorySizeBelow4gb() call is not > placed correctly. > > PlatformGetSystemMemorySizeBelow4gb() depends on "HostBridgeDevId", but > this hunk reorders the setting of "HostBridgeDevId" against the call to > PlatformGetSystemMemorySizeBelow4gb(). Correct, nice catch. Placed it there for optical reasons (keep the nice '=' alignment) but didn't realize that. > > diff --git a/OvmfPkg/Library/PlatformInitLib/Platform.c b/OvmfPkg/Library/PlatformInitLib/Platform.c > > index 3e13c5d4b34f..9ab0342fd8c0 100644 > > --- a/OvmfPkg/Library/PlatformInitLib/Platform.c > > +++ b/OvmfPkg/Library/PlatformInitLib/Platform.c > > @@ -128,7 +128,6 @@ PlatformMemMapInitialization ( > > { > > UINT64 PciIoBase; > > UINT64 PciIoSize; > > - UINT32 TopOfLowRam; > > UINT64 PciExBarBase; > > UINT32 PciBase; > > UINT32 PciSize; > > @@ -150,7 +149,7 @@ PlatformMemMapInitialization ( > > return; > > } > > > > - TopOfLowRam = PlatformGetSystemMemorySizeBelow4gb (PlatformInfoHob); > > + PlatformGetSystemMemorySizeBelow4gb (PlatformInfoHob); > > PciExBarBase = 0; > > if (PlatformInfoHob->HostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) { > > // > > @@ -158,11 +157,11 @@ PlatformMemMapInitialization ( > > // the base of the 32-bit PCI host aperture. > > // > > PciExBarBase = PcdGet64 (PcdPciExpressBaseAddress); > > - ASSERT (TopOfLowRam <= PciExBarBase); > > + ASSERT (PlatformInfoHob->LowMemory <= PciExBarBase); > > ASSERT (PciExBarBase <= MAX_UINT32 - SIZE_256MB); > > PciBase = (UINT32)(PciExBarBase + SIZE_256MB); > > This change looks OK, but, similarly to my question (9): > > (11) Is the following comment still up to date: > > // > // The MMCONFIG area is expected to fall between the top of low RAM and > // the base of the 32-bit PCI host aperture. > // > > with regard to the new branch introduced by commit 2a0bd3bffc80 > ("OvmfPkg/PlatformInitLib: q35 mtrr setup fix", 2022-09-28)? root@fedora ~# cat /proc/iomem [ ... ] 7ebfe000-7effffff : System RAM 7f000000-7fffffff : Reserved 80000000-afffffff : PCI Bus 0000:00 b0000000-bfffffff : PCI MMCONFIG 0000 [bus 00-ff] b0000000-bfffffff : Reserved b0000000-bfffffff : pnp 00:04 c0000000-febfffff : PCI Bus 0000:00 [ ... ] root@fedora ~# cat /proc/mtrr reg00: base=0x080000000 ( 2048MB), size= 2048MB, count=1: uncachable reg01: base=0x800000000 (32768MB), size=32768MB, count=1: uncachable With gigabyte-alignment being the common case these days it might make sense to place the MMCONFIG area at 0xe0000000 instead ... take care, Gerd ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v2 2/4] OvmfPkg/PlatformInitLib: Add PlatformGetLowMemoryCB 2023-01-11 7:29 ` Gerd Hoffmann @ 2023-01-11 13:56 ` Laszlo Ersek 2023-01-11 15:23 ` Gerd Hoffmann 0 siblings, 1 reply; 19+ messages in thread From: Laszlo Ersek @ 2023-01-11 13:56 UTC (permalink / raw) To: Gerd Hoffmann Cc: devel, Pawel Polawski, Jiewen Yao, Oliver Steffen, Jordan Justen, Ard Biesheuvel On 1/11/23 08:29, Gerd Hoffmann wrote: >> (9) BTW, still regarding commit 2a0bd3bffc80 ("OvmfPkg/PlatformInitLib: >> q35 mtrr setup fix", 2022-09-28) -- does the following code comment >> still apply? >> >> // >> // Set the memory range from the start of the 32-bit MMIO area (32-bit PCI >> // MMIO aperture on i440fx, PCIEXBAR on q35) to 4GB as uncacheable. >> // >> >> Because, in case the new branch introduced by commit 2a0bd3bffc80 takes >> effect (namely, "Uc32Base = BASE_2GB"), I'm not sure where the PCIEXBAR >> starts, and then the above comment may no longer hold. > > PCIEXBAR location doesn't change, it's still at 0xb0000000. >>> @@ -158,11 +157,11 @@ PlatformMemMapInitialization ( >>> // the base of the 32-bit PCI host aperture. >>> // >>> PciExBarBase = PcdGet64 (PcdPciExpressBaseAddress); >>> - ASSERT (TopOfLowRam <= PciExBarBase); >>> + ASSERT (PlatformInfoHob->LowMemory <= PciExBarBase); >>> ASSERT (PciExBarBase <= MAX_UINT32 - SIZE_256MB); >>> PciBase = (UINT32)(PciExBarBase + SIZE_256MB); >> >> This change looks OK, but, similarly to my question (9): >> >> (11) Is the following comment still up to date: >> >> // >> // The MMCONFIG area is expected to fall between the top of low RAM and >> // the base of the 32-bit PCI host aperture. >> // >> >> with regard to the new branch introduced by commit 2a0bd3bffc80 >> ("OvmfPkg/PlatformInitLib: q35 mtrr setup fix", 2022-09-28)? > > root@fedora ~# cat /proc/iomem > [ ... ] > 7ebfe000-7effffff : System RAM > 7f000000-7fffffff : Reserved > 80000000-afffffff : PCI Bus 0000:00 > b0000000-bfffffff : PCI MMCONFIG 0000 [bus 00-ff] > b0000000-bfffffff : Reserved > b0000000-bfffffff : pnp 00:04 > c0000000-febfffff : PCI Bus 0000:00 > [ ... ] > root@fedora ~# cat /proc/mtrr > reg00: base=0x080000000 ( 2048MB), size= 2048MB, count=1: uncachable > reg01: base=0x800000000 (32768MB), size=32768MB, count=1: uncachable Ugh, what? :) I was about to point out a contradiction between (a) the following from commit 2a0bd3bffc80: + // Newer qemu with gigabyte aligned memory, + // 32-bit pci mmio window is 2G -> 4G then. and (b) your confirmation that the PCIEXBAR location does not change. Namely, I was about to point out that PCIEXBAR -- *config space* expressed as MMIO -- would then overlap the 32-bit MMIO aperture, the one that's assignable to BARs as MMIO space. But then your /proc/iomem quote actually confirms this is what happens in practice -- and apparently works??? In Linux anyways? FWIW I don't see how this is safe with regard to the firmware. Even if QEMU is capable of generating a set of discontiguous resource descriptors in the DSDT / _CRS, and Linux is capable of dealing with that, I don't understand how the firmware does it. Has it only been working by chance, perhaps? PciHostBridgeDxe uses this intersection-based MMIO addition that we discussed in the BZ, so I certainly don't expect a conflict there; after all, the MMIO space used for MMCONFIG and the MMIO space used for BAR assignments should mostly be the same; IOW there should be no conflict or compatibility problem at the GCD level that PciHostBridgeDxe chokes on. But when the actual BARs are assigned (allocated), what prevents them from being allocated from the overlapping MMCONFIG "sub" interval? I think there's a problem there, we just have not hit it yet. OK, OK, let me review what the code actually does. Here's the relevant part of the call tree: InitializePlatform() [OvmfPkg/PlatformPei/Platform.c] [1] PlatformQemuUc32BaseInitialization() [OvmfPkg/Library/PlatformInitLib/MemDetect.c] InitializeRamRegions() [OvmfPkg/PlatformPei/MemDetect.c] [2] PlatformQemuInitializeRam() [OvmfPkg/Library/PlatformInitLib/MemDetect.c] MemMapInitialization() [OvmfPkg/PlatformPei/Platform.c] [3] PlatformMemMapInitialization() [OvmfPkg/Library/PlatformInitLib/Platform.c] MiscInitialization() [OvmfPkg/PlatformPei/Platform.c] PlatformMiscInitialization() [OvmfPkg/Library/PlatformInitLib/Platform.c] [4] PciExBarInitialization() [OvmfPkg/Library/PlatformInitLib/Platform.c] [5] AmdSevDxeEntryPoint() [OvmfPkg/AmdSevDxe/AmdSevDxe.c] - At [1], the most recent state is from commit 2a0bd3bffc80 ("OvmfPkg/PlatformInitLib: q35 mtrr setup fix", 2022-09-28). What this commit does is, it lowers (conditionally) the base of the area that we'll mark as UC ("Uc32Base"), from 0xB0000000 (2816 MB, the start of the EXBAR) to 2048 MB. It does not change the location of MMCONFIG *or* the 32-bit MMIO aperture. It only adds a *comment* like this: + // Newer qemu with gigabyte aligned memory, + // 32-bit pci mmio window is 2G -> 4G then. which is a *natural language statement* about the 32-bit MMIO aperture, but no code change. - At [2], we mark the area [Uc32Base, 4GB) as uncacheable in the MTRRs. There is a comment saying: // // Set the memory range from the start of the 32-bit MMIO area (32-bit PCI // MMIO aperture on i440fx, PCIEXBAR on q35) to 4GB as uncacheable. // And this comment *conflicts* with the one from [1]. Because on Q35, the new Uc32Base (2GB) may not actually match the PCIEXBAR start (2816 MB). Therefore commit 2a0bd3bffc80 made the comment at [2] stale. This is issue {1}. Still, this is not a functional error, as we're only marking a *larger* (and simpler-to-express) area as UC than before. When this new logic fires, we have *nothing* in the space between the 32-bit RAM and the EXBAR base -- thus far, anyway!. - At [3], we have a comment saying // // The MMCONFIG area is expected to fall between the top of low RAM and // the base of the 32-bit PCI host aperture. // plus code that actually *implements* this. In spite of the *comment* added in commit 2a0bd3bffc80, at [1], the logic at [3] *still* -- correctly -- places the 32-bit MMIO aperture *above* the PCIEXBAR. This is what PciHostBridgeDxe will expose as aperture, and what PciBusDxe will assign BARs from. No conflict is possible with the MMCONFIG area. This is in fact confirmed by the following log snippet, when booting a pc-q35-7.2 guest with 1792 MB of RAM: > PciHostBridgeUtilityInitRootBridge: populated root bus 0, with room for 255 subordinate bus(es) > RootBridge: PciRoot(0x0) > Support/Attr: 70069 / 70069 > DmaAbove4G: No > NoExtConfSpace: No > AllocAttr: 3 (CombineMemPMem Mem64Decode) > Bus: 0 - FF Translation=0 > Io: 6000 - FFFF Translation=0 > Mem: C0000000 - FBFFFFFF Translation=0 > MemAbove4G: 800000000 - FFFFFFFFF Translation=0 > PMem: FFFFFFFFFFFFFFFF - 0 Translation=0 > PMemAbove4G: FFFFFFFFFFFFFFFF - 0 Translation=0 Note "Mem: C0000000 - FBFFFFFF Translation=0". - Still at [3], we cover the MMCONFIG area with a reserved memory HOB (not MMIO HOB). This is alright; and again the reason we have no conflict in PciHostBridgeDxe is that the 32-bit MMIO aperture *still* starts above the EXBAR; it does not "surround" it. - At [4], we actually program the EXBAR. - At [5], early in the DXE phase, knowing that we marked the EXBAR as reserved memory and not as MMIO, we explicitly decrypt (when on SEV) the EXBAR. OK, so what do we learn from the above? - issue {1}: the statement in [2] PlatformQemuInitializeRam(), in the following comment: // // Set the memory range from the start of the 32-bit MMIO area (32-bit PCI // MMIO aperture on i440fx, PCIEXBAR on q35) to 4GB as uncacheable. // was broken by commit 2a0bd3bffc80. - issue {2}: the statement from commit 2a0bd3bffc80 + // 32-bit pci mmio window is 2G -> 4G then. is not factual, as far as the firmware is concerned. I don't know *how* Linux ends up extending the MMIO aperture so far down that it streddles / embeds MMCONFIG, but AFAICT it has nothing to do with the firmware. Therefore, I also don't understand where the requirement comes (from Linux? where?) that the firmware mark the "gap" between 2048 MB and 2816 MB as uncached. The firmware does not use it for anything, so why does the Linux kernel do? And if the Linux kernel does, then why does it not reprogram the MTRRs as well? The commit message from commit 2a0bd3bffc80 states, "Which effectively makes the 32-bit pci mmio window start at 0x80000000". I'm precisely after that "effectively" adverb here: placing the 32-bit MMIO aperture at 2048 MB is not *at all* what the firmware does. ... OK, I think I've found it! It's the following QEMU commit: 4a4418369d6d ("q35: fix mmconfig and PCI0._CRS", 2019-06-16). I've even found the original discussion: - v1: http://mid.mail-archive.com/20190528204331.5280-1-kraxel@redhat.com - v2: http://mid.mail-archive.com/20190607073429.3436-1-kraxel@redhat.com So, this seems to happen by QEMU moving the hole as low as possible in the \SB.PCI0 _CRS, in the DSDT, punching gaps as neeed. And Linux adheres to that. I've tested it with said pc-q35-7.2 guest with 1792 MB of RAM, running RHEL-7.9 (that's what I've had handy). The MTRR update from edk2 commit 2a0bd3bffc80 takes effect: > [ 0.000000] MTRR variable ranges enabled: > [ 0.000000] 0 base 0080000000 mask FF80000000 uncachable *but* the start of the 32-bit MMIO range (which is discontiguous) appears even lower, per QEMU commit 4a4418369d6d: > [ 0.000000] e820: [mem 0x70000000-0xafffffff] available for PCI devices > ... > [ 0.281120] pci_bus 0000:00: root bus resource [mem 0x70000000-0xafffffff window] > ... > [ 0.529741] pci 0000:00:02.0: BAR 6: assigned [mem 0x70000000-0x7000ffff pref] > ... > [ 0.565903] pci_bus 0000:00: resource 7 [mem 0x70000000-0xafffffff window] and > 70000000-afffffff : PCI Bus 0000:00 > 70000000-7000ffff : 0000:00:02.0 > b0000000-bfffffff : PCI MMCONFIG 0000 [bus 00-ff] > b0000000-bfffffff : reserved > b0000000-bfffffff : pnp 00:04 > c0000000-febfffff : PCI Bus 0000:00 > c0000000-c0ffffff : 0000:00:02.0 > c0000000-c0ffffff : bochs-drm There is *no sign* of 0x70000000 in the firmware log. So Linux effectively ressigns some PCI resources, and utilizes the (discontiguous) area that QEMU exposes in the DSDT, with the firmware knowing nothing about it. Note, again, that our UC settings in the MTRR start *higher*, at 2GB. So not only am I unconvinced (or at least confused!) that edk2 commit 2a0bd3bffc80 was necessary, it even *seems* insufficient, for UC-coverage of the 32-bit MMIO aperture. In practice though, it doesn't seem to cause issues! (Which again questions if the original change in 2a0bd3bffc80 was really necessary.) I've filed a new TianoCore BZ about clarifying the comments please: https://bugzilla.tianocore.org/show_bug.cgi?id=4289 > With gigabyte-alignment being the common case these days it might make > sense to place the MMCONFIG area at 0xe0000000 instead ... I feel really unsafe about complicating this code even further. Laszlo ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v2 2/4] OvmfPkg/PlatformInitLib: Add PlatformGetLowMemoryCB 2023-01-11 13:56 ` Laszlo Ersek @ 2023-01-11 15:23 ` Gerd Hoffmann 2023-01-12 11:09 ` Laszlo Ersek 0 siblings, 1 reply; 19+ messages in thread From: Gerd Hoffmann @ 2023-01-11 15:23 UTC (permalink / raw) To: Laszlo Ersek Cc: devel, Pawel Polawski, Jiewen Yao, Oliver Steffen, Jordan Justen, Ard Biesheuvel > > root@fedora ~# cat /proc/iomem > > [ ... ] > > 7ebfe000-7effffff : System RAM > > 7f000000-7fffffff : Reserved > > 80000000-afffffff : PCI Bus 0000:00 > > b0000000-bfffffff : PCI MMCONFIG 0000 [bus 00-ff] > > b0000000-bfffffff : Reserved > > b0000000-bfffffff : pnp 00:04 > > c0000000-febfffff : PCI Bus 0000:00 > > [ ... ] > > root@fedora ~# cat /proc/mtrr > > reg00: base=0x080000000 ( 2048MB), size= 2048MB, count=1: uncachable > > reg01: base=0x800000000 (32768MB), size=32768MB, count=1: uncachable > > Ugh, what? :) > > I was about to point out a contradiction between (a) the following from > commit 2a0bd3bffc80: > > + // Newer qemu with gigabyte aligned memory, > + // 32-bit pci mmio window is 2G -> 4G then. > > and (b) your confirmation that the PCIEXBAR location does not change. > Namely, I was about to point out that PCIEXBAR -- *config space* > expressed as MMIO -- would then overlap the 32-bit MMIO aperture, the > one that's assignable to BARs as MMIO space. > > But then your /proc/iomem quote actually confirms this is what happens > in practice -- and apparently works??? In Linux anyways? > > FWIW I don't see how this is safe with regard to the firmware. Even if > QEMU is capable of generating a set of discontiguous resource > descriptors in the DSDT / _CRS, and Linux is capable of dealing with > that, I don't understand how the firmware does it. It doesn't. It still operates with the 0xc0000000+ range as 32bit mmio window. Which is why the 80000000-afffffff range is unused. Linux could map hotplug device resources there, but that's it. > > Bus: 0 - FF Translation=0 > > Io: 6000 - FFFF Translation=0 > > Mem: C0000000 - FBFFFFFF Translation=0 > > MemAbove4G: 800000000 - FFFFFFFFF Translation=0 > > PMem: FFFFFFFFFFFFFFFF - 0 Translation=0 > > PMemAbove4G: FFFFFFFFFFFFFFFF - 0 Translation=0 > > Note "Mem: C0000000 - FBFFFFFF Translation=0". Yes. > Therefore, I also don't understand where the requirement comes (from > Linux? where?) that the firmware mark the "gap" between 2048 MB and > 2816 MB as uncached. The firmware does not use it for anything, so why > does the Linux kernel do? And if the Linux kernel does, then why does > it not reprogram the MTRRs as well? Some test case complained because the 80000000-afffffff range is io address space (according to /proc/iomem) but not tagged as uncachable in mtrr registers. > The commit message from commit 2a0bd3bffc80 states, "Which effectively > makes the 32-bit pci mmio window start at 0x80000000". .. according to the guest os view because qemu generates _CRS resources with 80000000-afffffff included. > I'm precisely after that "effectively" adverb here: placing the 32-bit > MMIO aperture at 2048 MB is not *at all* what the firmware does. Yes. > I've filed a new TianoCore BZ about clarifying the comments please: > > https://bugzilla.tianocore.org/show_bug.cgi?id=4289 OK. > > With gigabyte-alignment being the common case these days it might make > > sense to place the MMCONFIG area at 0xe0000000 instead ... > > I feel really unsafe about complicating this code even further. I think it should actually simplify things. All the inconsistencies we have (as you outlined above) due to the hole punching and edk2 supporting only a single range for 32bit mmio should go away, and we will have less address space layout differences between q35 and pc. We'll set LowMemory -> 4G to UC via mtrr (both pc and q35) We'll use LowMemory -> 0xFBFFFFFF (pc) or LowMemory -> 0xdfffffff (q35) as 32bit mmio window. We'll use 0xe0000000 -> 0xeffffffff for mmconfig (q35 only). Qemu will add 0xf0000000 -> 0xFBFFFFFF to the PCI bus _CRS so linux could use it but the firmware wouldn't do anything with it (q35 only). take care, Gerd ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v2 2/4] OvmfPkg/PlatformInitLib: Add PlatformGetLowMemoryCB 2023-01-11 15:23 ` Gerd Hoffmann @ 2023-01-12 11:09 ` Laszlo Ersek 2023-01-12 14:03 ` Gerd Hoffmann 0 siblings, 1 reply; 19+ messages in thread From: Laszlo Ersek @ 2023-01-12 11:09 UTC (permalink / raw) To: Gerd Hoffmann Cc: devel, Pawel Polawski, Jiewen Yao, Oliver Steffen, Jordan Justen, Ard Biesheuvel On 1/11/23 16:23, Gerd Hoffmann wrote: > Some test case complained because the 80000000-afffffff range is io > address space (according to /proc/iomem) but not tagged as uncachable > in mtrr registers. Ah, very interesting! I didn't know there was a test case for this. (And now I'm curious, per the new BZ, whether this same test case complained if it saw us go deeper with the low mem amount -- e.g. the same situation arises between 0x7000_0000 and 0x8000_0000.) >>> With gigabyte-alignment being the common case these days it might make >>> sense to place the MMCONFIG area at 0xe0000000 instead ... >> >> I feel really unsafe about complicating this code even further. > > I think it should actually simplify things. All the inconsistencies we > have (as you outlined above) due to the hole punching and edk2 > supporting only a single range for 32bit mmio should go away, and we > will have less address space layout differences between q35 and pc. We've tried 0xE000_0000 in the past, in commit 75136b29541b. But had to revert it in commit eb4d62b0779c, due to 0xE000_0000 tickling a bug in QEMU. The bug tickling was actually reported by you :) See <https://bugzilla.tianocore.org/show_bug.cgi?id=1859>. The current 0xB000_0000 value comes from commit b07de0974b65a, which was a replacement for 75136b29541b (after the revert -- for re-fixing the original issue <https://bugzilla.tianocore.org/show_bug.cgi?id=1814>, which 75136b29541b intended to fix in the first place). > > We'll set LowMemory -> 4G to UC via mtrr (both pc and q35) This is problematic, as LowMemory can have any kind of "resolution" (i.e. an effectively unrestricted count of 1-bits in its binary representation). That's a problem because MtrrLib's algorithm (probably justifiedly) cannot find enough variable MTRRs to cover the boundary precisely -- and will fail. This is why our current logic exists for i440fx, in PlatformQemuUc32BaseInitialization(), rounding up Uc32Base from LowMemory. (Well, if you mean to keep the same logic for both i440fx adn q35, that's OK then.) > > We'll use LowMemory -> 0xFBFFFFFF (pc) or > LowMemory -> 0xdfffffff (q35) as 32bit mmio window. This is precisely the situation (32-bit MMIO aperture below EXBAR) that triggered the QEMU bug described in TianoCore#1859 and commit eb4d62b0779c. I don't know if that QEMU bug is now fixed (and how far in the QEMU release history the breakage goes back). At the time of the edk2 revert commit eb4d62b0779c (2019-JUN-03), QEMU's latest release was v4.0.0 (2019-APR-23). Release v4.1.0 would follow at 2019-AUG-15. > We'll use 0xe0000000 -> 0xeffffffff for mmconfig (q35 only). > > Qemu will add 0xf0000000 -> 0xFBFFFFFF to the PCI bus _CRS so > linux could use it but the firmware wouldn't do anything with > it (q35 only). If QEMU only *added* this range to the _CRS, that would be fine, but the QEMU issue in TianoCore#1859 was that QEMU *moved* the aperture to this range in the _CRS, effectively invalidating all the firmware-assigned BARs (which would now all fall outside of the _CRS). If you can ascertain that this problem is no longer relevant in any QEMU releases that are still in use, then I won't try to block this direction. In that case, it might be sufficient to just "re-play" commit 75136b29541b. (Note however that the MTRR setup was tied to the approach taken, please refer to commits 39b9a5ffe661 and 49edde15230a.) Either way, this has been a brittle area of OVMF platform code, and I'd feel real uncomfortable, providing an explicit ACK. ... Luckily, you wouldn't need an ACK from me :) Laszlo ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v2 2/4] OvmfPkg/PlatformInitLib: Add PlatformGetLowMemoryCB 2023-01-12 11:09 ` Laszlo Ersek @ 2023-01-12 14:03 ` Gerd Hoffmann 2023-01-12 15:44 ` Laszlo Ersek 0 siblings, 1 reply; 19+ messages in thread From: Gerd Hoffmann @ 2023-01-12 14:03 UTC (permalink / raw) To: Laszlo Ersek Cc: devel, Pawel Polawski, Jiewen Yao, Oliver Steffen, Jordan Justen, Ard Biesheuvel Hi, > > I think it should actually simplify things. All the inconsistencies we > > have (as you outlined above) due to the hole punching and edk2 > > supporting only a single range for 32bit mmio should go away, and we > > will have less address space layout differences between q35 and pc. > > We've tried 0xE000_0000 in the past, in commit 75136b29541b. > > But had to revert it in commit eb4d62b0779c, due to 0xE000_0000 tickling > a bug in QEMU. > > The bug tickling was actually reported by you :) See > <https://bugzilla.tianocore.org/show_bug.cgi?id=1859>. Oh. I totally forgot about that. The patch from (I think) 2019 which added _CRS for the range below the MMCONFIG should have fixed that, and with recent qemu everything works fine. I suspect we can't easily detect whenever qemu is broken or not. Hmm. Is more than three years being passed enough to just do it unconditionally and effectively raise the bar for the minimum supported qemu version? > (Well, if you mean to keep the same logic for both i440fx adn q35, > that's OK then.) Yes, it would be Uc32Base. LowMemory and Uc32Base are identical anyway most of the time due to qemu preferring gigabyte pages when possible, you need odd memory sizes like 1.5 or 2.5 GB to see they actually can be different. take care, Gerd ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v2 2/4] OvmfPkg/PlatformInitLib: Add PlatformGetLowMemoryCB 2023-01-12 14:03 ` Gerd Hoffmann @ 2023-01-12 15:44 ` Laszlo Ersek 0 siblings, 0 replies; 19+ messages in thread From: Laszlo Ersek @ 2023-01-12 15:44 UTC (permalink / raw) To: Gerd Hoffmann Cc: devel, Pawel Polawski, Jiewen Yao, Oliver Steffen, Jordan Justen, Ard Biesheuvel On 1/12/23 15:03, Gerd Hoffmann wrote: > Hi, > >>> I think it should actually simplify things. All the inconsistencies we >>> have (as you outlined above) due to the hole punching and edk2 >>> supporting only a single range for 32bit mmio should go away, and we >>> will have less address space layout differences between q35 and pc. >> >> We've tried 0xE000_0000 in the past, in commit 75136b29541b. >> >> But had to revert it in commit eb4d62b0779c, due to 0xE000_0000 tickling >> a bug in QEMU. >> >> The bug tickling was actually reported by you :) See >> <https://bugzilla.tianocore.org/show_bug.cgi?id=1859>. > > Oh. I totally forgot about that. The patch from (I think) 2019 which > added _CRS for the range below the MMCONFIG should have fixed that, and > with recent qemu everything works fine. > > I suspect we can't easily detect whenever qemu is broken or not. Hmm. > > Is more than three years being passed enough to just do it > unconditionally and effectively raise the bar for the minimum > supported qemu version? Well, in the other thread ("[PATCH v2] OvmfPkg/PlatformInitLib: catch QEMU's CPU hotplug reg block regression"), I'm proposing a hard hang for a QEMU bug that's not been fixed in *any* public release yet, and will only be fixed in v8 :) Can you determine the exact QEMU bugfix (commit hash) and the first QEMU release that included it? Maybe even build & test that version? If we determine the minimum functional QEMU version precisely, and it's like v5 or v6, making it the "official minimum" should be fine. > >> (Well, if you mean to keep the same logic for both i440fx adn q35, >> that's OK then.) > > Yes, it would be Uc32Base. > > LowMemory and Uc32Base are identical anyway most of the time due to qemu > preferring gigabyte pages when possible, you need odd memory sizes like > 1.5 or 2.5 GB to see they actually can be different. > Thanks Laszlo ^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH v2 3/4] OvmfPkg/PlatformInitLib: Add PlatformAddHobCB 2023-01-10 8:21 [PATCH v2 0/4] OvmfPkg: check 64bit mmio window for resource conflicts Gerd Hoffmann 2023-01-10 8:21 ` [PATCH v2 1/4] OvmfPkg/PlatformInitLib: Add PlatformScanE820 and GetFirstNonAddressCB Gerd Hoffmann 2023-01-10 8:21 ` [PATCH v2 2/4] OvmfPkg/PlatformInitLib: Add PlatformGetLowMemoryCB Gerd Hoffmann @ 2023-01-10 8:21 ` Gerd Hoffmann 2023-01-10 17:42 ` Laszlo Ersek 2023-01-10 8:21 ` [PATCH v2 4/4] OvmfPkg/PlatformInitLib: Add PlatformReservationConflictCB Gerd Hoffmann 3 siblings, 1 reply; 19+ messages in thread From: Gerd Hoffmann @ 2023-01-10 8:21 UTC (permalink / raw) To: devel Cc: Pawel Polawski, Jiewen Yao, Oliver Steffen, Jordan Justen, László Érsek, Ard Biesheuvel, Gerd Hoffmann Add PlatformAddHobCB() callback function for use with PlatformScanE820(). It adds HOBs for high memory and reservations (low memory is handled elsewhere because there are some special cases to consider). This replaces calls to PlatformScanOrAdd64BitE820Ram() with AddHighHobs = TRUE. Also remove PlatformScanOrAdd64BitE820Ram() which is not used any more. Signed-off-by: Gerd Hoffmann <kraxel@redhat.com> --- OvmfPkg/Library/PlatformInitLib/MemDetect.c | 174 ++++---------------- 1 file changed, 36 insertions(+), 138 deletions(-) diff --git a/OvmfPkg/Library/PlatformInitLib/MemDetect.c b/OvmfPkg/Library/PlatformInitLib/MemDetect.c index 63329c4e796a..83a219581a1b 100644 --- a/OvmfPkg/Library/PlatformInitLib/MemDetect.c +++ b/OvmfPkg/Library/PlatformInitLib/MemDetect.c @@ -112,143 +112,6 @@ PlatformQemuUc32BaseInitialization ( } } -/** - Iterate over the RAM entries in QEMU's fw_cfg E820 RAM map that start outside - of the 32-bit address range. - - Find the highest exclusive >=4GB RAM address, or produce memory resource - descriptor HOBs for RAM entries that start at or above 4GB. - - @param[out] MaxAddress If MaxAddress is NULL, then PlatformScanOrAdd64BitE820Ram() - produces memory resource descriptor HOBs for RAM - entries that start at or above 4GB. - - Otherwise, MaxAddress holds the highest exclusive - >=4GB RAM address on output. If QEMU's fw_cfg E820 - RAM map contains no RAM entry that starts outside of - the 32-bit address range, then MaxAddress is exactly - 4GB on output. - - @retval EFI_SUCCESS The fw_cfg E820 RAM map was found and processed. - - @retval EFI_PROTOCOL_ERROR The RAM map was found, but its size wasn't a - whole multiple of sizeof(EFI_E820_ENTRY64). No - RAM entry was processed. - - @return Error codes from QemuFwCfgFindFile(). No RAM - entry was processed. -**/ -STATIC -EFI_STATUS -PlatformScanOrAdd64BitE820Ram ( - IN BOOLEAN AddHighHob, - OUT UINT64 *LowMemory OPTIONAL, - OUT UINT64 *MaxAddress OPTIONAL - ) -{ - EFI_STATUS Status; - FIRMWARE_CONFIG_ITEM FwCfgItem; - UINTN FwCfgSize; - EFI_E820_ENTRY64 E820Entry; - UINTN Processed; - - Status = QemuFwCfgFindFile ("etc/e820", &FwCfgItem, &FwCfgSize); - if (EFI_ERROR (Status)) { - return Status; - } - - if (FwCfgSize % sizeof E820Entry != 0) { - return EFI_PROTOCOL_ERROR; - } - - if (LowMemory != NULL) { - *LowMemory = 0; - } - - if (MaxAddress != NULL) { - *MaxAddress = BASE_4GB; - } - - QemuFwCfgSelectItem (FwCfgItem); - for (Processed = 0; Processed < FwCfgSize; Processed += sizeof E820Entry) { - QemuFwCfgReadBytes (sizeof E820Entry, &E820Entry); - DEBUG (( - DEBUG_VERBOSE, - "%a: Base=0x%Lx Length=0x%Lx Type=%u\n", - __FUNCTION__, - E820Entry.BaseAddr, - E820Entry.Length, - E820Entry.Type - )); - if (E820Entry.Type == EfiAcpiAddressRangeMemory) { - if (AddHighHob && (E820Entry.BaseAddr >= BASE_4GB)) { - UINT64 Base; - UINT64 End; - - // - // Round up the start address, and round down the end address. - // - Base = ALIGN_VALUE (E820Entry.BaseAddr, (UINT64)EFI_PAGE_SIZE); - End = (E820Entry.BaseAddr + E820Entry.Length) & - ~(UINT64)EFI_PAGE_MASK; - if (Base < End) { - PlatformAddMemoryRangeHob (Base, End); - DEBUG (( - DEBUG_VERBOSE, - "%a: PlatformAddMemoryRangeHob [0x%Lx, 0x%Lx)\n", - __FUNCTION__, - Base, - End - )); - } - } - - if (MaxAddress || LowMemory) { - UINT64 Candidate; - - Candidate = E820Entry.BaseAddr + E820Entry.Length; - if (MaxAddress && (Candidate > *MaxAddress)) { - *MaxAddress = Candidate; - DEBUG (( - DEBUG_VERBOSE, - "%a: MaxAddress=0x%Lx\n", - __FUNCTION__, - *MaxAddress - )); - } - - if (LowMemory && (Candidate > *LowMemory) && (Candidate < BASE_4GB)) { - *LowMemory = Candidate; - DEBUG (( - DEBUG_VERBOSE, - "%a: LowMemory=0x%Lx\n", - __FUNCTION__, - *LowMemory - )); - } - } - } else if (E820Entry.Type == EfiAcpiAddressRangeReserved) { - if (AddHighHob) { - DEBUG (( - DEBUG_INFO, - "%a: Reserved: Base=0x%Lx Length=0x%Lx\n", - __FUNCTION__, - E820Entry.BaseAddr, - E820Entry.Length - )); - BuildResourceDescriptorHob ( - EFI_RESOURCE_MEMORY_RESERVED, - 0, - E820Entry.BaseAddr, - E820Entry.Length - ); - } - } - } - - return EFI_SUCCESS; -} - typedef VOID (*E820_SCAN_CALLBACK) ( EFI_E820_ENTRY64 *E820Entry, EFI_HOB_PLATFORM_INFO *PlatformInfoHob @@ -304,6 +167,41 @@ PlatformGetLowMemoryCB ( } } +/** + Create HOBs for reservations and RAM (except low memory). +**/ +VOID +PlatformAddHobCB ( + IN EFI_E820_ENTRY64 *E820Entry, + IN OUT EFI_HOB_PLATFORM_INFO *PlatformInfoHob + ) +{ + UINT64 Base = E820Entry->BaseAddr; + UINT64 End = E820Entry->BaseAddr + E820Entry->Length; + + switch (E820Entry->Type) { + case EfiAcpiAddressRangeMemory: + // + // Round up the start address, and round down the end address. + // + Base = ALIGN_VALUE (Base, (UINT64)EFI_PAGE_SIZE); + End = End & ~(UINT64)EFI_PAGE_MASK; + if ((Base >= BASE_4GB) && (Base < End)) { + DEBUG ((DEBUG_INFO, "%a: HighMemory [0x%Lx, 0x%Lx]\n", __FUNCTION__, Base, End)); + PlatformAddMemoryRangeHob (Base, End); + } + + break; + case EfiAcpiAddressRangeReserved: + BuildResourceDescriptorHob (EFI_RESOURCE_MEMORY_RESERVED, 0, Base, End); + DEBUG ((DEBUG_INFO, "%a: Reserved [0x%Lx, 0x%Lx]\n", __FUNCTION__, Base, End)); + break; + default: + DEBUG ((DEBUG_WARN, "%a: Type %d [0x%Lx, 0x%Lx] (NOT HANDLED)\n", __FUNCTION__, E820Entry->Type, Base, End)); + break; + } +} + /** Iterate over the RAM entries in QEMU's fw_cfg E820 RAM map, call the passed callback for each entry. @@ -1048,7 +946,7 @@ PlatformQemuInitializeRam ( // entries. Otherwise, create a single memory HOB with the flat >=4GB // memory size read from the CMOS. // - Status = PlatformScanOrAdd64BitE820Ram (TRUE, NULL, NULL); + Status = PlatformScanE820 (PlatformAddHobCB, PlatformInfoHob); if (EFI_ERROR (Status)) { UpperMemorySize = PlatformGetSystemMemorySizeAbove4gb (); if (UpperMemorySize != 0) { -- 2.39.0 ^ permalink raw reply related [flat|nested] 19+ messages in thread
* Re: [PATCH v2 3/4] OvmfPkg/PlatformInitLib: Add PlatformAddHobCB 2023-01-10 8:21 ` [PATCH v2 3/4] OvmfPkg/PlatformInitLib: Add PlatformAddHobCB Gerd Hoffmann @ 2023-01-10 17:42 ` Laszlo Ersek 2023-01-11 8:06 ` Gerd Hoffmann 0 siblings, 1 reply; 19+ messages in thread From: Laszlo Ersek @ 2023-01-10 17:42 UTC (permalink / raw) To: Gerd Hoffmann, devel Cc: Pawel Polawski, Jiewen Yao, Oliver Steffen, Jordan Justen, Ard Biesheuvel On 1/10/23 09:21, Gerd Hoffmann wrote: > Add PlatformAddHobCB() callback function for use with > PlatformScanE820(). It adds HOBs for high memory and reservations (low > memory is handled elsewhere because there are some special cases to > consider). This replaces calls to PlatformScanOrAdd64BitE820Ram() with > AddHighHobs = TRUE. > > Also remove PlatformScanOrAdd64BitE820Ram() which is not used any more. > > Signed-off-by: Gerd Hoffmann <kraxel@redhat.com> > --- > OvmfPkg/Library/PlatformInitLib/MemDetect.c | 174 ++++---------------- > 1 file changed, 36 insertions(+), 138 deletions(-) > > diff --git a/OvmfPkg/Library/PlatformInitLib/MemDetect.c b/OvmfPkg/Library/PlatformInitLib/MemDetect.c > index 63329c4e796a..83a219581a1b 100644 > --- a/OvmfPkg/Library/PlatformInitLib/MemDetect.c > +++ b/OvmfPkg/Library/PlatformInitLib/MemDetect.c > @@ -112,143 +112,6 @@ PlatformQemuUc32BaseInitialization ( > } > } > > -/** > - Iterate over the RAM entries in QEMU's fw_cfg E820 RAM map that start outside > - of the 32-bit address range. > - > - Find the highest exclusive >=4GB RAM address, or produce memory resource > - descriptor HOBs for RAM entries that start at or above 4GB. > - > - @param[out] MaxAddress If MaxAddress is NULL, then PlatformScanOrAdd64BitE820Ram() > - produces memory resource descriptor HOBs for RAM > - entries that start at or above 4GB. > - > - Otherwise, MaxAddress holds the highest exclusive > - >=4GB RAM address on output. If QEMU's fw_cfg E820 > - RAM map contains no RAM entry that starts outside of > - the 32-bit address range, then MaxAddress is exactly > - 4GB on output. > - > - @retval EFI_SUCCESS The fw_cfg E820 RAM map was found and processed. > - > - @retval EFI_PROTOCOL_ERROR The RAM map was found, but its size wasn't a > - whole multiple of sizeof(EFI_E820_ENTRY64). No > - RAM entry was processed. > - > - @return Error codes from QemuFwCfgFindFile(). No RAM > - entry was processed. > -**/ > -STATIC > -EFI_STATUS > -PlatformScanOrAdd64BitE820Ram ( > - IN BOOLEAN AddHighHob, > - OUT UINT64 *LowMemory OPTIONAL, > - OUT UINT64 *MaxAddress OPTIONAL > - ) > -{ > - EFI_STATUS Status; > - FIRMWARE_CONFIG_ITEM FwCfgItem; > - UINTN FwCfgSize; > - EFI_E820_ENTRY64 E820Entry; > - UINTN Processed; > - > - Status = QemuFwCfgFindFile ("etc/e820", &FwCfgItem, &FwCfgSize); > - if (EFI_ERROR (Status)) { > - return Status; > - } > - > - if (FwCfgSize % sizeof E820Entry != 0) { > - return EFI_PROTOCOL_ERROR; > - } > - > - if (LowMemory != NULL) { > - *LowMemory = 0; > - } > - > - if (MaxAddress != NULL) { > - *MaxAddress = BASE_4GB; > - } > - > - QemuFwCfgSelectItem (FwCfgItem); > - for (Processed = 0; Processed < FwCfgSize; Processed += sizeof E820Entry) { > - QemuFwCfgReadBytes (sizeof E820Entry, &E820Entry); > - DEBUG (( > - DEBUG_VERBOSE, > - "%a: Base=0x%Lx Length=0x%Lx Type=%u\n", > - __FUNCTION__, > - E820Entry.BaseAddr, > - E820Entry.Length, > - E820Entry.Type > - )); > - if (E820Entry.Type == EfiAcpiAddressRangeMemory) { > - if (AddHighHob && (E820Entry.BaseAddr >= BASE_4GB)) { > - UINT64 Base; > - UINT64 End; > - > - // > - // Round up the start address, and round down the end address. > - // > - Base = ALIGN_VALUE (E820Entry.BaseAddr, (UINT64)EFI_PAGE_SIZE); > - End = (E820Entry.BaseAddr + E820Entry.Length) & > - ~(UINT64)EFI_PAGE_MASK; > - if (Base < End) { > - PlatformAddMemoryRangeHob (Base, End); > - DEBUG (( > - DEBUG_VERBOSE, > - "%a: PlatformAddMemoryRangeHob [0x%Lx, 0x%Lx)\n", > - __FUNCTION__, > - Base, > - End > - )); > - } > - } > - > - if (MaxAddress || LowMemory) { > - UINT64 Candidate; > - > - Candidate = E820Entry.BaseAddr + E820Entry.Length; > - if (MaxAddress && (Candidate > *MaxAddress)) { > - *MaxAddress = Candidate; > - DEBUG (( > - DEBUG_VERBOSE, > - "%a: MaxAddress=0x%Lx\n", > - __FUNCTION__, > - *MaxAddress > - )); > - } > - > - if (LowMemory && (Candidate > *LowMemory) && (Candidate < BASE_4GB)) { > - *LowMemory = Candidate; > - DEBUG (( > - DEBUG_VERBOSE, > - "%a: LowMemory=0x%Lx\n", > - __FUNCTION__, > - *LowMemory > - )); > - } > - } > - } else if (E820Entry.Type == EfiAcpiAddressRangeReserved) { > - if (AddHighHob) { > - DEBUG (( > - DEBUG_INFO, > - "%a: Reserved: Base=0x%Lx Length=0x%Lx\n", > - __FUNCTION__, > - E820Entry.BaseAddr, > - E820Entry.Length > - )); > - BuildResourceDescriptorHob ( > - EFI_RESOURCE_MEMORY_RESERVED, > - 0, > - E820Entry.BaseAddr, > - E820Entry.Length > - ); > - } > - } > - } > - > - return EFI_SUCCESS; > -} > - > typedef VOID (*E820_SCAN_CALLBACK) ( > EFI_E820_ENTRY64 *E820Entry, > EFI_HOB_PLATFORM_INFO *PlatformInfoHob > @@ -304,6 +167,41 @@ PlatformGetLowMemoryCB ( > } > } > > +/** > + Create HOBs for reservations and RAM (except low memory). > +**/ > +VOID > +PlatformAddHobCB ( > + IN EFI_E820_ENTRY64 *E820Entry, > + IN OUT EFI_HOB_PLATFORM_INFO *PlatformInfoHob > + ) > +{ > + UINT64 Base = E820Entry->BaseAddr; > + UINT64 End = E820Entry->BaseAddr + E820Entry->Length; (1) To my understanding, the edk2 coding style forbids initialization of variables with automatic storage duration ("non-static locals"). > + > + switch (E820Entry->Type) { > + case EfiAcpiAddressRangeMemory: (Side comment: I'm sure you've run this through Uncrustify -- so that's a coding style change then. What I remember is that "switch" and "case" were supposed to start in the same column.) > + // > + // Round up the start address, and round down the end address. > + // > + Base = ALIGN_VALUE (Base, (UINT64)EFI_PAGE_SIZE); > + End = End & ~(UINT64)EFI_PAGE_MASK; > + if ((Base >= BASE_4GB) && (Base < End)) { (2) This is not faithful conversion. The original code first compares the base against 4GB, then rounds it up; this variant reverses the order of those steps. I don't think if it will ever matter, but this is a refactoring, so let's stick with the original logic (not hard to do). > + DEBUG ((DEBUG_INFO, "%a: HighMemory [0x%Lx, 0x%Lx]\n", __FUNCTION__, Base, End)); (3) I've not noticed before, but I'm noticing now: before this series, the DEBUG levels (or more precisely, "debug masks") for the messages emitted by PlatformScanOrAdd64BitE820Ram() were inconsistent. Most of them were DEBUG_VERBOSE (per original intent), but then commit bf65d7ee8842 ("OvmfPkg/PlatformInitLib: pass through reservations from qemu", 2022-12-23) introduced a new branch with DEBUG_INFO. From the perspective of this series, that's a preexistent inconsistency. Is that worth fixing up at first, separately? (Changing it to DEBUG_VERBOSE.) (4) Also relating to logging. The current patch set seems to move all DEBUG masks here to DEBUG_INFO. The uniformity is welcome, but I'm unsure if DEBUG_INFO is justified. Writes to the QEMU debug console are slow; are we sure we want these logs emitted in a defult build of OVMF? (5) Still about logging. Before this series, the PlatformScanOrAdd64BitE820Ram() function would log each E820 entry before investigating them. (And, based on the investigation, further messages may be logged.) With the whole series applied however, as far as I can tell, we'll never get a complete dump of the E820 map, because PlatformScanE820() doesn't log entries at all, and the callbacks only log entries that prove "interesting" for them. Is this intentional? I think it may make debugging harder. I didn't notice it under patch#1, but I think we should add generic (unconditional) logging there. (6) *Yet more* logging-related observations. The original log message uses a bracket "[" on the left hand side of the logged intervals, and a parenthesis ")" on the RHS, to express that the RHS limit is exclusive: "%a: PlatformAddMemoryRangeHob [0x%Lx, 0x%Lx)\n", This detail is lost in this patch (in all three DEBUG messages); both sides use brackets. (7) Sorry, I'm getting tired and my observations are starting to fall apart. Anyway -- I think all the actual callback functions should be STATIC. (8) Furthermore, *perhaps* we should put E820 in their names somewhere (I don't insist at all), instead of the "Platform" prefix -- these functions are not public PlatformInitLib APIs. > + PlatformAddMemoryRangeHob (Base, End); > + } > + > + break; (9) Empty line intentional? > + case EfiAcpiAddressRangeReserved: > + BuildResourceDescriptorHob (EFI_RESOURCE_MEMORY_RESERVED, 0, Base, End); > + DEBUG ((DEBUG_INFO, "%a: Reserved [0x%Lx, 0x%Lx]\n", __FUNCTION__, Base, End)); > + break; > + default: > + DEBUG ((DEBUG_WARN, "%a: Type %d [0x%Lx, 0x%Lx] (NOT HANDLED)\n", __FUNCTION__, E820Entry->Type, Base, End)); (10) I meant to ask earlier -- what is now the maximum line length? I notice, in ".pytool/Plugin/UncrustifyCheck/uncrustify.cfg": > # Code width / line splitting > #code_width =120 # TODO: This causes non-deterministic behaviour in some cases when code wraps > ls_code_width =false Does that mean that 120 is considered a soft limit? (I used to ask for 80 chars under OvmfPkg, but there's no need to stick with that anymore.) (11) "E820Entry->Type" is an enumeration type; per UEFI 2.10, 2.3.1 Data Types, the UEFI build environment is supposed to make the compiler pick INT32 or UINT32. (This is from Mantis ticket 913.) Now, as long as QEMU sticks with the small set of enumeration constants we define in "OvmfPkg/Include/IndustryStandard/E820.h", it's all fine, and we can indeed print "E820Entry->Type" with both %d and %u, interchangeably. I used "%u" in the original logging because I find the printing of unexpected values as positive integers rather than negative ones more tolerable. I don't mind %d as long as we're conscious of it. Back to the patch: On 1/10/23 09:21, Gerd Hoffmann wrote: > + break; > + } > +} > + > /** > Iterate over the RAM entries in QEMU's fw_cfg E820 RAM map, call the > passed callback for each entry. > @@ -1048,7 +946,7 @@ PlatformQemuInitializeRam ( > // entries. Otherwise, create a single memory HOB with the flat >=4GB > // memory size read from the CMOS. > // > - Status = PlatformScanOrAdd64BitE820Ram (TRUE, NULL, NULL); > + Status = PlatformScanE820 (PlatformAddHobCB, PlatformInfoHob); > if (EFI_ERROR (Status)) { > UpperMemorySize = PlatformGetSystemMemorySizeAbove4gb (); > if (UpperMemorySize != 0) { Looks OK. Thanks, Laszlo ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v2 3/4] OvmfPkg/PlatformInitLib: Add PlatformAddHobCB 2023-01-10 17:42 ` Laszlo Ersek @ 2023-01-11 8:06 ` Gerd Hoffmann 2023-01-11 14:08 ` Laszlo Ersek 0 siblings, 1 reply; 19+ messages in thread From: Gerd Hoffmann @ 2023-01-11 8:06 UTC (permalink / raw) To: Laszlo Ersek Cc: devel, Pawel Polawski, Jiewen Yao, Oliver Steffen, Jordan Justen, Ard Biesheuvel > > + DEBUG ((DEBUG_INFO, "%a: HighMemory [0x%Lx, 0x%Lx]\n", __FUNCTION__, Base, End)); > > (3) I've not noticed before, but I'm noticing now: before this series, > the DEBUG levels (or more precisely, "debug masks") for the messages > emitted by PlatformScanOrAdd64BitE820Ram() were inconsistent. Most of > them were DEBUG_VERBOSE (per original intent), but then commit > bf65d7ee8842 ("OvmfPkg/PlatformInitLib: pass through reservations from > qemu", 2022-12-23) introduced a new branch with DEBUG_INFO. From the > perspective of this series, that's a preexistent inconsistency. > > Is that worth fixing up at first, separately? (Changing it to > DEBUG_VERBOSE.) > > (4) Also relating to logging. The current patch set seems to move all > DEBUG masks here to DEBUG_INFO. The uniformity is welcome, but I'm > unsure if DEBUG_INFO is justified. Writes to the QEMU debug console are > slow; are we sure we want these logs emitted in a defult build of OVMF? > > (5) Still about logging. Before this series, the > PlatformScanOrAdd64BitE820Ram() function would log each E820 entry > before investigating them. (And, based on the investigation, further > messages may be logged.) With the whole series applied however, as far > as I can tell, we'll never get a complete dump of the E820 map, because > PlatformScanE820() doesn't log entries at all, and the callbacks only > log entries that prove "interesting" for them. > > Is this intentional? I think it may make debugging harder. I didn't > notice it under patch#1, but I think we should add generic > (unconditional) logging there. Yes, all intentional. I've dropped all logging from PlatformScanE820, we run that multiple times and logging the e820 map there would make it show up multiple times in the logs. Instead I'm logging at the places where the code actually does something with the values (set LowMemory, add HOB, ...), which should give us good insights into the code flow in the logs. I've turned them on by default because the logging should be less verbose than it used to be and also because I've found myself flipping these from VERBOSE to INFO frequently when debugging something. > (6) *Yet more* logging-related observations. The original log message > uses a bracket "[" on the left hand side of the logged intervals, and a > parenthesis ")" on the RHS, to express that the RHS limit is exclusive: > > "%a: PlatformAddMemoryRangeHob [0x%Lx, 0x%Lx)\n", > > This detail is lost in this patch (in all three DEBUG messages); both > sides use brackets. Oh, I wasn't aware of that. It looked like a typo to me so I "fixed" it along the way. I think I prefer to stick with the (inclusive) brackets and print "End - 1" then so it actually is inclusive. > (7) Sorry, I'm getting tired and my observations are starting to fall > apart. Anyway -- I think all the actual callback functions should be > STATIC. Yes. PlatformScanE820() is static too. Isn't there a gcc warning which complains about non-static functions without prototype in some header? Seems this is not turned on for edk2, I'm somehow used to gcc throwing warnings on that. > (8) Furthermore, *perhaps* we should put E820 in their names somewhere > (I don't insist at all), instead of the "Platform" prefix -- these > functions are not public PlatformInitLib APIs. There is a simple reason for the naming: I love 'grep ^Platform' on edk2 log files ;) > > + DEBUG ((DEBUG_WARN, "%a: Type %d [0x%Lx, 0x%Lx] (NOT HANDLED)\n", __FUNCTION__, E820Entry->Type, Base, End)); > > (10) I meant to ask earlier -- what is now the maximum line length? > > I notice, in ".pytool/Plugin/UncrustifyCheck/uncrustify.cfg": > > > # Code width / line splitting > > #code_width =120 # TODO: This causes non-deterministic behaviour in some cases when code wraps > > ls_code_width =false > > Does that mean that 120 is considered a soft limit? (I used to ask for > 80 chars under OvmfPkg, but there's no need to stick with that anymore.) Oh, 120. I already wondered why uncrustify didn't wrap that one, I didn't expect the limit being higher than 100 which seems to be the new standard in many projects. take care, Gerd ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v2 3/4] OvmfPkg/PlatformInitLib: Add PlatformAddHobCB 2023-01-11 8:06 ` Gerd Hoffmann @ 2023-01-11 14:08 ` Laszlo Ersek 0 siblings, 0 replies; 19+ messages in thread From: Laszlo Ersek @ 2023-01-11 14:08 UTC (permalink / raw) To: Gerd Hoffmann Cc: devel, Pawel Polawski, Jiewen Yao, Oliver Steffen, Jordan Justen, Ard Biesheuvel On 1/11/23 09:06, Gerd Hoffmann wrote: >>> + DEBUG ((DEBUG_INFO, "%a: HighMemory [0x%Lx, 0x%Lx]\n", __FUNCTION__, Base, End)); >> >> (3) I've not noticed before, but I'm noticing now: before this series, >> the DEBUG levels (or more precisely, "debug masks") for the messages >> emitted by PlatformScanOrAdd64BitE820Ram() were inconsistent. Most of >> them were DEBUG_VERBOSE (per original intent), but then commit >> bf65d7ee8842 ("OvmfPkg/PlatformInitLib: pass through reservations from >> qemu", 2022-12-23) introduced a new branch with DEBUG_INFO. From the >> perspective of this series, that's a preexistent inconsistency. >> >> Is that worth fixing up at first, separately? (Changing it to >> DEBUG_VERBOSE.) >> >> (4) Also relating to logging. The current patch set seems to move all >> DEBUG masks here to DEBUG_INFO. The uniformity is welcome, but I'm >> unsure if DEBUG_INFO is justified. Writes to the QEMU debug console are >> slow; are we sure we want these logs emitted in a defult build of OVMF? >> >> (5) Still about logging. Before this series, the >> PlatformScanOrAdd64BitE820Ram() function would log each E820 entry >> before investigating them. (And, based on the investigation, further >> messages may be logged.) With the whole series applied however, as far >> as I can tell, we'll never get a complete dump of the E820 map, because >> PlatformScanE820() doesn't log entries at all, and the callbacks only >> log entries that prove "interesting" for them. >> >> Is this intentional? I think it may make debugging harder. I didn't >> notice it under patch#1, but I think we should add generic >> (unconditional) logging there. > > Yes, all intentional. > > I've dropped all logging from PlatformScanE820, we run that multiple > times and logging the e820 map there would make it show up multiple > times in the logs. Instead I'm logging at the places where the code > actually does something with the values (set LowMemory, add HOB, ...), > which should give us good insights into the code flow in the logs. > > I've turned them on by default because the logging should be less > verbose than it used to be and also because I've found myself flipping > these from VERBOSE to INFO frequently when debugging something. I think the last part should be replaced by you just building with DEBUG_VERBOSE :), carrying perhaps a few patches for the DSC files for re-disabling DEBUG_VERBOSE for a number of unjustifiably chatty modules (I can give you a list); *regardless*, I think the above is all good, just please mention it somewhere in the commit messages. (Best would be to change the debug levels after the conversion, separately, but I don't want to get on your nerves.) > >> (6) *Yet more* logging-related observations. The original log message >> uses a bracket "[" on the left hand side of the logged intervals, and a >> parenthesis ")" on the RHS, to express that the RHS limit is exclusive: >> >> "%a: PlatformAddMemoryRangeHob [0x%Lx, 0x%Lx)\n", >> >> This detail is lost in this patch (in all three DEBUG messages); both >> sides use brackets. > > Oh, I wasn't aware of that. It looked like a typo to me so I "fixed" it > along the way. I think I prefer to stick with the (inclusive) brackets > and print "End - 1" then so it actually is inclusive. Works for me -- as long as you won't be searching the firmware logs for the *exclusive end* hex strings :) :) :) (Now of course you can satisfy both goals, as long as you don't print (End-1) with "0x%Lx", but print (End) with "0x%Lx - 1"! In fact, you may have meant the latter already, above.) > >> (7) Sorry, I'm getting tired and my observations are starting to fall >> apart. Anyway -- I think all the actual callback functions should be >> STATIC. > > Yes. PlatformScanE820() is static too. Isn't there a gcc warning which > complains about non-static functions without prototype in some header? > Seems this is not turned on for edk2, I'm somehow used to gcc throwing > warnings on that. Haha, good catch -- it's intentionally not turned on in edk2. Namely, some version of MSVC (maybe even bleeding edge ones, I don't know) screw up source-level debugging for such functions that are marked STATIC, as far as I remember. This is why, in core packages, you'll see an inexplicably low number of STATIC functions. So the MSVC shortcoming (if I can call it that) actively conflicts with the nice gcc warning you mention. The gcc warning is a no-brainer for when you can actually enable it. > >> (8) Furthermore, *perhaps* we should put E820 in their names somewhere >> (I don't insist at all), instead of the "Platform" prefix -- these >> functions are not public PlatformInitLib APIs. > > There is a simple reason for the naming: > I love 'grep ^Platform' on edk2 log files ;) That sounds convincing enough, thanks. Log analysis is important, we should support it! > >>> + DEBUG ((DEBUG_WARN, "%a: Type %d [0x%Lx, 0x%Lx] (NOT HANDLED)\n", __FUNCTION__, E820Entry->Type, Base, End)); >> >> (10) I meant to ask earlier -- what is now the maximum line length? >> >> I notice, in ".pytool/Plugin/UncrustifyCheck/uncrustify.cfg": >> >>> # Code width / line splitting >>> #code_width =120 # TODO: This causes non-deterministic behaviour in some cases when code wraps >>> ls_code_width =false >> >> Does that mean that 120 is considered a soft limit? (I used to ask for >> 80 chars under OvmfPkg, but there's no need to stick with that anymore.) > > Oh, 120. I already wondered why uncrustify didn't wrap that one, I > didn't expect the limit being higher than 100 which seems to be the new > standard in many projects. > > take care, > Gerd > Thanks! Laszlo ^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH v2 4/4] OvmfPkg/PlatformInitLib: Add PlatformReservationConflictCB 2023-01-10 8:21 [PATCH v2 0/4] OvmfPkg: check 64bit mmio window for resource conflicts Gerd Hoffmann ` (2 preceding siblings ...) 2023-01-10 8:21 ` [PATCH v2 3/4] OvmfPkg/PlatformInitLib: Add PlatformAddHobCB Gerd Hoffmann @ 2023-01-10 8:21 ` Gerd Hoffmann 2023-01-10 17:55 ` Laszlo Ersek 3 siblings, 1 reply; 19+ messages in thread From: Gerd Hoffmann @ 2023-01-10 8:21 UTC (permalink / raw) To: devel Cc: Pawel Polawski, Jiewen Yao, Oliver Steffen, Jordan Justen, László Érsek, Ard Biesheuvel, Gerd Hoffmann Add PlatformReservationConflictCB() callback function for use with PlatformScanE820(). It checks whenever the 64bit PCI MMIO window overlaps with a reservation from qemu. If so move down the MMIO window to resolve the conflict. This happens on (virtal) AMD machines with 1TB address space, because the AMD IOMMU uses an address window just below 1GB. Bugzilla: https://bugzilla.tianocore.org/show_bug.cgi?id=4251 Signed-off-by: Gerd Hoffmann <kraxel@redhat.com> --- OvmfPkg/Library/PlatformInitLib/MemDetect.c | 41 +++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/OvmfPkg/Library/PlatformInitLib/MemDetect.c b/OvmfPkg/Library/PlatformInitLib/MemDetect.c index 83a219581a1b..f12d48cad755 100644 --- a/OvmfPkg/Library/PlatformInitLib/MemDetect.c +++ b/OvmfPkg/Library/PlatformInitLib/MemDetect.c @@ -202,6 +202,46 @@ PlatformAddHobCB ( } } +/** + Check whenever the 64bit PCI MMIO window overlaps with a reservation + from qemu. If so move down the MMIO window to resolve the conflict. + + This happens on (virtal) AMD machines with 1TB address space, + because the AMD IOMMU uses an address window just below 1GB. +**/ +VOID +PlatformReservationConflictCB ( + IN EFI_E820_ENTRY64 *E820Entry, + IN OUT EFI_HOB_PLATFORM_INFO *PlatformInfoHob + ) +{ + UINT64 IntersectionBase = MAX ( + E820Entry->BaseAddr, + PlatformInfoHob->PcdPciMmio64Base + ); + UINT64 IntersectionEnd = MIN ( + E820Entry->BaseAddr + E820Entry->Length, + PlatformInfoHob->PcdPciMmio64Base + + PlatformInfoHob->PcdPciMmio64Size + ); + UINT64 NewBase; + + if (IntersectionBase >= IntersectionEnd) { + return; // no overlap + } + + NewBase = (PlatformInfoHob->PcdPciMmio64Base - + PlatformInfoHob->PcdPciMmio64Size); + DEBUG (( + DEBUG_INFO, + "%a: move mmio: 0x%Lx => %Lx\n", + __FUNCTION__, + PlatformInfoHob->PcdPciMmio64Base, + NewBase + )); + PlatformInfoHob->PcdPciMmio64Base = NewBase; +} + /** Iterate over the RAM entries in QEMU's fw_cfg E820 RAM map, call the passed callback for each entry. @@ -638,6 +678,7 @@ PlatformDynamicMmioWindow ( DEBUG ((DEBUG_INFO, "%a: MMIO Space 0x%Lx (%Ld GB)\n", __func__, MmioSpace, RShiftU64 (MmioSpace, 30))); PlatformInfoHob->PcdPciMmio64Size = MmioSpace; PlatformInfoHob->PcdPciMmio64Base = AddrSpace - MmioSpace; + PlatformScanE820 (PlatformReservationConflictCB, PlatformInfoHob); } else { DEBUG ((DEBUG_INFO, "%a: using classic mmio window\n", __func__)); } -- 2.39.0 ^ permalink raw reply related [flat|nested] 19+ messages in thread
* Re: [PATCH v2 4/4] OvmfPkg/PlatformInitLib: Add PlatformReservationConflictCB 2023-01-10 8:21 ` [PATCH v2 4/4] OvmfPkg/PlatformInitLib: Add PlatformReservationConflictCB Gerd Hoffmann @ 2023-01-10 17:55 ` Laszlo Ersek 2023-01-11 8:26 ` Gerd Hoffmann 0 siblings, 1 reply; 19+ messages in thread From: Laszlo Ersek @ 2023-01-10 17:55 UTC (permalink / raw) To: Gerd Hoffmann, devel Cc: Pawel Polawski, Jiewen Yao, Oliver Steffen, Jordan Justen, Ard Biesheuvel On 1/10/23 09:21, Gerd Hoffmann wrote: > Add PlatformReservationConflictCB() callback function for use with > PlatformScanE820(). It checks whenever the 64bit PCI MMIO window > overlaps with a reservation from qemu. If so move down the MMIO window > to resolve the conflict. > > This happens on (virtal) AMD machines with 1TB address space, (1) s/virtal/virtual/ > because the AMD IOMMU uses an address window just below 1GB. (2) s/1GB/1TB/? > > Bugzilla: https://bugzilla.tianocore.org/show_bug.cgi?id=4251 > Signed-off-by: Gerd Hoffmann <kraxel@redhat.com> > --- > OvmfPkg/Library/PlatformInitLib/MemDetect.c | 41 +++++++++++++++++++++ > 1 file changed, 41 insertions(+) > > diff --git a/OvmfPkg/Library/PlatformInitLib/MemDetect.c b/OvmfPkg/Library/PlatformInitLib/MemDetect.c > index 83a219581a1b..f12d48cad755 100644 > --- a/OvmfPkg/Library/PlatformInitLib/MemDetect.c > +++ b/OvmfPkg/Library/PlatformInitLib/MemDetect.c > @@ -202,6 +202,46 @@ PlatformAddHobCB ( > } > } > > +/** > + Check whenever the 64bit PCI MMIO window overlaps with a reservation > + from qemu. If so move down the MMIO window to resolve the conflict. > + > + This happens on (virtal) AMD machines with 1TB address space, > + because the AMD IOMMU uses an address window just below 1GB. (3) Same two typos, I think, as in the commit message. > +**/ > +VOID > +PlatformReservationConflictCB ( (4) should be STATIC etc, maybe use E820 in the name rathern than Platform, etc... up to you. > + IN EFI_E820_ENTRY64 *E820Entry, > + IN OUT EFI_HOB_PLATFORM_INFO *PlatformInfoHob > + ) > +{ > + UINT64 IntersectionBase = MAX ( > + E820Entry->BaseAddr, > + PlatformInfoHob->PcdPciMmio64Base > + ); > + UINT64 IntersectionEnd = MIN ( > + E820Entry->BaseAddr + E820Entry->Length, > + PlatformInfoHob->PcdPciMmio64Base + > + PlatformInfoHob->PcdPciMmio64Size > + ); (5) Locals should not be initialized (per my last memories of the edk2 coding style). > + UINT64 NewBase; > + > + if (IntersectionBase >= IntersectionEnd) { > + return; // no overlap > + } > + > + NewBase = (PlatformInfoHob->PcdPciMmio64Base - > + PlatformInfoHob->PcdPciMmio64Size); (6) This appears a typo; we'll want NewBase + PcdPciMmio64Size == E820Entry->BaseAddr where the LHS stands for the exclusive end of the moved MMIO aperture, with unchanged size, and the RHS stands for the inclusive base of the (unmovable) reservation. The above formula ensures that the intersection be empty, without changing sizes, or moving the reservation. Then, reordering the formula for an assignment, we get NewBase = E820Entry->BaseAddr - PcdPciMmio64Size; as an assignment. So, yes, a typo. > + DEBUG (( > + DEBUG_INFO, > + "%a: move mmio: 0x%Lx => %Lx\n", (7) pls consider DEBUG_VERBOSE, like before (8) usage of the 0x prefix in the debug message is inconsistent, we should prefix the NewBase output with it, too > + __FUNCTION__, > + PlatformInfoHob->PcdPciMmio64Base, > + NewBase > + )); > + PlatformInfoHob->PcdPciMmio64Base = NewBase; > +} (9) Do we need any other checks or maybe assertions that we're only conflicting with a reserved area, and/or that the subtraction for NewBase does not underflow? I don't think we can "armor" this very well, I'm just pondering if there are any egregious misunderstandings between QEMU and the firmware that we might want to catch here. If not, that's OK of course. > + > /** > Iterate over the RAM entries in QEMU's fw_cfg E820 RAM map, call the > passed callback for each entry. > @@ -638,6 +678,7 @@ PlatformDynamicMmioWindow ( > DEBUG ((DEBUG_INFO, "%a: MMIO Space 0x%Lx (%Ld GB)\n", __func__, MmioSpace, RShiftU64 (MmioSpace, 30))); > PlatformInfoHob->PcdPciMmio64Size = MmioSpace; > PlatformInfoHob->PcdPciMmio64Base = AddrSpace - MmioSpace; > + PlatformScanE820 (PlatformReservationConflictCB, PlatformInfoHob); > } else { > DEBUG ((DEBUG_INFO, "%a: using classic mmio window\n", __func__)); > } Looks fine. Thanks, Laszlo ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v2 4/4] OvmfPkg/PlatformInitLib: Add PlatformReservationConflictCB 2023-01-10 17:55 ` Laszlo Ersek @ 2023-01-11 8:26 ` Gerd Hoffmann 2023-01-12 10:36 ` Laszlo Ersek 0 siblings, 1 reply; 19+ messages in thread From: Gerd Hoffmann @ 2023-01-11 8:26 UTC (permalink / raw) To: Laszlo Ersek Cc: devel, Pawel Polawski, Jiewen Yao, Oliver Steffen, Jordan Justen, Ard Biesheuvel Hi, > > +/** > > + Check whenever the 64bit PCI MMIO window overlaps with a reservation > > + from qemu. If so move down the MMIO window to resolve the conflict. > > + > > + This happens on (virtal) AMD machines with 1TB address space, > > + because the AMD IOMMU uses an address window just below 1GB. > > (3) Same two typos, I think, as in the commit message. Duplicated by the power of cut + paste. > > + NewBase = (PlatformInfoHob->PcdPciMmio64Base - > > + PlatformInfoHob->PcdPciMmio64Size); > > (6) This appears a typo; we'll want > > NewBase + PcdPciMmio64Size == E820Entry->BaseAddr But then NewBase is not aligned. The assignment above moves it down while maintaining the existing alignment. > (9) Do we need any other checks or maybe assertions that we're only > conflicting with a reserved area, and/or that the subtraction for > NewBase does not underflow? > > I don't think we can "armor" this very well, I'm just pondering if there > are any egregious misunderstandings between QEMU and the firmware that > we might want to catch here. If not, that's OK of course. Yes, it's hard to design something which can handle all reservations qemu might do in the future correctly. And, yes, the code above works because we know the qemu reservation is smaller than the mmio window, so moving down to the next naturally aligned address actually solves the conflict. take care, Gerd ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v2 4/4] OvmfPkg/PlatformInitLib: Add PlatformReservationConflictCB 2023-01-11 8:26 ` Gerd Hoffmann @ 2023-01-12 10:36 ` Laszlo Ersek 0 siblings, 0 replies; 19+ messages in thread From: Laszlo Ersek @ 2023-01-12 10:36 UTC (permalink / raw) To: Gerd Hoffmann Cc: devel, Pawel Polawski, Jiewen Yao, Oliver Steffen, Jordan Justen, Ard Biesheuvel On 1/11/23 09:26, Gerd Hoffmann wrote: > Hi, > >>> +/** >>> + Check whenever the 64bit PCI MMIO window overlaps with a reservation >>> + from qemu. If so move down the MMIO window to resolve the conflict. >>> + >>> + This happens on (virtal) AMD machines with 1TB address space, >>> + because the AMD IOMMU uses an address window just below 1GB. >> >> (3) Same two typos, I think, as in the commit message. > > Duplicated by the power of cut + paste. > >>> + NewBase = (PlatformInfoHob->PcdPciMmio64Base - >>> + PlatformInfoHob->PcdPciMmio64Size); >> >> (6) This appears a typo; we'll want >> >> NewBase + PcdPciMmio64Size == E820Entry->BaseAddr > > But then NewBase is not aligned. The assignment above moves it down > while maintaining the existing alignment. Ah, good point. I totally missed the idea here. The starting predicate is, apparently, that the base is aligned by size ("naturally aligned"), so by subtracting size from the aperture, we get a new aperture that conforms to both properties below: - still naturally aligned (original predicate preserved), - empty intersection with the original aperture (because the new aperture will end where the old one just started). Now, here's one thought: just because the new (sunken) aperture does not intersect the pre-move aperture, is it guaranteed to also steer clear of the E820 Entry either? I don't think that's certain. If the E820 Entry overlaps the bottom of the original aperture, but goes "deeper" than that, then it will overlap the top of the sunken aperture too. So I think we might want to do a two step process here, in case the original aperture overlaps the E820 Entry: - push down the aperture (same size) so its exclusive end equal the inclusive start of the E820 Entry - align *down* (truncate) the base of the aperture, while keeping its size unchanged. Something like: NewBase = E820Entry->BaseAddr - PcdPciMmio64Size; ASSERT (PcdPciMmio64Size != 0); ASSERT ((PcdPciMmio64Size & (PcdPciMmio64Size - 1)) == 0); NewBase = NewBase & ~(PcdPciMmio64Size - 1); > >> (9) Do we need any other checks or maybe assertions that we're only >> conflicting with a reserved area, and/or that the subtraction for >> NewBase does not underflow? >> >> I don't think we can "armor" this very well, I'm just pondering if there >> are any egregious misunderstandings between QEMU and the firmware that >> we might want to catch here. If not, that's OK of course. > > Yes, it's hard to design something which can handle all reservations > qemu might do in the future correctly. And, yes, the code above works > because we know the qemu reservation is smaller than the mmio window, so > moving down to the next naturally aligned address actually solves the > conflict. Not only smaller, but also *not encompassing* the lower boundary of the MMIO window. Anyway, up to you -- if you want to stick with the logic shown in this patch, I'm OK, but then please add some comments, or maybe even some ASSERTs. Thanks! Laszlo ^ permalink raw reply [flat|nested] 19+ messages in thread
end of thread, other threads:[~2023-01-12 15:45 UTC | newest] Thread overview: 19+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2023-01-10 8:21 [PATCH v2 0/4] OvmfPkg: check 64bit mmio window for resource conflicts Gerd Hoffmann 2023-01-10 8:21 ` [PATCH v2 1/4] OvmfPkg/PlatformInitLib: Add PlatformScanE820 and GetFirstNonAddressCB Gerd Hoffmann 2023-01-10 15:41 ` Laszlo Ersek 2023-01-10 8:21 ` [PATCH v2 2/4] OvmfPkg/PlatformInitLib: Add PlatformGetLowMemoryCB Gerd Hoffmann 2023-01-10 16:53 ` Laszlo Ersek 2023-01-11 7:29 ` Gerd Hoffmann 2023-01-11 13:56 ` Laszlo Ersek 2023-01-11 15:23 ` Gerd Hoffmann 2023-01-12 11:09 ` Laszlo Ersek 2023-01-12 14:03 ` Gerd Hoffmann 2023-01-12 15:44 ` Laszlo Ersek 2023-01-10 8:21 ` [PATCH v2 3/4] OvmfPkg/PlatformInitLib: Add PlatformAddHobCB Gerd Hoffmann 2023-01-10 17:42 ` Laszlo Ersek 2023-01-11 8:06 ` Gerd Hoffmann 2023-01-11 14:08 ` Laszlo Ersek 2023-01-10 8:21 ` [PATCH v2 4/4] OvmfPkg/PlatformInitLib: Add PlatformReservationConflictCB Gerd Hoffmann 2023-01-10 17:55 ` Laszlo Ersek 2023-01-11 8:26 ` Gerd Hoffmann 2023-01-12 10:36 ` Laszlo Ersek
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox