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>
This commit is contained in:
parent
8453c4f2fb
commit
e8c2e83973
|
@ -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;
|
||||
/*
|
||||
* 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;
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* 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)
|
||||
|
|
Loading…
Reference in New Issue