《操作系统真象还原》第二篇:启动分页机制

《操作系统真象还原》第二篇:启动分页机制

目录

  • 《操作系统真象还原》第二篇:启动分页机制
    • 二级页表
      • 二级页表转换原理
      • 页目录项和页表项
    • 启动分页机制三部曲
    • TLB(快表)

二级页表

二级页表相比一级页表可以动态地创建页表,达到节省空间的目的。

二级页表转换原理

将虚拟地址分为高10位,中间10位,低12位三部分

转换步骤如下

  • 用虚拟地址的高10位乘4,作为页目录表内的偏移地址,加上页目录表的物理地址,所得到的的便是页目录项的地址。读取该页目录项,从中获取到页表的物理地址。
  • 用虚拟地址的中间10位乘4,作为页表内的偏移地址,加上页表的物理地址,所得到的便是页表项的物理地址。读取该页表项,从中获取到分配的物理页的地址。
  • 虚拟地址的低12位代表页内偏移地址,将其加上物理页的地址,便可得到最终的物理地址。

《操作系统真象还原》第二篇:启动分页机制_第1张图片

页目录项和页表项

页目录项和页表项结构如下,均为32位。

《操作系统真象还原》第二篇:启动分页机制_第2张图片

  • P位present,为1表示在内存中
  • RW位,read/write,为1表示可读可写
  • US位User/Supervisor,为0表示Supervisor级,特权级为3的程序不允许访问,只允许特权级为0,1,2的程序访问。
  • PWT和PCD位都用于高速缓存,为0表示关闭。
  • A位, Access,为1表示被CPU访问过。
  • D位,Dirty,意为脏页位,当该物理页被CPU写时,会将对应页表项的D位置1
  • PAT位,Page Attribute Table,意为页属性表位。
  • G位,Global意为全局位,若为1则将在TLB中保存
  • AVL位,Available,软件可用。

启动分页机制三部曲

  • 第一步:准备好页目录表及页表
  • 第二步:将页目录表的地址写入控制寄存器cr3
  • 第三步:控制寄存器的PG位置1

第一步所需函数如下:

;----创建页目录表及页表 ------
setup_page:
;先将页目录表的4kb初始化为0
	mov ecx, 4096
	mov esi, 0
.create_page_dir:
	mov byte [PAGE_DIR_TABLE_POS + esi], 0
	inc esi
	loop .create_page_dir
	
;开始创建页目录项(PDE)
.create_pde:
	mov eax, PAGE_DIR_TABLE_POS
	add eax, 0x1000			;此时eax为第一个页表的地址
	mov ebx, eax
	or eax, PG_US_U | PG_RW_W | PG_P
	;第一个页目录项和第768个页目录项映射到第一个页表,
	mov [PAGE_DIR_TABLE_POS + 0x0], eax
	mov [PAGE_DIR_TABLE_POS + 0xc00], eax
	
	;使页目录表最后一项指向页目录表自己的地址
	sub eax, 0x1000
	mov [PAGE_DIR_TABLE_POS + 4092], eax
	
;下面创建页表项
	mov ecx, 256		;1MB低端内存/4kb = 256页
	mov esi, 0
	mov edx, PG_US_U | PG_RW_W | PG_P
.create_pte:
	mov [ebx + esi * 4], edx
	inc esi
	add edx, 4096
	loop .create_pte
	
;创建内核地址空间(1GB)的其他页表的PDE
	mov eax, PAGE_DIR_TABLE_POS
	add eax, 0x2000			;此时eax为第二个页表的位置
	or eax, PG_US_U | PG_RW_W | PG_P
	mov ebx, PAGE_DIR_TABLE_POS
	mov esi, 769			;从第769个页目录项开始
	mov ecx, 254 			;高1GB共256个页目录项,除去第一个和最后一个,共254个
.create_kernel_pde:
	mov [ebx + esi * 4], eax
	inc esi
	add eax, 0x1000
	loop .create_kernel_pde
	ret

接下来正式开启三部曲

;第一步:创建页目录表并初始化页内存位图
call setup_page
	;将全局描述符表的地址读入gdt_ptr
	sgdt [gdt_ptr]
	
	;低2字节是界限,所以+2
	mov ebx, [gdt_ptr + 2]
	;将视频段的地址移到高1GB
	;视频段是第三个段描述符,所以8 * 3 = 0x18
	or dword [ebx + 0x18 + 4], 0xc0000000
	
	;将gdt的基地址移动到高1GB
	add dword [gdt_ptr + 2], 0xc0000000
	;将栈指针也移动到高1GB
	add esp, 0xc0000000
	
;第二步:将页目录表地址赋给cr3
	mov eax, PAGE_DIR_TABLE_POS
	mov cr3, eax
	
;第三步:将控制寄存器cr0的pg位(第31位)置1
	mov eax, cr0
	or eax, 0x80000000
	mov cr0, eax
	
	;启动分页后,用新的gdt地址重新加载
	lgdt [gdt_ptr]

TLB(快表)

​ 处理器准备了一个高速缓存,可以匹配高速的处理器速率和低速的内存访问速度,它专门用来存放虚拟地址页框和物理地址页框的映射关系,这个缓存就是TLB,即Translation Lookaside Buffer,俗称快表。

​ 只有P位为1的页表项才能在TLB中,TLB并不自动更新,由操作系统开发人员维护。

​ 有两种方法可以对TLB进行间接更新

  • 一个是针对TLB中所有条目的方法 - 重新加载cr3,这个操作会刷新TLB
  • 另一种方法是指令invlpg(invalidate page),针对某个虚拟地址对应的条目。指令格式为invlpg m,m表示操作数为虚拟内存地址,而不是立即数。

《操作系统真象还原》第二篇:启动分页机制_第3张图片

你可能感兴趣的:(操作系统,linux,运维,服务器)