查看linux kernel地址空间,为什么x86上Linux kernel没有自己独立的地址空间?

接上上次写的博文(linux里的high memory),里面提到high

memory存在的原因是在32位系统下,kernel只能访问高端的1G地址空间(kernel需要和进程共享地址空间),从而导致当物理内存超过896M的时候,有一部分物理内存无法直接映射。那既然x86提供了MMU进行地址转换,为什么kernel不能有自己独立的4G地址空间?如果kernel有自己独立的4G空间,那就不需要high

memory了,另外user space进程也可以有完整的4G空间。(物理内存超过4G?那是另外一个问题,和high

memory无关,x86提供了PSE(32位)以及PAE(64位)来解决这个问题。)

先来看看如果kernel要有自己独立的4G空间,需要什么样的硬件支持。进程之所以有各自独立的地址空间,是因为进程有自己的独立页表(kernel管理,保存在task_struct中),当进程切换的时候,kernel负责切换进程的页表(参考context_switch->switch_mm)。同样的道理,如果kernel想要有独立地址空间,就要有自己的独立页表,并且在切换到kernel态的时候,切换到kernel的页表。什么时候会切换到kernel态?中断发生的时候(这里的中断包括外部中断,以及INT

x等软件exception,以及NMI等等所有中断)。kernel是直接管理硬件的代码,kernel不能自己load映射自己的页表,所以这个页表切换过程必须硬件实现。有人可能会问,中断发生时(切换到kernel态)的第一件事就是切换到kernel的页表,不就可以实现kernel自己切换页表了吗?不行的,首先中断向量表里的interrupt

handler里的地址本身就是虚拟地址,不是物理地址,这时页表没有ready,当然CPU就不能访问到正确的interrupt

handler。那如果把IDT表的interrupt

handler设计成物理地址不就行了吗?也不行,因为切换到kernel态的时候,要保存执行现场,比如代码断,数据段,比如堆栈地址等等,而这个也是虚拟地址。所以,要想让kernel有自己独立的地址空间,硬件必须支持切换到kernel态的时候,自动切换到kernel的页表。

那x86提供这样的硬件机制吗?没有。其实x86的Task

switch机制可以提供自动切换页表,但这是为进程切换用的(以及让中断在自己的线程里跑),设计的远比单纯切换页表复杂,并不适用于这种目的(事实上,由于使用Task

switch机制,时间开销很大,Linux并没有使用该机制去实现切换)。所以,在x86上,kernel只能和user

space进程共享地址空间,在用户态切换到内核态时,不会进行页表切换,这样,只要所有的进程都共享内核空间(高端1G),kernel就可以正确寻址,无论是从哪个进程切换到内核态,因为所有进程的3G~4G这段虚拟地址的映射都是一样的。顺便提一句,SPARC的MMU提供了这样的机制,所以Solaris在SPARC上,kernel和用户态进程是各自独享64位地址空间。

总之一句话,所有地址空间的管理和分配(能力),本质上都是MMU的架构决定的,MMU提供什么样的能力,决定了对地址空间管理和分配的能力。这个适用于CPU,也适用于IO。

题外话:

1)关于x86进程切换时TLB的flush

x86规定,切换页表的时候(move页表基地址到CR3),会invalidate整个TLB。这种设计导致进程切换会影响性能,因为当进程被重新调度到CPU上的时候,原先cache在TLB里的数据早就没有了。个人觉得这是一种非常脑残的设计,因为要解决这个问题很简单,只需要为不同的进程tag一个PID(进程ID)就行了,TLB

cache的数据里也包含PID,有了PID做为tag,进程切换时就不需要invalidate整个TLB。目前x86_64的paging机制里实现了类似的机制,但提供的PID只有12位,最多支持4k个PID,这对于现在的OS来说,实在是太少了。不知道Intel为什么这么设计,也许是由于兼容性的包袱,谁知道呢。

2)下次再写吧:)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值