用大白话说操作系统(五)

好的,OK,今天终于来到了高级语言的世界,操作系统的旅途又看到新风景了,日日新,我们废话不多说,现在开始!

开启分页机制

上次我们在head.s中重新设置了gdt和idt。
然后开启分页机制并跳转到main函数

jmp after_page_tables
...
after_page_tables:
    push 0
    push 0
    push 0
    push L6
    push _main
    jmp setup_paging
L6:
    jmp L6

如何开启分页机制

setup_paging:
    mov ecx,1024*5
    xor eax,eax
    xor edi,edi
    pushf
    cld
    rep stosd
    mov eax,_pg_dir
    mov [eax],pg0+7
    mov [eax+4],pg1+7
    mov [eax+8],pg2+7
    mov [eax+12],pg3+7
    mov edi,pg3+4092
    mov eax,00fff007h
    std
L3: stosd
    sub eax,00001000h
    jge L3
    popf
    xor eax,eax
    mov cr3,eax
    mov eax,cr0
    or  eax,80000000h
    mov cr0,eax
    ret

我们之前已经知道在保护模式下我们需要进行地址转换,那里段寄存器中存放的是段选择子,需要根绝分段机制的转换成物理地址,换言之,保护模式下一定是开启分段机制的,也就是将内存分为代码段、数据段和栈段这样的。
开启了分页机制后,我们的还是需要先经过分段机制的转换,但是转换后的地址仍然不是物理地址,而是线性地址,我们需要通过线性地址经过分页机制的转化才能得到物理地址。
段选择子+偏移地址 -> 线性地址 -> 物理地址

如何从线性地址到物理地址

线性地址:15M
二进制:0000000011_0100000000_000000000000
我们先将线性地址分为三部分

  • 高10位从页目录项找到对应页目录项
  • 页目录项值+中间10位找到页表项
  • 页表项值+后12位得到物理地址
    上面的这一系列操作由计算机硬件MMU(内存管理单元)来进行转换。
    操作系统作为一个系统软件,只需要提供页目录项和页表项就可以了~
    页目录项PDE
    可以看做是页表的一个索引表,起到一个目录的作用
    页表项PTE
    存放每个页的物理地址
    在这里插入图片描述
    开启分页机制就像之前开启保护模式一样改变cr0寄存器的一个标志位
    在这里插入图片描述
    好的,现在我们再来看设置也页表的代码,实际上是把页目录项和页表项在内存中写好了,linux-0.11认为总共可以使用的内存不超过16M也就是4个页表项就可以搞定了
    每个页表项可以包含1024个页表,每个页表的是4KB,因为有12位的偏移地址。
    然后将页目录表放在内存的最开头,随后放置4个页表项,随后开启分页机制。
    xor eax,eax
    mov cr3,eax
    
    此处告诉cr3寄存器,0地址处是页目录表,通过页目录表可以找到所有的页表。
    在这里插入图片描述
    现在内存中的一个样貌就是这样的了
setup_paging:
    ...
    mov eax,_pg_dir
    mov [eax],pg0+7
    mov [eax+4],pg1+7
    mov [eax+8],pg2+7
    mov [eax+12],pg3+7
    mov edi,pg3+4092
    mov eax,00fff007h
    std
L3: stosd
    sub eax, 1000h
    jpe L3
    ...

通过上面这段代码,将页目录项和页表项都填充完毕,映射到16M的内存地址空间 ,之后我们就可以顺利找到对应的内存地址了。

跳转到main函数

after_page_tables:
    push 0
    push 0
    push 0
    push L6
    push _main
    jmp setup_paging
...
setup_paging:
    ...
    ret

我们看到上述代码将0 0 0 L6压栈,这里栈是向下发展的,然后将_main压栈。

0
0
0
L6
main

我们看到自setup_paging之后是ret,也就是返回指令,到底返回到哪里呢,CPU直接将栈顶的元素当做返回地址,于是就跳转到main函数中执行了。
将esp(栈顶地址)赋值给eip,cs:eip就是CPU下一条执行指令的地址。
对于Intel而言,访问内存就分为三类:代码、数据、栈。
cs:eip:执行哪里的代码
ds:xxx:访问哪里的数据
ss:esp:栈顶地址在哪里

好的,OK,今天就说到这里吧。有问题欢迎留言讨论!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

神仙诙谐代码

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值