在保护模式下启动分页机制,并且使…

分页是在应用程序对内存的需要越来越大的情况下出现的,为了满足应用程序对内存可寻址地址超过4MB的需要,在80386开始就加入了分页机制。

分页机制是针对某一个任务的,或者更准确的说是针对某一个段的。我们在某一个段使用分页机制,就要把对应的页目录表基址给cr3,从而开始使用该段对应的虚拟地址;当我们切换任务,或想要跳转到另外一个段的时候,需要从新加载cr3。每当把一个任务的cr3加载好后,该任务都可以访问4GB的虚拟内存地址。

而在x86中的各个地址之间的关系是
在汇编程序中,我们给出的是类似于[gs:edi]这样的逻辑地址,在保护模式中,用分段的方法,cpu会把gs左移4位,再加上edi得到线性地址。如果这时候没有启动分页机制,这个线性地址就等于物理地址。如果这时候已经启动分页机制,则cpu会通过这个线性地址和该段加载到cr3的页目录表基址,进行分页转换,通过地址映射,把线性地址映射到摸一个物理地址。
在保护模式下启动分页机制,并且使用虚拟地址来验证分页机制
注意,只有在保护模式下才可以打开分页机制,不然会出现不可挽回的错误(一般就是虚拟机再也不能打开了,除非修改vmx里面的内容)

那假设我们在启动分页机制后,使用了某个虚拟地址,cpu是如何对它进行映射的呢?
首先,对于每一个要使用虚拟地址的段,我们都要准备好一张页目录表和1024张页表,存放到内存的某一个位置,其中每一个页目录有1024个项,每一项对应一个页表的基址;每一个页表也有1024个项,每一个项对应一个4K的物理页。我们先把页目录表的基址赋值给cr3寄存器,来通知cpu虚拟地址的映射关系存在这个位置开始处。
然后,分段机制会帮我们把逻辑地址(虚拟地址形式)转换为线性地址,这时候这个线性地址由三部分组成,第一部分是在页目录表中的偏移,第二部分是在页表中的偏移,第三部分是在物理页中的偏移。
通过线性地址和地址映射关系,就可以得到物理地址。
在保护模式下启动分页机制,并且使用虚拟地址来验证分页机制
在保护模式下启动分页机制,并且使用虚拟地址来验证分页机制

我们了解了映射关系,现在就开始编写这张映射关系表
首先我们要建立两个段描述符,这两个描述符都用来描述同一个段,只不过一个的属性是用来建立表的,一个的属性是用来读写的。
LABEL_DESC_PAGE: Descriptor 0,               0xFFFFF,             DA_DRW | DA_LIMIT_4K
LABEL_DESC_EXE: Descriptor 0,               0xFFFFF,             DA_DRW | DA_DPL3
...
SelectorPage equ LABEL_DESC_PAGE - LABEL_GDT
SelectorExe equ LABEL_DESC_EXE - LABEL_GDT

然后我们来填写这张表,我们假设页目录表的基址为PageDirBase,第0张页表的基址为PageTblBase
;启动分页机制
mov eax, SelectorPage
mov es, eax
mov edi, PageDirBase
xor eax, eax
mov eax, PageTblBase | PG_P | PG_USU | PG_RWW
mov ecx, 1024
.1: ;循环初始化页目录表,使它里面的每一项对应于一个页表
stosd
add eax, 4096
loop .1
mov edi, PageTblBase
mov ecx, 1048567
xor eax, eax
mov eax, 0x0 | PG_P | PG_USU | PG_RWW
.2: ;循环初始化页表,使它里面的每一项对应于一个物理页
stosd
add eax, 4096
loop .2

按照上面的映射关系,我们把这个段的线性地址和物理地址映射到了相同的位置,也就是使用这个映射关系,线性地址就是物理地址。这样我们很难让自己信服,所以我们额外修改一个映射关系
;测试一个虚拟地址 
  mov edi, PageTblBase 
  mov eax, 0x400000 | PG_P | PG_USU | PG_RWW 
  stosd
也就是说,我们单独把虚拟地址0x0映射得到了0x400000的物理地址处

然后,加载cr3,启动分页机制
mov eax, PageDirBase
mov cr3, eax
mov eax, cr0
or eax, 0x80000000
mov cr0, eax

;进入该段,往虚拟地址[0:50]写入一个字符
mov ax, SelectorExe
mov es, ax
mov al, 'K'
mov [es:50], al
;写入字符后,关闭分页机制
mov eax, cr0
and eax, 0x7FFFFFFF
mov cr0, eax
;再取原虚拟地址[0:50]对应物理地址[400000:50]的内容显示
mov ax, SelectorPa 
mov es, ax
mov edi, (80 * 12 + 4) * 2
mov ah, 0x0C
mov al, [es:50]
mov [gs:edi], ax
这样就算是一次写虚拟地址,然后通过映射关系找到物理地址读内容的过程

运行结果:
在保护模式下启动分页机制,并且使用虚拟地址来验证分页机制

还有值得注意的是,在保护模式下,对于段寄存器的赋值问题,不是所有属性的段都可以赋值给段寄存器,在这里我给的段属性是DA_DRW | DA_DPL3,若果加上DA_32什么什么的,好像就不可以赋值给段寄存器,值得注意。

在这个文件夹里面注意,把paging.asm 编译成setup.asm
nasm paging.asm -o paging.bin
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值