Skip to the content.
X86 Architecture Details
CPU
- Cache(SDM Chap.12)
- CR0中的CD flag可以关闭cache,任何一个cpu关了cache,所有cpu的cache都关了
- Invalidate Cache
- WBINVD指令
- 写回并清除所有cache,期间所有CPU停止工作
- 包括L1,L2,L3缓存
- INVD指令
- 清除但不写回所有cache,期间所有CPU停止工作
- 包括L1,L2,L3缓存
- CLFLUSH/CLFLUSHOPT指令
- Memory Typing
- Strong UC(UC):无缓存,无预取,直接访问system bus,无乱序执行和预测执行,比如MMIO地址
- UC-:32位的产物
- WC(Write Combining):不能缓存,不保证coherency,比如frame buffer
- WT(Write Through):缓存,保证coherency,写直达内存,比如frame buffer
- WB(Write-Back):缓存,保证coherency,写操作到cache中,WC
- WP(Write-Protected):
- Implict Caching
- 由于speculative execution和prefetch,有些没访问的内存也会被cache,如果可能更改一个预测执行的内存地址,软件要做好invalidate
- Expilict Caching
- L1 Data Cache Context Mode
- 在IA32_MISC_ENABLE MSR中可以配置了L1 Cache的两种模式
- Adaptive Mode:当不同CPU的CR3一样且paging mode一致时,可以共享L1 Data Cache
- Shared Mode:完全共享L1 Data Cache
- Self Modifying Code
- 如果写了code segment的内容,对应cacheline会被invalidate
- 如果对应内存的指令已经prefetch或者decode,整个trace cache会被invalidate
- trace cache是Xeon CPU存储decoded instruction(也就是微指令,micro-ops)的地方
- MTRR(Memory Type Range Register)
- 给内存区段配置Memory Type
- hardware reset将所有物理内存设为UC,BIOS需要在启动时设置好MTRR
- MTRR的支持在CPUID中查询,IA32_MTRRCAP MSR给出MTTR的capabilities
- 三种MTRR
- IA32_MTRR_DEF_TYPE MSR表示默认Memeory Type,一般是UC,就是大部分没用的物理地址空间
- Fixed Range MTRR
- IA32_MTRR_FIX64K_00000 MSR表示物理地址0到512K的8个64K range,每8bit表示一个
- IA32_MTRR_FIX16K_80000 MSR表示物理地址512K到640K的8个16K range,每8bit表示一个
- IA32_MTRR_FIX16K_A0000 MSR表示物理地址640到768K的8个16K range,每8bit表示一个
- IA32_MTRR_FIX4K_C0000到IA32_MTRR_FIX4K_F8000 MSR中的每个表示768K到1M中的32K range,每个MSR的每8bit表示32K中的一个4K range
- Variable Range MTRR
- IA32_MTRRCAP MSR中给出支持的Variable Range数量
- 每个range用一对MTRR(IA32_MTRR_PHYSBASEn、IA32_MTRR_PHYSMASKn)表示
- 一个表示起始地址和Memory Type
- 另一个表示Mask
- 当address & mask == range_base_addr & mask时,address在此range中
- 也就是说一个range可能是不连续的多段地址组合起来
- 当有重叠时,按照优先级判定
- Fxied > Variable > Default
- variable range 之间的重叠,如果有一方是UC,则判定为UC;如果一边是WT,一边是WB,则判定为WT;其他情况属于Undefined Behavior
- range必须是2的n次方页,起始地址必须2的n次方对齐
- 多CPU启动时需将BSP的MTRR值告知其他AP,赋相同的值,并打开MTRR
- 同一个大页里边Memory Type需要一致
- TLB(SDM 4.10)
- caching translation information有两种
- TLB:linear addr -> physical addr
- Paging-Structure Cache(PxE):“linear address的前一部分bits”到某一级页表的映射
- PCID(Process Context ID)
- 12bit
- CR4中有个bit控制其使能
- 如果disable,相当于一直为0
- 如果enable,PCID=CR3[11:0]
- 每个TLB都有个PCID的tag,只有符合当前CR3的PCID才会被使用,创建的时候会使用当前CR3[12:0]作为tag
- Global page
- 如果CR4中打开PGE,最后一级PTE(包括大页)的G bit置位表示这是一个global page,这个地址的TLB的tag会被忽略,直接使用
- 细节
- Access bit是1的才会有TLB,创建TLB会把Access bit置1
- TLB会有prefetch,且speculative execution是存在的,也就是说可能会有TLB映射到不是内存的地方
- 大页的TLB也可能是很多小页的形式,清除的时候会被一起清除
- 页表entry如果self referencing,会引起多个TLB的创建:加入四级页表的第一个entry(0号)指向该四级页表,相当于无限循环,每一级PxE(如果虚拟地址的前几位都是0)都会映射到四级页表地址,那TLB(如果虚拟地址的前几位都是0)也会有到四级页表地址的映射
- Invalidate TLB
- INVLPG指令:给出一个虚拟地址
- 清除对应该虚拟地址的当前PCID的TLB
- 清除对应该虚拟地址的global TLB
- 清除所有PxE,无论是否对应该虚拟地址
- INVPCID指令:四种清除模式
- 清除某个PCID的某个地址的TLB
- 清除某个PCID
- 清除所有非global的TLB
- 清除所有TLB,包括global
- 写CR0的PG bit会清除所有TLB,包括global
- 写MTRR
- 写CR3
- 如果关闭PCID,只清除PCID=0的TLB,不清除global
- 如果开启PCID
- 如果CR3的新内容的bit63==1,不做任何清除动作
- 如果CR3的新内容的bit63==0,清除新PCID的所有TLB,不清除global
- 如果新的CR3和之前的CR3有相同的PCID,但是代表新的虚拟地址空间,应该将bit63置0
- 一般bit63==0就是用户空间,bit63==1是内核空间,内核页表变动较少,这可以帮助减少TLB flush
- 写CR4
- 如果改变了PGE bit或者关闭了PCID(PCIDE bit),清除所有TLB,包括global
- 如果改变了PAE bit或者打开了SMEP bit,清除当前PCID的所有TLB
- CPU保证清除指定的TLB,但是可能会同时清除其他(比如global)TLB
- 在一个HT上清除TLB,可能会影响同一个物理CPU的另一个HT
- Page Fault会清理对应PCID和对应地址的TLB,防止再次发生
- TLB shootdown:把地址转换信息的改变转递给别的CPU的过程
- 改页表需要是原子的,在一个cpu上改了页表,需要原子地让其他CPU flush老的TLB
- 这需要软件做好同步,比如发IPI告知其他CPU等,防止其他CPU使用了老的TLB
Memory
- Page Size Extension
- 大页的支持需要cpu支持的,对于intel,cpuinfo里有pse(2M大页),pse36(32位时代的东西),pdpe1gb(1G大页)就表示支持大页
- index PMD的时候,entry中PS这个bit如果为1,就表示是个2M大页,就没有下一级页表了
- index PUD的时候,entry中PS这个bit如果为1,就表示是个1G大页,就没有下两级页表了
- 具体参考intel-sdm 4.5.4
- PCI hole
- 32位CPU的地址空间只有4G,当物理内存插满4G时,由于PCI等设备需要一部分地址空间来做MMIO,物理内存在地址空间上便不能连续,需要被挖出一个空洞
- Pentium Pro使用36bit总线来解决这个问题,可以把被hole覆盖掉的物理内存重映射到>4G的地址空间
- 但是至今到了64bit系统上,如果BIOS为了兼容16/32bit软件,还是会有这个问题
IO