Lab: page tables¶
+-----------------------------------+
| |
| 程序运行时 |
| |
+-----------------+-----------------+
|
| 使用虚拟地址访问内存
|
v
+-----------------+-----------------+
| |
| MMU 硬件模块 |
| |
+-----------------+-----------------+
|
| 通过页表映射,将虚拟地址转换为物理地址
|
v
+-----------------+-----------------+
| |
| 操作系统的页表 |
| |
+-----------------+-----------------+
|
| 查找虚拟页号对应的物理页号
|
v
+-----------------+-----------------+
| |
| 物理内存 |
| |
+-----------------+-----------------+
解释过程图:
- 程序运行时,程序使用虚拟地址访问内存。
- MMU(Memory Management Unit)硬件模块是计算机的一部分,负责虚拟内存地址转换。它接收程序发出的虚拟地址,并通过页表映射将虚拟地址转换为物理地址。
- 操作系统的页表是存储在内存中的数据结构,它包含虚拟页号与物理页号之间的映射关系。MMU会使用虚拟页号在页表中查找对应的物理页号。
- 物理内存是实际的内存空间,包含了程序的数据和指令。一旦找到虚拟页号对应的物理页号,MMU会将物理页号与页内偏移组合成物理地址,从而能够访问实际的物理内存。
通过这个过程,程序能够在虚拟内存空间中运行,并且不需要关心物理内存的具体位置和管理,操作系统通过虚拟内存地址转换来完成内存管理的任务。
多级页表-名词¶
页(Page)¶
页(通常称为页面)是内存管理中的一个基础概念,它代表的是一个固定长度的内存块。操作系统把物理内存和虚拟内存都分为许多大小相等的页。例如,在很多系统中,一个常见的页大小可能是4KB。使用页的主要目的是为了实现虚拟内存系统,其中的地址空间由许多这样的页构成。
页表(Page Table)¶
页表是一种数据结构,它把虚拟地址空间中的页映射到物理内存中的页帧。这样的映射对于操作系统进行地址转换是必要的—即将程序使用的虚拟地址转换为实际物理内存地址。页表通常存储在内存中,有时候还会被缓存到快速的硬件寄存器(例如TLB—Translation Lookaside Buffer)中以加速查找速度。
页目录(Page Directory)¶
在许多分页系统中,特别是在Intel x86体系结构的传统分页模式中,页目录是管理页表的一种机制。考虑到页表可能会非常大,一个包含所有映射的单一页表将不实用,所以系统使用页目录来组织这些页表。页目录包含了指向页表的指针,每个指针都对应着一个页表,这些页表进一步存储着虚拟页到物理页帧的映射。页目录本身也分页,将地址空间的不同部分分配给不同的页表。
页表项(Page Table Entry,PTE)¶
每个页表项是页表中的一个元素,包含用于将虚拟页映射到物理页帧的信息。PTE通常包含物理页帧的地址以及与该页相关的一些标志,如是否可读写,是否已被访问,是否脏(被修改过),以及页是否在物理内存中。
页面¶
页面与页是相同的概念。在分页内存管理中,“页面”是另一种说法,指的是被分配了特定物理内存页帧的虚拟内存区域。
页框号=页帧号=内存块号=物理块号=物理页号
从属关系¶
-
页面(Page):
- 页面是虚拟内存中分配的基本单位,通常大小固定,如4KB或2MB。
-
页表项(Page Table Entry, PTE):
-
每个页面在页表中对应一个页表项(PTE)。
- 页表项包含映射信息,指示对应页面在物理内存中的实际位置(页帧)。
-
页表(Page Table):
-
页表是一系列页表项的集合。
- 一个页表通常包括足够的页表项来映射一块大的虚拟地址空间至物理内存页帧。
- 通常,一个页表能够映射几兆字节(MB)的内存空间。
-
页目录(Page Directory):
-
页目录含有指向页表的指针,是页表的一个高级索引。
- 在多级页表结构中,页目录是顶级结构,它组织了下层的页表。
- 当虚拟地址空间很大时,可能会有多个页表,每个页表负责地址空间的一部分,页目录帮助管理这些页表。
总的来看,从属关系可以描述如下:
- 虚拟地址由虚拟页面(分页大小的单位)组成。
- 每个虚拟页面都会在页表中有一个对应的页表项(PTE)。
- 所有的页表项组成了一个或多个页表。
- 页目录包含对这些页表的索引。
- 在分页中,页表项最终指向物理内存中的页帧,这就是虚拟页到物理页帧的映射。
代码¶
speed up syscall // todo
Print a page table¶
在defs.h
中添加声明
void vmprint(pagetable_t, int);
exec.c
中使用vmprint()
+ if (p->pid == 1)
+ vmprint(p->pagetable, 0);
return argc; // this ends up in a0, the first argument to main(argc, argv)
vm.c
中实现该函数
void vmprint(pagetable_t pagetable,int depth) {
if(depth > 2) { // 深度大于2就返回
return;
}
if(depth == 0) { // 深度等于0时输出pagetable
printf("page table %p\n",pagetable);
}
for(int i = 0; i < 512; i++){ // 遍历页表项
pte_t pte = pagetable[i];
if(pte & PTE_V) { // 如果可以访问
for(int i=0;i<=depth;i++){ // 处理vmprint的格式
if(i == 0)
printf("..");
else {
printf(" ..");
}
}
printf("%d: pte %p pa %p\n",i,pte,PTE2PA(pte)); // 输出
uint64 child = PTE2PA(pte); // 下一级
vmprint((pagetable_t)child,depth+1);
}
}
}
pa 物理地址
pte 页表
va 虚拟地址