summaryrefslogtreecommitdiff
path: root/src/arch/x86
diff options
context:
space:
mode:
Diffstat (limited to 'src/arch/x86')
-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)