操作系统开发系列—6.内存分页机制

a.概述

页尺寸是4KB,页表每个表项占4字节,CR3寄存器给出了页目录的物理基地址;页目录给出了所有页表的物理地址,而每个页表给出了它所包含的页的物理地址。

处理器的页部件专门负责线性地址到物理地址的转换工作。它首先将段部件送来的32位线性地址截成3段,分别是高10位、中间的10位和低12位。高10位是页目录的索引,中间10位是页表的索引,低12位则作为页内偏移来用。

假如某个任务加载后,操作系统根据它的实际情况在其4GB虚拟地址空间里创建了一个段,段的起始地址为0x00800000,段界限值为0x5000,字节粒度。当该任务执行时,段寄存器DS指向该段。又假设执行了下面一条指令:

mov edx,[0x1050]

此时,段部件会输出线性地址0x00801050。在没有开启分页机制时,这就是要访问的物理内存地址,但现在开启了分页机制,这是一个虚拟地址,要经过页部件的转换才能得到物理地址。

当前任务页目录的物理地址在处理器的CR3寄存器中,假设它的内容为0x00005000.段管理部件输出的线性地址是0x00801050,其二进制的形式为0000 0000 1000 0000 0001 0000 0101 0000.高10位为0000000010,也就是十六进制的0x002,它是页目录表内的索引,处理器将它乘以4(因为每个目录项为4字节),作为偏移量访问页目录。最终,处理器从物理地址00005008处取得页表的物理地址0x08001000.

页目录表的表项简称PDE,页表的表项简称PTE。分页机制是否生效的开关位于cr0的最高位PG位。如果PG=1,则分页机制生效。

b.源码

PageDirBase		equ	200000h	; 页目录开始地址: 2M
PageTblBase		equ	201000h	; 页表开始地址: 2M+4K

LABEL_DESC_PAGE_DIR: Descriptor PageDirBase, 4095, DA_DRW;Page Directory
LABEL_DESC_PAGE_TBL: Descriptor PageTblBase, 1023, DA_DRW|DA_LIMIT_4K;Page Tables

SelectorPageDir		equ	LABEL_DESC_PAGE_DIR	- LABEL_GDT
SelectorPageTbl		equ	LABEL_DESC_PAGE_TBL	- LABEL_GDT

; 启动分页机制 --------------------------------------------------------------
SetupPaging:
    ...

PageDirBase和PageTblBase指定了页目录表和页表在内存中的位置。页目录表位于地址2MB处,有1024个表项,占用4KB空间。

PDE(左)和PTE(右)格式如下:

cr3的结构如下图,cr3又叫PDBR,它的高20位将是页目录表首地址的高20位,页目录表首地址的低12位会是零,也就是说,页目录表会是4KB对齐的。类似的,PDE中的页表基址以及PTE中的页基址也是用高20位来表示4KB对齐的页表和页。

运行结果如下:

d.分页机制的作用

LinearAddrDemo	equ	00401000h
ProcFoo		equ	00401000h
ProcBar		equ	00501000h
ProcPagingDemo	equ	00301000h

	call	SetupPaging		; 启动分页
	call	SelectorFlatC:ProcPagingDemo
	call	PSwitch			; 切换页目录,改变地址映射关系,和SetupPaging代码差不多
	call	SelectorFlatC:ProcPagingDemo

PagingDemoProc:
OffsetPagingDemoProc	equ	PagingDemoProc - $$
	mov	eax, LinearAddrDemo
	call	eax
	retf
LenPagingDemoAll	equ	$ - PagingDemoProc

foo:
OffsetFoo		equ	foo - $$
	mov	ah, 0Ch			; 0000: 黑底    1100: 红字
	mov	al, 'F'
	mov	[gs:((80 * 17 + 0) * 2)], ax	; 屏幕第 17 行, 第 0 列。
	mov	al, 'o'
	mov	[gs:((80 * 17 + 1) * 2)], ax	; 屏幕第 17 行, 第 1 列。
	mov	[gs:((80 * 17 + 2) * 2)], ax	; 屏幕第 17 行, 第 2 列。
	ret
LenFoo			equ	$ - foo

bar:
OffsetBar		equ	bar - $$
	mov	ah, 0Ch			; 0000: 黑底    1100: 红字
	mov	al, 'B'
	mov	[gs:((80 * 18 + 0) * 2)], ax	; 屏幕第 18 行, 第 0 列。
	mov	al, 'a'
	mov	[gs:((80 * 18 + 1) * 2)], ax	; 屏幕第 18 行, 第 1 列。
	mov	al, 'r'
	mov	[gs:((80 * 18 + 2) * 2)], ax	; 屏幕第 18 行, 第 2 列。
	ret
LenBar			equ	$ - bar

 ProcFoo的值处的地址对应的是foo:函数,ProcBar的值处的地址对应的是bar:函数。PSwitch和SetupPaging差不多,只是紧接着程序增加了改变线性地址LinearAddrDemo对应的物理地址的语句。改变后,LinearAddrDemo将不再对应ProcFoo,而是对应ProcBar。切换的过程是通过改变cr3的值完成的。

 

 

一个码农的日常 

源码

posted @ 2016-04-12 16:21  是非猫  阅读(1386)  评论(0编辑  收藏  举报