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 e8e5b8fbe400fe3eca15f153979ba03c84e6110d 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 address alignment boundary.
To simplify this, utilize additonal MTRRs to cover the entire size specified. We reuse the code code from cpu/x86/mtrr/mtrr.c.
Move fls() amd fms() definitions to mtrr.h.
TEST=Build and boot Kunimitsu.
Change-Id: Ie2e88b596f43692169c7d4440b18498a72fcba11 Signed-off-by: Rizwan Qureshi rizwan.qureshi@intel.com --- src/arch/x86/postcar_loader.c | 59 +++++++++++++++++++++++++++---------------- src/cpu/x86/mtrr/mtrr.c | 24 ------------------ src/include/cpu/x86/mtrr.h | 27 ++++++++++++++++++++ 3 files changed, 64 insertions(+), 46 deletions(-)
diff --git a/src/arch/x86/postcar_loader.c b/src/arch/x86/postcar_loader.c index b5d8db0..d9719ff 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) diff --git a/src/cpu/x86/mtrr/mtrr.c b/src/cpu/x86/mtrr/mtrr.c index 8bdc511..8033e79 100644 --- a/src/cpu/x86/mtrr/mtrr.c +++ b/src/cpu/x86/mtrr/mtrr.c @@ -92,30 +92,6 @@ static void enable_var_mtrr(unsigned char deftype) wrmsr(MTRR_DEF_TYPE_MSR, msr); }
-/* fms: find most significant bit set, stolen from Linux Kernel Source. */ -static inline unsigned int fms(unsigned int x) -{ - int r; - - __asm__("bsrl %1,%0\n\t" - "jnz 1f\n\t" - "movl $0,%0\n" - "1:" : "=r" (r) : "g" (x)); - return r; -} - -/* fls: find least significant bit set */ -static inline unsigned int fls(unsigned int x) -{ - int r; - - __asm__("bsfl %1,%0\n\t" - "jnz 1f\n\t" - "movl $32,%0\n" - "1:" : "=r" (r) : "g" (x)); - return r; -} - #define MTRR_VERBOSE_LEVEL BIOS_NEVER
/* MTRRs are at a 4KiB granularity. Therefore all address calculations can diff --git a/src/include/cpu/x86/mtrr.h b/src/include/cpu/x86/mtrr.h index f32bece..79f9890 100644 --- a/src/include/cpu/x86/mtrr.h +++ b/src/include/cpu/x86/mtrr.h @@ -84,6 +84,33 @@ void set_var_mtrr(unsigned reg, unsigned base, unsigned size, unsigned type); int get_free_var_mtrr(void); #endif
+#if !defined(__ASSEMBLER__) && !defined(__ROMCC__) + +/* fms: find most significant bit set, stolen from Linux Kernel Source. */ +static inline unsigned int fms(unsigned int x) +{ + int r; + + __asm__("bsrl %1,%0\n\t" + "jnz 1f\n\t" + "movl $0,%0\n" + "1:" : "=r" (r) : "g" (x)); + return r; +} + +/* fls: find least significant bit set */ +static inline unsigned int fls(unsigned int x) +{ + int r; + + __asm__("bsfl %1,%0\n\t" + "jnz 1f\n\t" + "movl $32,%0\n" + "1:" : "=r" (r) : "g" (x)); + return r; +} +#endif + /* Align up to next power of 2, suitable for ROMCC and assembler too. * Range of result 256kB to 128MB is good enough here. */