【x86架构】MTRR

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.

**/
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;
}

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

**/
VOID
MtrrLibInitializeMtrrMask (
  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的方式:

  • 4
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
可以使用以下命令查看Linux CPU的厂商信息: 1. 使用lscpu命令查看: lscpu命令可以显示CPU的详细信息,包括厂商信息、架构、核心数等等。 命令:lscpu 示例输出: ``` Architecture: x86_64 CPU op-mode(s): 32-bit, 64-bit Byte Order: Little Endian CPU(s): 1 On-line CPU(s) list: 0 Thread(s) per core: 1 Core(s) per socket: 1 Socket(s): 1 Vendor ID: GenuineIntel CPU family: 6 Model: 158 Model name: Intel(R) Core(TM) i5-7500T CPU @ 2.70GHz Stepping: 9 CPU MHz: 2700.000 BogoMIPS: 5400.00 Virtualization: VT-x L1d cache: 32K L1i cache: 32K L2 cache: 256K L3 cache: 6144K ``` 可以看到,Vendor ID显示的是CPU厂商信息,这里是GenuineIntel,表示是英特尔的CPU。 2. 使用cat /proc/cpuinfo命令查看: cat /proc/cpuinfo命令可以显示CPU的详细信息,包括厂商信息、型号、频率等等。 命令:cat /proc/cpuinfo 示例输出: ``` processor : 0 vendor_id : GenuineIntel cpu family : 6 model : 158 model name : Intel(R) Core(TM) i5-7500T CPU @ 2.70GHz stepping : 9 cpu MHz : 2700.000 cache size : 6144 KB physical id : 0 siblings : 1 core id : 0 cpu cores : 1 apicid : 0 initial apicid : 0 fpu : yes fpu_exception : yes cpuid level : 22 wp : yes flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf tsc_known_freq pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch cpuid_fault epb invpcid_single pti ssbd ibrs ibpb stibp tpr_shadow vnmi flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 hle avx2 smep bmi2 erms invpcid rtm mpx rdseed adx smap clflushopt intel_pt xsaveopt xsavec xgetbv1 xsaves ibrs_enhanced tpr_adjust md_clear flush_l1d bugs : cpu_meltdown spectre_v1 spectre_v2 spec_store_bypass l1tf mds swapgs bogomips : 5400.00 clflush size : 64 cache_alignment : 64 address sizes : 39 bits physical, 48 bits virtual power management: ``` 可以看到,vendor_id显示的是CPU厂商信息,这里也是GenuineIntel,表示是英特尔的CPU。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值