On 2015-06-23 12:53:49, Laszlo Ersek wrote:
> At the moment we work with a UC default MTRR type, and set three memory
> ranges to WB:
> - [0, 640 KB),
> - [1 MB, LowerMemorySize),
> - [4 GB, 4 GB + UpperMemorySize).
>
> Unfortunately, coverage for the third range can fail with a high
> likelihood. If the alignment of the base (ie. 4 GB) and the alignment of
> the size (UpperMemorySize) differ, then MtrrLib creates a series of
> variable MTRR entries, with power-of-two sized MTRR masks. And, it's
> really easy to run out of variable MTRR entries, dependent on the
> alignment difference.
>
> This is a problem because a Linux guest will loudly reject any high memory
> that is not covered my MTRR.
>
> So, let's follow the inverse pattern (loosely inspired by SeaBIOS):
> - flip the MTRR default type to WB,
> - set [0, 640 KB) to WB -- fixed MTRRs have precedence over the default
> type and variable MTRRs, so we can't avoid this,
> - set [640 KB, 1 MB) to UC -- implemented with fixed MTRRs,
> - set [LowerMemorySize, 4 GB) to UC -- should succeed with variable MTRRs
> more likely than the other scheme (due to less chaotic alignment
> differences).
>
> Effects of this patch can be observed by setting DEBUG_CACHE (0x00200000)
> in PcdDebugPrintErrorLevel.
>
> Cc: Maoming <[email protected]>
> Cc: Huangpeng (Peter) <[email protected]>
> Cc: Wei Liu <[email protected]>
> Contributed-under: TianoCore Contribution Agreement 1.0
> Signed-off-by: Laszlo Ersek <[email protected]>
> Tested-by: Maoming <[email protected]>
> Reviewed-by: Jordan Justen <[email protected]>
> ---
>
> Notes:
> v2:
> - update comments [Jordan]
> - calculate the size of the low 384 KB uncacheable hole as Jordan
> suggested
>
> OvmfPkg/PlatformPei/MemDetect.c | 46 ++++++++++++++++++--
> 1 file changed, 42 insertions(+), 4 deletions(-)
>
> diff --git a/OvmfPkg/PlatformPei/MemDetect.c b/OvmfPkg/PlatformPei/MemDetect.c
> index b74308f..4778a55 100644
> --- a/OvmfPkg/PlatformPei/MemDetect.c
> +++ b/OvmfPkg/PlatformPei/MemDetect.c
> @@ -252,6 +252,8 @@ QemuInitializeRam (
> {
> UINT64 LowerMemorySize;
> UINT64 UpperMemorySize;
> + MTRR_SETTINGS MtrrSettings;
> + EFI_STATUS Status;
>
> DEBUG ((EFI_D_INFO, "%a called\n", __FUNCTION__));
>
> @@ -272,12 +274,48 @@ QemuInitializeRam (
> }
> }
>
> - MtrrSetMemoryAttribute (BASE_1MB, LowerMemorySize - BASE_1MB,
> CacheWriteBack);
> + //
> + // We'd like to keep the following ranges uncached:
> + // - [640 KB, 1 MB)
> + // - [LowerMemorySize, 4 GB)
> + //
> + // Everything else should be WB. Unfortunately, programming the inverse
> (ie.
> + // keeping the default UC, and configuring the complement set of the above
> as
> + // WB) is not reliable in general, because the end of the upper RAM can
> have
> + // practically any alignment, and we may not have enough variable MTRRs to
> + // cover it exactly.
> + //
> + if (IsMtrrSupported ()) {
> + MtrrGetAllMtrrs (&MtrrSettings);
>
> - MtrrSetMemoryAttribute (0, BASE_512KB + BASE_128KB, CacheWriteBack);
> + //
> + // MTRRs disabled, fixed MTRRs disabled, default type is uncached
> + //
> + ASSERT ((MtrrSettings.MtrrDefType & BIT11) == 0);
> + ASSERT ((MtrrSettings.MtrrDefType & BIT10) == 0);
> + ASSERT ((MtrrSettings.MtrrDefType & 0xFF) == 0);
>
> - if (UpperMemorySize != 0) {
> - MtrrSetMemoryAttribute (BASE_4GB, UpperMemorySize, CacheWriteBack);
> + //
> + // flip default type to writeback
> + //
> + SetMem (&MtrrSettings.Fixed, sizeof MtrrSettings.Fixed, 0x06);
> + ZeroMem (&MtrrSettings.Variables, sizeof MtrrSettings.Variables);
> + MtrrSettings.MtrrDefType |= BIT11 | BIT10 | 6;
> + MtrrSetAllMtrrs (&MtrrSettings);
> +
> + //
> + // Set memory from 640KB to 1MB to uncacheable
> + //
Thanks Laszlo. All the patches look good to me now.
If I have a nit pick remaining, it would be the comments I suggested
here. :)
I think maybe 'memory' => 'memory range' seems better. What do you
think?
> + Status = MtrrSetMemoryAttribute (BASE_512KB + BASE_128KB,
> + BASE_1MB - (BASE_512KB + BASE_128KB), CacheUncacheable);
> + ASSERT_EFI_ERROR (Status);
> +
> + //
> + // Set MMIO just below 4GB to uncacheable
> + //
You expressed some doubts about this, and I agree. To throw out
another option, maybe:
//
// Set memory range from the "top of lower RAM" (RAM below 4GB) to
// 4GB as uncacheable
//
Or, maybe:
//
// Set memory range for memory mapped IO below 4GB as uncacheable
//
Or, perhaps you have a better suggestion?
Anyway, I don't think it is critical, so with or without changes,
series Reviewed-by: Jordan Justen <[email protected]>
> + Status = MtrrSetMemoryAttribute (LowerMemorySize,
> + SIZE_4GB - LowerMemorySize, CacheUncacheable);
> + ASSERT_EFI_ERROR (Status);
> }
> }
>
> --
> 1.8.3.1
>
>
> ------------------------------------------------------------------------------
> Monitor 25 network devices or servers for free with OpManager!
> OpManager is web-based network management software that monitors
> network devices and physical & virtual servers, alerts via email & sms
> for fault. Monitor 25 devices for free with no restriction. Download now
> http://ad.doubleclick.net/ddm/clk/292181274;119417398;o
> _______________________________________________
> edk2-devel mailing list
> [email protected]
> https://lists.sourceforge.net/lists/listinfo/edk2-devel
------------------------------------------------------------------------------
Monitor 25 network devices or servers for free with OpManager!
OpManager is web-based network management software that monitors
network devices and physical & virtual servers, alerts via email & sms
for fault. Monitor 25 devices for free with no restriction. Download now
http://ad.doubleclick.net/ddm/clk/292181274;119417398;o
_______________________________________________
edk2-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/edk2-devel