博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
x86架构——MTRR
阅读量:491 次
发布时间:2019-03-06

本文共 3350 字,大约阅读时间需要 11 分钟。

MTRR是什么

MTRR的全称是Memory Type Range Registers。

它们是一组组的MSR寄存器对(目前最多有96组),用来指定特定的系统内存段的类型。

这里说的类型,是指内存的CACHE类型,有如下的值:

对应的C代码中的实现:

//// Memory cache types//typedef enum {  CacheUncacheable    = 0,  CacheWriteCombining = 1,  CacheWriteThrough   = 4,  CacheWriteProtected = 5,  CacheWriteBack      = 6,  CacheInvalid        = 7} MTRR_MEMORY_CACHE_TYPE;

通过MTRR,系统可以优化RAM/ROM/MMIO等不同类型的内存的访问速度。

下面是一个设置MTRR的例子:

 

如何判断MTRR的支持情况

因为MTRR是MSR寄存器,因此它是跟CPU有关的,并不是所有的CPU都支持。

不过现在的x86平台CPU都支持该功能,事实上从P6型号开始就只是MTRR了。

要判断是否支持MTRR,需要使用CPUID命令,对应的是CPUID.EAX=01H,返回的结果在EDX:

当确定是否支持之后,还需要确定MTRR的支持情况,这对应于一个MSR寄存器(IA32_MTRRCAP):

它是一个只读的寄存器,具体的BIT位说明如下:

SMRR:确定是否支持System-Management Range Register;

FIX:确定是否支持Fixed Range MTRR(两种类型的MTRR,可变和固定);

WC:Write Combining的CACHE类型是否支持;

VCNT:可变MTRR的支持个数。

这里没有说固定MTRR的个数,是否意味着它的个数是固定的?(目前来看是固定的11个,后面再介绍)

对应判断MTRR是否支持的代码如下:

/**  Checks if MTRR is supported.  @retval TRUE  MTRR is supported.  @retval FALSE MTRR is not supported.**/BOOLEANEFIAPIIsMtrrSupported (  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;}

 

MTRR的设置

硬件复位之后,CPU会Disable掉所有的MTRR,此时所有的系统内存都是UNCACHEABLE的。

需要BIOS来完成MTRR,且在多处理器的系统中,各个处理器的设置必须是一致的。

MTRR的设置对应到3类寄存器,首先是一个全局的MSR(IA32_MTRR_DEF_TYPE):

E:MTRR的开关;

FE:固定MTRR的开关;

Type:系统内存的默认CACHE类型,对于没有被MTRR覆盖到的内存段,就使用默认的CACHE类型;

第二类是固定MTRR,因为它们对应的内存段是固定的,所以也比较好理解,下面是所有的固定MTRR:

每一个寄存器又将内存段分为8个小段,可以分别设置。

第三类是可变MTRR,它通过一组MSR寄存器来设置一段内存的属性,这组MSR如下所示:

第一个寄存器设定了内存的基址和类型,而第二个寄存器设置了它的大小以及使能与否。

这里还有一个概念,就是MAXPHYADDR,它表示的是最大支持的系统内存。

虽然我们说现在x86是64位的系统,但是CPU真正只是的系统内存却不是2^64,而是2^MAXPHYADDR,而这个MAXPHYADDR的大小不同系统有不同的值。关于这个值,可以通过CPUID.80000008H获取,下面是具体的代码:

/**  Initializes the valid bits mask and valid address mask for MTRRs.  This function initializes the valid bits mask and valid address mask for MTRRs.  @param[out]  MtrrValidBitsMask     The mask for the valid bit of the MTRR  @param[out]  MtrrValidAddressMask  The valid address mask for the MTRR**/VOIDMtrrLibInitializeMtrrMask (  OUT UINT64 *MtrrValidBitsMask,  OUT UINT64 *MtrrValidAddressMask  ){  UINT32                          MaxExtendedFunction;  CPUID_VIR_PHY_ADDRESS_SIZE_EAX  VirPhyAddressSize;  AsmCpuid (CPUID_EXTENDED_FUNCTION, &MaxExtendedFunction, NULL, NULL, NULL);  if (MaxExtendedFunction >= CPUID_VIR_PHY_ADDRESS_SIZE) {    AsmCpuid (CPUID_VIR_PHY_ADDRESS_SIZE, &VirPhyAddressSize.Uint32, NULL, NULL, NULL);  } else {    VirPhyAddressSize.Bits.PhysicalAddressBits = 36;  }  *MtrrValidBitsMask = LShiftU64 (1, VirPhyAddressSize.Bits.PhysicalAddressBits) - 1;  *MtrrValidAddressMask = *MtrrValidBitsMask & 0xfffffffffffff000ULL;}

当MAXPHYADDR确定之后,基址的设置没有什么特别好介绍的,不过大小需要说明下。

一个可变MTRR可以存放的内存大小通过如下的方式计算:

Address_Within_Range AND PhysMask = PhysBase AND PhysMask

其中Address_Within_Range就是可用的内存地址。

对应到代码如下:

Mask = ((~(Length - 1)) & MtrrValidAddressMask) | BIT11;

其中的MtrrValidAddressMask是可用的地址的掩码(即MAXPHYADDR个1,前面的MtrrLibInitializeMtrrMask()有计算方式)。

 

MTRR查看

Linux下查看MTRR的方式:

 

转载地址:http://qgadz.baihongyu.com/

你可能感兴趣的文章