Skip to content

Commit

Permalink
grub-core/loader/i386/txt/txt.c: Use MAXPHYADDR in MTRR masks
Browse files Browse the repository at this point in the history
Based on Intel TXT MLE Developer Guide revision 017.4 Table 4
the SINIT capabilities bit 8 indicates whether fixed 36bit masks
or MAXPHYADDR masks are to be used in MTRR calculations. Failing
to adhere to it may lead to creation of potentially disjoint WB
cache ranges and violation of CRAM protections - according to the
document.

Signed-off-by: Michał Żygowski <[email protected]>
  • Loading branch information
miczyg1 committed Aug 17, 2024
1 parent 85ccfdc commit dcc430d
Showing 1 changed file with 32 additions and 8 deletions.
40 changes: 32 additions & 8 deletions grub-core/loader/i386/txt/txt.c
Original file line number Diff line number Diff line change
Expand Up @@ -350,19 +350,35 @@ fls (int mask)
return (mask == 0 ? mask : (int)bsrl ((grub_uint32_t)mask) + 1);
}

static grub_uint64_t cpu_phys_addr(void)
{
uint32_t eax, ebx, ecx, edx;
unsigned int phys_bits = 36;
/* Find the physical address size for this CPU. */
cpuid(0x80000000, &eax, &ebx, &ecx, &edx);
if ( eax >= 0x80000008 )
{
cpuid(0x80000008, &eax, &ebx, &ecx, &edx);
phys_bits = (uint8_t)eax;
}

return phys_bits;
}

/*
* set the memory type for specified range (base to base+size)
* to mem_type and everything else to UC
*/
static grub_err_t
set_mtrr_mem_type (const grub_uint8_t *base, grub_uint32_t size,
grub_uint32_t mem_type)
grub_uint32_t mem_type, bool mtrr_mask_36b)
{
grub_uint64_t mtrr_def_type;
grub_uint64_t mtrr_cap;
grub_uint64_t mtrr_mask;
union mtrr_physbase_t mtrr_physbase;
union mtrr_physmask_t mtrr_physmask;
grub_uint32_t vcnt, pages_in_range;
grub_uint32_t vcnt, pages_in_range, sinit_caps;
unsigned long ndx, base_v;
int i = 0, j, num_pages, mtrr_s;

Expand All @@ -376,6 +392,16 @@ set_mtrr_mem_type (const grub_uint8_t *base, grub_uint32_t size,
mtrr_cap = grub_rdmsr (GRUB_MSR_X86_MTRRCAP);
vcnt = (mtrr_cap & GRUB_MSR_X86_VCNT_MASK);

sinit_caps = grub_txt_get_sinit_capabilities ((struct grub_txt_acm_header *)base);
if (!(sinit_caps & GRUB_TXT_CAPS_MAXPHYSADDR_SUPPORT)) {
/* Legacy 36bit mask */
mtrr_mask = SINIT_MTRR_MASK;
} else {
/* Calculate the MTRR mask because MAXPHYADDR is used per SINIT caps */
mtrr_mask = ((1ull << cpu_phys_addr()) - 1) & ~((1ull << 12) - 1);
mtrr_mask = mtrr_mask >> GRUB_PAGE_SHIFT;
}

for ( ndx = 0; ndx < vcnt; ndx++ )
{
mtrr_physmask.raw = grub_rdmsr (GRUB_MSR_X86_MTRR_PHYSMASK (ndx));
Expand Down Expand Up @@ -411,13 +437,12 @@ set_mtrr_mem_type (const grub_uint8_t *base, grub_uint32_t size,
while ( num_pages >= mtrr_s )
{
mtrr_physbase.raw = grub_rdmsr (GRUB_MSR_X86_MTRR_PHYSBASE (ndx));
mtrr_physbase.base = ((unsigned long)base >> GRUB_PAGE_SHIFT) &
SINIT_MTRR_MASK;
mtrr_physbase.base = ((unsigned long)base >> GRUB_PAGE_SHIFT) & mtrr_mask;
mtrr_physbase.type = mem_type;
grub_wrmsr (GRUB_MSR_X86_MTRR_PHYSBASE (ndx), mtrr_physbase.raw);

mtrr_physmask.raw = grub_rdmsr (GRUB_MSR_X86_MTRR_PHYSMASK (ndx));
mtrr_physmask.mask = ~(mtrr_s - 1) & SINIT_MTRR_MASK;
mtrr_physmask.mask = ~(mtrr_s - 1) & mtrr_mask;
mtrr_physmask.v = 1;
grub_wrmsr (GRUB_MSR_X86_MTRR_PHYSMASK (ndx), mtrr_physmask.raw);

Expand All @@ -433,8 +458,7 @@ set_mtrr_mem_type (const grub_uint8_t *base, grub_uint32_t size,
{
/* Set the base of the current MTRR */
mtrr_physbase.raw = grub_rdmsr (GRUB_MSR_X86_MTRR_PHYSBASE (ndx));
mtrr_physbase.base = ((unsigned long)base >> GRUB_PAGE_SHIFT) &
SINIT_MTRR_MASK;
mtrr_physbase.base = ((unsigned long)base >> GRUB_PAGE_SHIFT) & mtrr_mask;
mtrr_physbase.type = mem_type;
grub_wrmsr (GRUB_MSR_X86_MTRR_PHYSBASE (ndx), mtrr_physbase.raw);

Expand All @@ -446,7 +470,7 @@ set_mtrr_mem_type (const grub_uint8_t *base, grub_uint32_t size,
pages_in_range = 1 << (fls (num_pages) - 1);

mtrr_physmask.raw = grub_rdmsr (GRUB_MSR_X86_MTRR_PHYSMASK (ndx));
mtrr_physmask.mask = ~(pages_in_range - 1) & SINIT_MTRR_MASK;
mtrr_physmask.mask = ~(pages_in_range - 1) & mtrr_mask;
mtrr_physmask.v = 1;
grub_wrmsr (GRUB_MSR_X86_MTRR_PHYSMASK (ndx), mtrr_physmask.raw);

Expand Down

0 comments on commit dcc430d

Please sign in to comment.