diff options
author | Rizwan Qureshi <rizwan.qureshi@intel.com> | 2016-09-07 20:18:17 +0530 |
---|---|---|
committer | Martin Roth <martinroth@google.com> | 2016-09-12 19:52:27 +0200 |
commit | e8c2e839736917e25ddbfc6a84daf1b7ad035c74 (patch) | |
tree | 1e24a36a9154018e53628fdef88ede8f1c56d6f7 /src | |
parent | 8453c4f2fba7ae95ed14137a14575226b24218af (diff) |
arch/x86: Utilize additional MTRRs in postcar_frame_add_mtrr
In the current implementation of postcar_frame_add_mtrr,
if provided size is bigger than the base address alignment,
the alignment is considered as size and covered by the MTRRs
ignoring the specified size.
In this case the callee has to make sure that the provided
size should be smaller or equal to the base address alignment
boundary.
To simplify this, utilize additonal MTRRs to cover the entire
size specified. We reuse the code from cpu/x86/mtrr/mtrr.c.
Change-Id: Ie2e88b596f43692169c7d4440b18498a72fcba11
Signed-off-by: Rizwan Qureshi <rizwan.qureshi@intel.com>
Reviewed-on: https://review.coreboot.org/16509
Tested-by: build bot (Jenkins)
Reviewed-by: Aaron Durbin <adurbin@chromium.org>
Diffstat (limited to 'src')
-rw-r--r-- | src/arch/x86/postcar_loader.c | 59 |
1 files changed, 37 insertions, 22 deletions
diff --git a/src/arch/x86/postcar_loader.c b/src/arch/x86/postcar_loader.c index b5d8db0e1b..d9719ff729 100644 --- a/src/arch/x86/postcar_loader.c +++ b/src/arch/x86/postcar_loader.c @@ -59,29 +59,44 @@ int postcar_frame_init(struct postcar_frame *pcf, size_t stack_size) void postcar_frame_add_mtrr(struct postcar_frame *pcf, uintptr_t addr, size_t size, int type) { - size_t align; - - if (pcf->num_var_mttrs >= pcf->max_var_mttrs) { - printk(BIOS_ERR, "No more variable MTRRs: %d\n", - pcf->max_var_mttrs); - return; - } - - /* Determine address alignment by lowest bit set in address. */ - align = addr & (addr ^ (addr - 1)); - - if (align < size) { - printk(BIOS_ERR, "Address (%lx) alignment (%zx) < size (%zx)\n", - addr, align, size); - size = align; + /* + * Utilize additional MTRRs if the specified size is greater than the + * base address alignment. + */ + while (size != 0) { + uint32_t addr_lsb; + uint32_t size_msb; + uint32_t mtrr_size; + + if (pcf->num_var_mttrs >= pcf->max_var_mttrs) { + printk(BIOS_ERR, "No more variable MTRRs: %d\n", + pcf->max_var_mttrs); + return; + } + + addr_lsb = fls(addr); + size_msb = fms(size); + + /* All MTRR entries need to have their base aligned to the mask + * size. The maximum size is calculated by a function of the + * min base bit set and maximum size bit set. */ + if (addr_lsb > size_msb) + mtrr_size = 1 << size_msb; + else + mtrr_size = 1 << addr_lsb; + + printk(BIOS_DEBUG, "MTRR Range: Start=%lx End=%lx (Size %x)\n", + addr, addr + mtrr_size, mtrr_size); + + stack_push(pcf, pcf->upper_mask); + stack_push(pcf, ~(mtrr_size - 1) | MTRR_PHYS_MASK_VALID); + stack_push(pcf, 0); + stack_push(pcf, addr | type); + pcf->num_var_mttrs++; + + size -= mtrr_size; + addr += mtrr_size; } - - /* Push MTRR mask then base -- upper 32-bits then lower 32-bits. */ - stack_push(pcf, pcf->upper_mask); - stack_push(pcf, ~(size - 1) | MTRR_PHYS_MASK_VALID); - stack_push(pcf, 0); - stack_push(pcf, addr | type); - pcf->num_var_mttrs++; } void *postcar_commit_mtrrs(struct postcar_frame *pcf) |