Linux 0.11内核-内存管理
1. 为什么系统对1MB以内的内存空间不用分页方法管理?
答:操作系统的设计者对内核和用户进程采用了两套不同的分页管理方法。
(1)内核采用分页管理方法,线性地址和物理地址是完全一样的,是一一映射的。等价于内核可以直接获得物理地址。
(2)用户进程的线性地址和物理地址差异很大,他们之间没有可递推的逻辑关系。
操作系统设计者的目的就是让用户进程无法通过线性地址推算出具体的物理地址,让内核能够访问用户进程,用户进程不能访问其他的用户进程,更不能访问内核。
1MB以内是内核代码和只有由内核管控的大部分数据所在内存空间,是绝对不允许用户进程访问的。事实上内核只使用0-640Kb,剩余的部分被部分高速缓冲和设备内存占用
1MB以上特别是主内存区主要是用户进程的代码、数据所在内存空间,所以采用专门用来管理用户进程的分页管理方法,这套方法当然不能用在内核上。
2. 在一个具有16MB内存的80x8计算机系统中,其整个物理内存各部分的功能示意图如下:

在内核代码中的具体表现形式如下:
在Linux 0.11中,对1MB以上所有物理内存划分成一个个页面,并使用一个页面映射字节数组mem_map[]来管理所有这些页面。

3. 什么是操作系统? 其核心是什么?
操作系统就是若干正在运行、操作的进程构成的系统。其核心就是进程
4. 如何防止多个进程同时运行时,进程的代码、数据不会被其他进程直接访问、覆盖,即进程保护?
在Intel IA-32架构中,进程保护体现在对进程内存空间的保护,而进程内存空间的保护是由线性地址保护、物理地址保护实现的。简而言之:Linux操作系统依托Intel IA-32架构设计的段基址、段限长、GDT、LDT、特权级这一整套硬件保护机制,在线性地址层面上建立了牢固的进程间、进程与内核间的边界,有效地防止了非法跨越边界的操作。
5. 线性地址的保护具体体现在什么方面?
非法跨越进程边界有2种情况:从一个进程非法跨越到另一个进程以及从一个进程非法跨越到内核。
在Linux 0.11中,从如下方面对非法跨越进程边界保护:
(1)线性地址空间格局
- 32位线性总线的线性地址空间范围是0~4GB
- 将4GB的线性地址空间分成互不重叠的64等份,每份64MB,每个进程一份,最多同时开启64个进程
- 要求进程无论怎么执行,都不能跨越起点和终点
- task[64]是这个格局的基点,所有进程登记、注销都只由它统一管理
- 操作系统根据task[64]的项号nr在GDT中找到对应的LDT
- task[64]起到了控制进程总量,关联进程与GDT中的LDT,TSS的关键作用
(2)段基址、段限长、GDT、LDT、特权级
段基址和段限长:
- Intel早期的CPU为了降低成本,只设计了看住段起始位置的段头寄存器,并没有设计看住段结束位置的段尾寄存器。
- 为了兼容早期CPU,Intel IA-32架构在段寄存器中设计了段限长,等效于设计了段尾寄存器,用一个寄存器巧妙地起到了两个寄存器的作用。
- Linux 0.11操作系统利用Intel IA-32 CPU架构提供的段基址、段限长有效地阻拦了段内跳转中有意无意的越界行为。
- 但是对于进程代码中跨越段边界的ljmp,段基址、段限长不能阻拦
GDT、LDT:
- Linux 0.11采用的是通过LDT的设计,阻拦非法ljmp指令的执行
- 64个进程,每个进程都占用GDT的两项:TSS和LDT
- 所有进程的LDT段的设计是完全一样的,每个LDT都有3项:第一项为空,第二项是进程代码段、第三项是进程数据段
- Linux 0.11中所有进程的CS的内容都是一样的,用二进制表示的形式都是0000000000001111.。
- 代码段的段选择子存储在CS里面
- CPU硬件无法识别是哪一个进程的CS,也就无法选择段描述符,只能默认使用当前LDT中提供的段描述符
- 当一个进程的代码中有非法的跨进程跳转的指令时,比如ljmp,其操作数是“段内偏移段选择子”。无论后面操作数是什么,都无法跨越当前进程的代码段,也就无法进行段间跳转,最终只能是执行到本段
特权级:
- 用户进程代码段的特权级都是3
- 内核的特权级是0
- Intel IA-32架构禁止代码跨越特权级长跳转
- Linux0.11 将GDT、LDT这2个数据结构设置在内核数据区,是0特权级的,只有0特权级的代码才能修改设置GDT/LDT
- GDT/LDT是由CPU硬件认定的,这2个数据结构的首地址必须挂接在CPU中的GDTR、LDTR上
- Linxu 0.11在进程的初始化节点,就将GDT、LDT挂接到了CPU中的GDTR、LDTR上了

浙公网安备 33010602011771号