Topics

Question about the OVMF and MTRRs?

Andrew Fish
 

I noticed for my version of QEMU that MTRR registers are not supported. Is that expected? Or is it something if you get wrong it does not break in QEMU?

Due to no MTRR support the CPU Protocol SetMemoeryAttributes() call is falling [1] and non of the GCD ranges have EFI_MEMORY_UC Attribute. 

I’m not sure but I think the no MTRR case should attempt to set the attributes via page tables via:

return AssignMemoryPageAttributes (NULL, BaseAddress, Length, MemoryAttributes, NULL);

Vs 

return EFI_UNSUPPORTED;


Thanks,

Andrew Fish

Laszlo Ersek
 

Hi Andrew,

On 07/03/20 19:22, Andrew Fish via groups.io wrote:
I noticed for my version of QEMU that MTRR registers are not supported. Is that expected? Or is it something if you get wrong it does not break in QEMU?

Due to no MTRR support the CPU Protocol SetMemoeryAttributes() call is falling [1] and non of the GCD ranges have EFI_MEMORY_UC Attribute.

I’m not sure but I think the no MTRR case should attempt to set the attributes via page tables via:

return AssignMemoryPageAttributes (NULL, BaseAddress, Length, MemoryAttributes, NULL);

Vs

return EFI_UNSUPPORTED;

[1] https://github.com/tianocore/edk2/blob/master/UefiCpuPkg/CpuDxe/CpuDxe.c#L429
sorry, reaching this email only now.

I wouldn't really expect IsMtrrSupported() to return FALSE.

BOOLEAN
EFIAPI
IsMtrrSupported (
VOID
)
{
CPUID_VERSION_INFO_EDX Edx;
MSR_IA32_MTRRCAP_REGISTER MtrrCap;

//
// Check CPUID(1).EDX[12] for MTRR capability
//
AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, &Edx.Uint32);
if (Edx.Bits.MTRR == 0) {
return FALSE;
}

//
// Check number of variable MTRRs and fixed MTRRs existence.
// If number of variable MTRRs is zero, or fixed MTRRs do not
// exist, return false.
//
MtrrCap.Uint64 = AsmReadMsr64 (MSR_IA32_MTRRCAP);
if ((MtrrCap.Bits.VCNT == 0) || (MtrrCap.Bits.FIX == 0)) {
return FALSE;
}
return TRUE;
}


In QEMU, the rdmsr is handled in "target/i386/misc_helper.c", function
helper_rdmsr():

case MSR_MTRRcap:
if (env->features[FEAT_1_EDX] & CPUID_MTRR) {
val = MSR_MTRRcap_VCNT | MSR_MTRRcap_FIXRANGE_SUPPORT |
MSR_MTRRcap_WC_SUPPORTED;
} else {
/* XXX: exception? */
val = 0;
}
break;

thus the second "FALSE" branch in IsMtrrSupported() can never be
reached. (Either the first "FALSE" branch is taken, or the "TRUE" branch
is taken.) MSR_MTRRcap_VCNT is 8.

Regarding the first "FALSE" branch, whether that is taken depends on the
QEMU CPU model (or the QEMU command line). Check "target/i386/cpu.c" for
"CPUID_MTRR".

Unfortunately I can't think of an easy way to list the CPU models that
do *not* have CPUID_MTRR. What is your CPU model?

Thanks
Laszlo