summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRizwan Qureshi <rizwan.qureshi@intel.com>2016-09-07 20:18:17 +0530
committerMartin Roth <martinroth@google.com>2016-09-12 19:52:27 +0200
commite8c2e839736917e25ddbfc6a84daf1b7ad035c74 (patch)
tree1e24a36a9154018e53628fdef88ede8f1c56d6f7
parent8453c4f2fba7ae95ed14137a14575226b24218af (diff)
downloadcoreboot-e8c2e839736917e25ddbfc6a84daf1b7ad035c74.tar.xz
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>
-rw-r--r--src/arch/x86/postcar_loader.c59
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)