cpu/x86/mtrr: Exclude ranges above 4G if temporary MTRRs exhausted

mtrr_use_temp_range() is used to temporarily cache the area(s) of RAM
to which the SPI flash is mapped, in order to speed up reading the
payload out of flash in preparation for execution. On systems with more
than 32GiB of RAM, there are not enough MTRRs available to map the
"permanent" regions below 4GiB, these temporary regions below 4GiB, and
any RAM above 4GiB due to fragmentation in the various ranges, as well
as limitations on the area covered by a single MTRR due to how they
are stored in the CPU registers.

As a workaround, if the number of MTRRs needed for the temporary map
exceeds the maximum available for  the system, retry calc_var-mtrrs()
with `above4gb` set to false.

TEST=build/boot starlabs/starbook_mtl with > 32GB RAM, verify temporary
MTRRs are able to be assigned via cbmem console log, and no boot delays
in payload loading/decompression due to the SPI flash not being cached.

Change-Id: Ia9f9a1537e7e0c2f7ce21067eceb1549d0f9ea5b
Signed-off-by: Matt DeVillier <matt.devillier@gmail.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/86941
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Shuo Liu <shuo.liu@intel.com>
This commit is contained in:
Matt DeVillier 2025-03-20 13:54:32 -05:00
commit 5dd0181f7b

View file

@ -831,7 +831,7 @@ void mtrr_use_temp_range(uintptr_t begin, size_t size, int type)
const struct memranges *orig;
struct var_mtrr_solution sol;
struct memranges addr_space;
const bool above4gb = true; /* Cover above 4GiB by default. */
bool above4gb = true; /* Cover above 4GiB by default. */
int address_bits;
int num_mtrrs_used;
static struct temp_range {
@ -888,6 +888,12 @@ void mtrr_use_temp_range(uintptr_t begin, size_t size, int type)
sol.mtrr_default_type =
calc_var_mtrrs(&addr_space, above4gb, address_bits, &num_mtrrs_used);
/* If we ran out of MTRRs, retry excluding ranges above 4GiB */
if (above4gb && num_mtrrs_used > total_mtrrs) {
printk(BIOS_WARNING, "MTRR: Ran out of variable MTRRs; retrying excluding ranges above 4GiB.\n");
above4gb = false;
sol.mtrr_default_type = calc_var_mtrrs(&addr_space, above4gb, address_bits, &num_mtrrs_used);
}
if (num_mtrrs_used <= total_mtrrs)
prepare_var_mtrrs(&addr_space, sol.mtrr_default_type, above4gb, address_bits, &sol);
else