试验目标
操作系统和应用程序都需要内存空间来存放代码和数据,这要求操作系统能够高效管理和保护整个计算机中的物理内存,并给自己和上层应用提供简洁安全的内存申请和释放的服务接口。通过分段机制可以完成虚拟地址到线性地址的转换,而通过分页机制可以进一步完成线性地址到物理地址的转换。分段机制中对每段的大小是可变的,分页机制中页的大小固定为4KB,这样在操作系统对实现内存管理上会更加简洁。所以在建立好分页机制后,分段机制的映射功能退化为对等映射,即虚拟地址=线性地址,这样实际的地址映射工作将由分页机制来完成。
为此ucore需要在已有的分段机制的基础上,进一步加入分页机制,达到可以通过分页完成对不同应用程序执行的内存空间进行隔离(其实分段也能够达到此目的,但相对实现的开销会比较大,受到的限制(比如支持的应用执行个数)也较多)的目标。并且为后续的虚存管理提供基础支持。
proj5/5.1/5.1.1/5.1.2/5.2概述
实现描述
proj5基于proj4.3实现,主要完成了对计算机实际物理内存大小与分布的探测,实现以页(大小为4KB)为单位的简单物理内存管理,并通过建立二级页表,实现了分页内存管理,为将来试验中实现虚存管理打下一个基础。通过分析和实现proj5,读者可以了解到:
- 物理内存空间布局的探测;
- 基于分页机制的存储管理;
- 32位地址空间的二级页表结构;
proj5.1在proj5的基础上实现了基于best fit内存分配算法的页级内存分配和释放功能;proj5.1.1在proj5.1的基础上实现了first fit内存分配算法的页级内存分配和释放功能;proj5.1.2在proj5.1的基础上实现了worst fit内存分配算法的页级内存分配和释放功能;proj5.2在proj5.1的基础上实现了更加实用和强大的buddy内存分配算法的页级内存分配和释放功能。这些proj是操作系统原理相关算法的具体实现。读者可以参考这些实现完成新的内存分配算法。在这里通过讲解proj5的实现,让读者理解如何基于一个内存分配管理框架来实现不同的内存分配算法。
项目组成
proj5
|-- boot
| |-- asm.h
| |-- bootasm.S
| `-- bootmain.c
|-- kern
| |-- init
| | |-- entry.S
| | `-- init.c
| |-- mm
| | |-- default_pmm.c
| | |-- default_pmm.h
| | |-- memlayout.h
| | |-- mmu.h
| | |-- pmm.c
| | `-- pmm.h
| |-- sync
| | `-- sync.h
| `-- trap
| |-- trap.c
| |-- trapentry.S
| |-- trap.h
| `-- vectors.S
|-- libs
| |-- atomic.h
| |-- list.h
`-- tools
|-- kernel.ld
相对与proj4.3,proj5增加了6个文件。主要修改和增加的文件如下:
- boot/bootasm.S:增加了对计算机系统中物理内存布局的探测功能;
- kern/init/entry.S:根据临时段表重新暂时建立好新的段空间,为进行分页做好准备。
- kern/mm/default_pmm.[ch]:提供基本的基于链表方法的物理内存管理(分配单位为页,即4096字节);
- kern/mm/pmm.[ch]:pmm.h定义物理内存管理类框架struct pmm_manager,基于此通用框架可以实现不同的物理内存管理策略和算法(default_pmm.[ch] 实现了一个基于此框架的简单物理内存管理策略); pmm.c包含了对此物理内存管理类框架的访问,以及与建立、修改、访问页表相关的各种函数实现。
- kern/sync/sync.h:为确保内存管理修改相关数据时不被中断打断,提供两个功能,一个是保存eflag寄存器中的中断屏蔽位信息并屏蔽中断的功能,另一个是根据保存的中断屏蔽位信息来使能中断的功能;
- libs/list.h:定义了通用双向链表结构以及相关的查找、插入等基本操作,这是建立基于链表方法的物理内存管理(以及其他内核功能)的基础。其他有类似双向链表需求的内核功能模块可直接使用list.h中定义的函数。
- libs/atomic.h:定义了对一个变量进行读写的原子操作,确保相关操作不被中断打断。
- tools/kernel.ld:修改了ucore的起始入口和代码段的起始地址
编译运行
编译并运行proj5的命令如下:
make
make qemu
则可以得到如下显示界面
chenyu@chenyu-laptop:~/oscourse/ucore-svn/lab2_memory/proj5$ make qemu
(THU.CST) os is loading ...
Special kernel symbols:
entry 0xc010002c (phys)
etext 0xc010537f (phys)
edata 0xc01169b8 (phys)
end 0xc01178dc (phys)
Kernel executable memory footprint: 95KB
memory managment: default_pmm_manager
e820map:
memory: 0009f400, [00000000, 0009f3ff], type = 1.
memory: 00000c00, [0009f400, 0009ffff], type = 2.
memory: 00010000, [000f0000, 000fffff], type = 2.
memory: 07efd000, [00100000, 07ffcfff], type = 1.
memory: 00003000, [07ffd000, 07ffffff], type = 2.
memory: 00040000, [fffc0000, ffffffff], type = 2.
check_alloc_page() succeeded!
check_pgdir() succeeded!
check_boot_pgdir() succeeded!
-------------------- BEGIN --------------------
PDE(0e0) c0000000-f8000000 38000000 urw
|-- PTE(38000) c0000000-f8000000 38000000 -rw
PDE(001) fac00000-fb000000 00400000 -rw
|-- PTE(000e0) faf00000-fafe0000 000e0000 urw
|-- PTE(00001) fafeb000-fafec000 00001000 -rw
--------------------- END ---------------------
++ setup timer interrupts
100 ticks
100 ticks
……
通过上图,我们可以看到ucore在显示其entry(入口地址)、etext(代码段截止处地址)、edata(数据段截止处地址)、和end(ucore截止处地址)的值后,探测出计算机系统中的物理内存的布局(e820map下的显示内容)。接下来ucore会以页为最小分配单位实现一个简单的内存分配管理,完成二级页表的建立,进入分页模式,执行各种我们设置的检查,最后显示ucore建立好的二级页表内容,并在分页模式下响应时钟中断。下面我们将分析到底发生了什么事情。