你的位置:首页 > 操作系统

[操作系统]Linux内核系列—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	; 页目录开始地址: 2MPageTblBase		equ	201000h	; 页表开始地址: 2M+4KLABEL_DESC_PAGE_DIR: Descriptor PageDirBase, 4095, DA_DRW;Page DirectoryLABEL_DESC_PAGE_TBL: Descriptor PageTblBase, 1023, DA_DRW|DA_LIMIT_4K;Page TablesSelectorPageDir		equ	LABEL_DESC_PAGE_DIR	- LABEL_GDTSelectorPageTbl		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	00401000hProcFoo		equ	00401000hProcBar		equ	00501000hProcPagingDemo	equ	00301000h	call	SetupPaging		; 启动分页	call	SelectorFlatC:ProcPagingDemo	call	PSwitch			; 切换页目录,改变地址映射关系,和SetupPaging代码差不多	call	SelectorFlatC:ProcPagingDemoPagingDemoProc:OffsetPagingDemoProc	equ	PagingDemoProc - $$	mov	eax, LinearAddrDemo	call	eax	retfLenPagingDemoAll	equ	$ - PagingDemoProcfoo: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 列。	retLenFoo			equ	$ - foobar: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 列。	retLenBar			equ	$ - bar

 ProcFoo的值处的地址对应的是foo:函数,ProcBar的值处的地址对应的是bar:函数。

 

 

一个码农的日常 

源码