[062][x86汇编语言]第16章 源码分析 过程[alloc_inst_a_page]

学习笔记

《x86汇编语言:从实模式到保护模式》
https://www.jianshu.com/p/d481cb547e9f

详细调用关系以及过程在整个内核程序中的作用

参见 https://www.jianshu.com/p/2dba8674e8fd

内核程序:过程[alloc_inst_a_page]

[062][x86汇编语言]第16章 源码分析 过程[alloc_inst_a_page]_第1张图片
过程[alloc_inst_a_page]

代码流程

  • 1、根据传入的线性地址EBX,计算对应的页目录表表项的线性地址,存入ESI
  • 2、视页表存在与否,尚未存在则,创建页表,登记页表;
  • 3、根据传入的线性地址EBX,计算对应的页表的线性地址,存入ESI
  • 4、根据传入的线性地址EBX + 页表的线性地址,计算页表表项的线性地址,存入ESI
  • 5、为用户程序,申请一个空闲的物理页,物理页的物理地址通过EAX传回,配置页属性,将EAX存入页表([ESI])

取自源码文件 c16_core.asm

alloc_inst_a_page:                          ;分配一个页,并安装在当前活动的
                                            ;层级分页结构中
                                            ;输入:EBX=页的线性地址
         push eax
         push ebx
         push esi
         push ds
         
         mov eax,mem_0_4_gb_seg_sel
         mov ds,eax
         
         ;检查该线性地址所对应的页表是否存在
         mov esi,ebx
         and esi,0xffc00000
         shr esi,20                         ;得到页目录索引,并乘以4 
         or esi,0xfffff000                  ;页目录自身的线性地址+表内偏移 
                                            ;ESI = 页目录表表项的线性地址

         test dword [esi],0x00000001        ;P位是否为“1”。检查该线性地址是 
         jnz .b1                            ;否已经有对应的页表
          
         ;创建该线性地址所对应的页表 
         call allocate_a_4k_page            ;分配一个页做为页表 
         or eax,0x00000007
         mov [esi],eax                      ;在页目录中登记该页表
          
  .b1:
         ;开始访问该线性地址所对应的页表 
         mov esi,ebx
         shr esi,10
         and esi,0x003ff000                 ;或者0xfffff000,因高10位是零 
         or esi,0xffc00000                  ;得到该页表的线性地址
                                            ;ESI=页表的线性地址
         
         ;得到该线性地址在页表内的对应条目(页表项) 
         and ebx,0x003ff000
         shr ebx,10                         ;相当于右移12位,再乘以4
         or esi,ebx                         ;页表项的线性地址 
                                            ;ESI=页表表项的线性地址
         call allocate_a_4k_page            ;分配一个页,这才是要安装的页
         or eax,0x00000007
         mov [esi],eax 
          
         pop ds
         pop esi
         pop ebx
         pop eax
         
         retf  

注意:下列图解中可能的存在一个容易混淆的部分

  • 有关移位操作的代码,比如右移12位再左移2位,往往直接写成右移动10位,本质上,左移两2位就是乘以4
  • 处理器进行地址转换时,对于线性地址是按照高10位 中10位 低12位的格式去解读的,要做的运算是
页目录表物理地址 + 高10位x4 = 页目录表项的线性地址
页表物理地址 + 中10位x4 = 页表表项的线性地址
物理页物理地址 + 低12位 = 真正的物理地址
  • 可知,低12位本来是不需要乘以4的,但是下面的代码要么是访问页目录的表项,要么是访问页表的表项,这里面暗含着一个逻辑,那就是新的低12位其实是从旧的线性地址的要么高10位、要么中10位通过移位操作而来的,并且需要与页目录表的物理地址或者页表的物理地址结合,在移位的过程中往往就隐藏地进行了X4的操作,表现在代码的汇编指令上就是左移2位,然后又由于汇编语法的规则,先右移22位再左移2位等价于直接右移20位,表现在图解里就是,结果的线性地址里,最右端的两位的两个0永远都不是来自最初的线性地址,而是过程中的补0,我往往使用空白底色标识出来了

一、检查该线性地址所对应的页表是否存在

         mov esi,ebx
         and esi,0xffc00000
         shr esi,20                         ;得到页目录索引,并乘以4 
         or esi,0xfffff000                  ;页目录自身的线性地址+表内偏移 

         test dword [esi],0x00000001        ;P位是否为“1”。检查该线性地址是 
         jnz .b1                            ;否已经有对应的页表
1、传入的参数 EBX=页的线性地址,有何独特之处?
  • 物理页的大小是4KB,即0x1000 Byte
  • 第一个可以分配的物理页的线性起始基地址EBX = 0x 0000 0000
  • 那么,第二个可以分配的物理页的线性起始基地址就是EBX = 0x0000 0000 +0x1000 = 0x 0000 1000
  • 同理,第三个可以分配的物理页的线性起始基地址就是EBX = 0x0000 1000+ 0x1000 = 0x 0000 2000
  • 可以很清楚地看见,作为传入参数的线性起始基地址,一定是EBX = 0x ?????000低12位必然全是0
2、图解假设传入参数为 EBX =0x11122000 进行移位操作
[062][x86汇编语言]第16章 源码分析 过程[alloc_inst_a_page]_第2张图片
寄存器ESI各比特值的变化.png
  • 假设的EBX要满足作为物理页的线性起始基地址的基本要求,即低12位全是0,表现在十六进制0x的写法上就是0x?????000

  • and 指令是为了保留,为了保留传入的线性地址的高10位,以后叫原来的高10位

  • or 指令是为了强制置为1,就是要把新的高10位以及新的中10位霸道地全部设置为1,因为0xFFFFF???页目录表自己的线性基地址

  • 这一小段代码, 就是为了计算出一个,可以访问页目录表自己表项的线性地址

  • 如果访问页目录表自己的表项,具体原理

参见 https://www.jianshu.com/p/d6b534560669

  • 这里只需要记住,一个线性地址,只要是以0xFFFFF...开头的那么一定是访问页目录表自己

  • 那么,原来的高10位到哪里去了?到低12位去了。现在,我们要访问的是页目录表自己的表项,这等于就是说,现在我们要访问一个物理页,页目录表就是这个物理页

高10位 要乘以4 作为页目录表偏移量
低12位 直接作为 页的偏移量

原来的高10位变成了 现在的低12位
页目录表 不仅做页目录表 还做页表 现在更要作为 页

现在的低12位 与 现在的页 正好结合
  • 现在,ESI = 可以访问 页目录表自己表项的线性地址
3、从页目录表表项中取出页表的物理地址,查看对应的页表是否已经存在
 test dword [esi],0x00000001
 jnz .b1  
  • P = 1 表示存在,则跳转到.b1去继续执行;
  • P= 0表示还不存在,需要先申请一个物理页当做页表,然后再继续执行;

二、为页表申请一个物理页

 ;创建该线性地址所对应的页表 
         call allocate_a_4k_page            ;分配一个页做为页表 
         or eax,0x00000007
         mov [esi],eax                      ;在页目录中登记该页表
  • 调用过程 allocate_a_4k_page

参见 https://www.jianshu.com/p/49cbaccd38c5

  • 传回EAX = 分配的空闲物理页的物理地址
  • 配置页的属性or eax,0x00000007US=1,RW=1,P=1
  • 完成登记 mov [esi],eax ;在页目录中登记该页表

三、计算要访问的页表的线性地址

  .b1:
         ;开始访问该线性地址所对应的页表 
         mov esi,ebx
         shr esi,10
         and esi,0x003ff000                 ;或者0xfffff000,因高10位是零 
         or esi,0xffc00000                  ;得到该页表的线性地址
[062][x86汇编语言]第16章 源码分析 过程[alloc_inst_a_page]_第3张图片
图解假设传入参数为 EBX =0x11122000 进行移位操作 计算要访问的页表的线性地址
  • 可见,要访问页表,线性地址必然是以0xFFC..... 开头;
  • 访问页表表项,具体原理

参见 https://www.jianshu.com/p/d6b534560669

  • 现在,ESI = 页表的线性地址

四、访问页表表项

 ;得到该线性地址在页表内的对应条目(页表项) 
         and ebx,0x003ff000
         shr ebx,10                         ;相当于右移12位,再乘以4
         or esi,ebx                         ;页表项的线性地址 
         call allocate_a_4k_page            ;分配一个页,这才是要安装的页
         or eax,0x00000007
         mov [esi],eax 
[062][x86汇编语言]第16章 源码分析 过程[alloc_inst_a_page]_第4张图片
计算 要访问的 页表表项的线性地址
  • 步骤三,ESI = 页表的线性地址
  • 过程 call allocate_a_4k_page 申请了一个物理页作为安装用户程序的物理页
  • EAX = 分配的空闲的物理页的物理地址
  • 配置页属性之后,填入页表表项mov [esi],eax

你可能感兴趣的:([062][x86汇编语言]第16章 源码分析 过程[alloc_inst_a_page])