Rizwan Qureshi (rizwan.qureshi@intel.com) just uploaded a new patch set to gerrit, which you can find at https://review.coreboot.org/16509
-gerrit
commit 5f36423d2a43a2846e3a7622fc025e0924c4dc36 Author: Rizwan Qureshi rizwan.qureshi@intel.com Date: Tue Sep 6 22:56:59 2016 +0530
arch/x86: Configure additional MTRRs to cover specified size.
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 adress aligment boundary.
To simplify this, implement an algorithm to utilize additonal MTRRs to cover the entire size specified.
TEST: Build and Boot Kunimitsu.
Change-Id: Ie2e88b596f43692169c7d4440b18498a72fcba11 Signed-off-by: Rizwan Qureshi rizwan.qureshi@intel.com --- src/arch/x86/postcar_loader.c | 81 ++++++++++++++++++++++++++++++++----------- 1 file changed, 60 insertions(+), 21 deletions(-)
diff --git a/src/arch/x86/postcar_loader.c b/src/arch/x86/postcar_loader.c index b5d8db0..7500d14 100644 --- a/src/arch/x86/postcar_loader.c +++ b/src/arch/x86/postcar_loader.c @@ -59,29 +59,68 @@ 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; + size_t align, tsize, total_span = size;
- 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 aligment. + * 1. Get alignment and remaining size to cache, initially it is + * equal to provided size. + * 2. If aligment is bigger than remaining size then, + * Configure a MTRR for this base and size. + * Adjust remaing size and base address. + * jump to step 1. + * 3. Else If remaining size is bigger then, + * Determine the biggest 2^N part of it and, + * Configure a MTRR for this base and size. + * Adjust remaing size and base address. + * jump to step 1. + * 4. Stop when we run out of MTRRs or the whole span has been + * accounted for in MTRRs. + */ + while (total_span){ + + if (pcf->num_var_mttrs >= pcf->max_var_mttrs) { + printk(BIOS_ERR, "No more variable MTRRs: %d\n", + pcf->max_var_mttrs); + return; + } + + align = addr & (addr ^ (addr - 1)); + if (align >= total_span){ + printk(BIOS_DEBUG, "MTRR Range : Start: %lx End: %zx (Size %zx)\n", + addr, addr + total_span, total_span); + + stack_push(pcf, pcf->upper_mask); + stack_push(pcf, ~(total_span - 1) | MTRR_PHYS_MASK_VALID); + stack_push(pcf, 0); + stack_push(pcf, addr | type); + pcf->num_var_mttrs++; + + total_span -= total_span; + addr += total_span; + }else if (align < total_span){ + /* get the largest "power of 2 chunk" in size */ + tsize = total_span - 1; + tsize |= tsize >> 1; + tsize |= tsize >> 2; + tsize |= tsize >> 4; + tsize |= tsize >> 8; + tsize |= tsize >> 16; + tsize = ((tsize + 1) >> 1); + printk(BIOS_DEBUG, "MTRR Range : Start: %lx End: %lx (Size %zx)\n", + addr, addr + tsize, tsize); + + stack_push(pcf, pcf->upper_mask); + stack_push(pcf, ~(tsize - 1) | MTRR_PHYS_MASK_VALID); + stack_push(pcf, 0); + stack_push(pcf, addr | type); + pcf->num_var_mttrs++; + + total_span -= tsize; + addr += tsize; + } } - - /* 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)