保护模式——从分段到分页
其实很早以前就想写这个关于分页模式的了,可是自己还是有点东西没弄的太明白,今天也是终于写出来了,关于上一篇讲分段机制的,一博友还夸了我一下,另我有点小激动,开博客三年来第一次啊!谢谢那位博友,也同时给我很大鼓励,觉得就是每天抱着一大堆天书,没人指导的也值了!
当然也免不了会有错误,但是以后会开一个错误更正章,专门负责更正错误。
关于分段模式和分页模式的关系,分页是在分段的基础上进行的,具体关系请见:内存管理--三个地址,分页与分段的关系http://blog.sina.com.cn/s/blog_6730a3aa01010z8m.html
大家都知道,我们现在的内存现在都是几个GB,上一章也说了是为了提高寻址范围而有了保护模式,那么在保护模式下分段模式下总感觉内存定位不是很好,其实单单是使用分段的话也能实现应有的功能。而分页模式就为内存提供了更加细致的划分,每个页是4KB,每个也都能准确的寻址定位到具体的字节。这样细致的划分也就很啥啥啥了。
那么首先来介绍下分页机制的原理,分页机制采用的是三级寻址,为了好理解,我们用一个比喻:
我们平时看书的时候要想看哪个具体内容,也就是哪一页,我们首先找到目录里面的哪一章,然后在找到的章中找到哪一节,然后我们再到找到的节中具体的找到哪一页。那么,这其中就用到了三个“地址”,章、节和页。
类似的,在内存分页机制也是这样的(引用老师说的话就是当计算机的东西困扰人的时候,计算机工作者就会想到实际生活,看,这个就是实际生活的例子),我们把一页内存(4KB)比喻成书的一节(注意不是一页,而是一节,可以把具体的字节(具体地址)看成是书的一页),保存这些内存页的地址的地方我们成为页表,实际是内存里面的一张表(先记住!!!),我们把保存所有页表地址的地方比喻成为章,我们成为页目录表,也就是说页目录表里面存的是很多页表的地址,页表里面存的是很多页地址(你明白了吗?:-)),实际上页目录表和页表都是内存里面的表,是实际存在内存里面的。那么现在你就会问了,页目录表是怎么寻到的?其实页目录表的首地址是在一个固定的寄存器中存存着的,硬件会自动识别:-)。那么,现在寻到4KB的页了以后是不是还是需要一个地址来寻到具体的地址,也就是定位到哪一个字节?是的:-)。现在来理清一下寻址方式:
好了,了解了分页机制的大致过程之后我们再来看点专业的东西:
首先,我们来看看保存页目录表的寄存器:
CR3控制寄存器:
还记得上一章说的CR0吗?跟这个差不多,80X86一共有五个控制寄存器:CR0~CR4,现在我们看看前四个:
前三个暂时不说,看 CR3,CR3的后20位保存的是页目录表的地址的高20位,也就是说页目录表的地址的低12位必须位0。
然后再来说说传说中的线性地址和物理地址,还有一种地址怕弄乱在此不说,线性地址说通俗点就是我们程序里面写的地址(事实上线性地址是由分段模式翻译过来的地址,具体请见:内存管理--三个地址,分页与分段的关系http://blog.sina.com.cn/s/blog_6730a3aa01010z8m.html),物理地址就是内存里面的实际地址,保护分页模式下线性地址经过一系列翻译后翻译成物理地址,然后才可访问,那么我们在程序里面写的线性地址格式如下:
22~31位:A段 |
12~21位:B段 |
0~11位:C段 |
为了防止头晕,我们不使用那些专业术语,我们直接使用A、B、C段来表示,A段存的数据指示的是页目录表里面的哪一项,单位为(个),注意,不是字节!!!B段存的数据指示的是页表里面的哪一项,单位为(个),C段指示的是页内的偏移量,单位为(字节)。
值得说明的是:内存里面可以有很多页目录表,一般4GB以内,一个页目录表就够用了,一个页目录表指向很多页表,一个页表指向很多页,从上面可以看出,一个页目录表总共最多可以指向2^10=1024个页表,一个页表最多可以指向2^10=1024个页,每个页有2^12=4KB.实际上,一个页目录表里面的项有4字节,一个页表里面的项也是4个字节。所以一页内存可以存储一个页目录表或者一个页表。
我们再来看看页目录表里面的一项,我们就称为页表项,一个页表项占4个字节,格式如下:
其中 12~31位存的是页表的基地址,其他的下面介绍。
页表里面的一项称为页表项,格式如下:
其中 12~31位存的是页的基地址,其他的位同页表项一样:
如下摘自《Linux0.11源码分析》:
下面就总结看看寻址:
从上面可以知道,基地址位20位,就是说基地址后面20位为0.
延续上面的A、B、C段,我们称页目录项的物理地址部分位X1,页表项的物理地址部分为X2,那么:
页表基地址位:
因为A的单位为个数,一个位4字节,所以要乘以4.
页基地址位:
物理地址位
设置好这些后我们再设置一个东西,那就是CR0的pg位,pg=0时不启用分页机制,当pg=1时才启用分页机制。
设置好分页机制以后,内存地址从线性地址到物理地址的转换是由硬件负责的,我们不用管,剩下的就是软件控制内存什么的了,现在不知道该写什么了,等想到了再继续写。
下面是代码:代码说明后来加上(电脑没电了。。。。。)
boot.asm:
start:
load_setup:
ok_load_setup:
load_msg:
load_curser:
loadmessage
setup.asm:
gdtaddr:
gdt:
null_table:
system_code_table:
system_data_table:
user_code_table:
user_data_table:
idtaddr:
start:
load_jump:
load_set:
ok_load:
;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; hadware read here.
;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
move_gdt:
load_msg:
load_curser:
open_a20:
o:
t:
move_jump:
init_8259a:
io_delay:
set_cr0:
loadmessage:
jump.asm:
set_cr0:
start:
show:
set.asm:
_idt:
_gdt:
start:
set_page_dir:
s1:
end_set_page_dir:
set_int_table:
set_int_end:
open_pages:
set_cr3:
set_cr0:
open_pages_end:
操作系统文章更正地址:http://blog.sina.com.cn/s/blog_6730a3aa01010xrc.html
前一篇:操作系统引导--从实模式到保护模式后一篇:文章更正篇