X86_64 CR3详解

从CPU的视角来看,是没有进程概念的,那么底层是如何区分进程的呢?因为不同的进程的虚拟地址是可以相同的。

应该是通过TLB来区分的,TLB通过flush的操作,将TLB刷新了,每次切换进程就flush TLB。CPU根本不需要区分进程,只需要从TLB中得到物理地址就行了。

flush TLB是通过cr3寄存器来决定何时flush的。cr3寄存器一旦改变,就会flush TLB。改变cr3的操作应该是操作系统来做的,Linux源码中有改变cr3的函数。

flush TLB的相关内容请看转载的文章:

X86_64 CR3控制寄存器详解_SweeNeil的博客-CSDN博客_cr3寄存器

转载内容如下:

CR3寄存器目前博客主要能查找到的内容都比较简单,例如

控制寄存器 cr0,cr2,cr3 - chingliuyu - 博客园》等博客,只对CR3寄存器进行了简单的介绍:

状态和控制寄存器组除了EFLAGS、EIP ,还有四个32位的控制寄存器,它们是CR0,CR1,CR2和CR3。其中CR1没有使用。

CR3含有存放页目录表页面的物理地址,因此CR3也被称为PDBR。因为页目录表页面是页对齐的,所以该寄存器只有高20位是有效的。而低12位保留供更高级处理器使用,因此在往CR3中加载一个新值时低12位必须设置为0。

使用MOV指令加载CR3时具有让页高速缓冲无效的副作用。为了减少地址转换所要求的总线周期数量,最近访问的页目录和页表会被存放在处理器的页高速缓冲器件中,该缓冲器件被称为转换查找缓冲区(Translation Lookaside Buffer,TLB)。只有当TLB中不包含要求的页表项时才会使用额外的总线周期从内存中读取页表项。

即使CR0中的PG位处于复位状态(PG=0),我们也能先加载CR3。以允许对分页机制进行初始化。当切换任务时,CR3的内容也会随之改变。但是如果新任务的CR3值与原任务的一样,处理器就无需刷新页高速缓冲。这样共享页表的任务可以执行得更快。

本文深入挖掘一下CR3寄存器的相关信息,了解MMU、TLB、操作系统与CR3寄存器的交互。

一、CR3寄存器
对于64位机,CR3寄存器也从32位变成了64位,它的主要功能还是用来存放页目录表物理内存基地址,每当进程切换时,Linux就会把下一个将要运行进程的页目录表物理内存基地址等信息存放到CR3寄存器中。

 

二、CR3寄存器与TLB
关于CR3寄存器与TLB找到了两个大佬的博文,对于TLB里面的信息描述得很清楚,可以直接移步~

1、《TLB原理》

地址:https://zhuanlan.zhihu.com/p/108425561?utm_source=wechat_timeline

这个文章对于TLB的原理描述地很清晰,TLB只能使用虚拟地址来做tag,那么是否会出现TLB别名问题以及TLB歧义问题都进行了分析。文中指出了TLB不存在别名问题,但是存在TLB歧义,解决TLB歧义最简单的方法就是进程切换之后使整个TLB无效,这会导致性能损失,所以文中提出了尽可能避免TLB flush的方法,例如在TLB中添加一项ASID(Address Space ID)的匹配之类的。这篇文章很有参考价值,内容也比较新~

2、《进程切换分析(2):TLB处理》

地址:http://www.wowotech.net/process_management/context-switch-tlb.html

这个文章也提出了《TLB原理》这个文章中的一些问题,但是没有上一篇文章那么细致,它重点关注了进程切换的时候,TLB的一些处理。

在《深入理解LINUX内核》一书中指出,Intel微处理器只提供了两种使TLB无效的技术:

在向CR3寄存器写入值时所有Pentium处理器自动刷新相对于非全局页的TLB表项;
在Pentium Pro及之后的处理器中,invlpg汇编语言指令使映射指定虚拟地址的单个TLB表项无效。
深入理解LINUX内核基于2.6版本内核,本文将基于4.15版本内核对相关内容进行探究,所以上面的说法可能有些已经过时,需要我们自己看内核代码来分析。对于本节给出的文章2《进程切换分析(2):TLB处理》,它指出x86平台上,在进程切换的时候,软件不需要显示的调用tlb flush函数,在switch_mm函数中会用next task中的mm->pgd加载CR3寄存器,这时候load cr3的动作会导致本cpu中的local tlb entry被全部flush掉。在x86支持PCID(X86术语,相当与ARM的ASID)的情况下会怎样呢?也会在load cr3的时候flush掉所有的本地CPU上的 local tlb entry吗?其实在linux中,由于TLB shootdown,普通的linux并不支持PCID,因此,对于x86的进程地址空间切换,它就是会有flush local tlb entry这样的side effect。

但是对于切换到内核线程时,不需要进行TLB flush,这里涉及到enter_lazy_tlb函数。

三、CR3寄存器与操作系统
CR3寄存器的改变与操作系统的关联主要是由于进程切换,每当进程切换时,CR3的内容需要被操作系统修改。

先了解一下进程切换的具体内容,从本质上说,每个进程切换由两部分组成:

1、切换页全局目录以安装一个新的地址空间

2、切换内核态堆栈和硬件上下文,因为硬件上下文提供了内核执行新进程所需要的所有信息,包括CPU寄存器。
原作者还有Linux源码分析,我没有看过源码,就不在此转载源码部分了,有需要请看原文章。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值