在Lab2中 我们将要建立基本的保护模式下的内存管理机制,我们有必要先弄清楚保护模式下是如何管理内存的。
概述
80x86在保护模式下内存机制主要分为段机制和页机制,其中页机制是基于段机制的。
关于一个内存管理机制,有两个大的方面我们需要关心,一个是如何寻址,另一个是如何确定权限(即实现所谓保护)。段机制和页机制都提供了一定的寻址功能,但是其中有一定的重复。JOS没有使用段机制中的寻址功能,所有寻址只和页机制有关。段机制和页机制共同决定权限。
段机制
概述:
通过段选择符(selector)从段描述符表中获得段描述符,再加上offset,可以映射得到linear address(线性地址)。
段描述符:
Descriptor Table(段描述符表)是一个段描述符的数组,Segment Descriptor(段描述符)定义虚拟内存段的基本信息,如base,limit(从哪里开始,从哪里结束),访问权限等。具体的段描述符信息如下图:
由图可以看出,段描述符是一个64位长的符在JOS中我们通过inc/mmu.h下的SEG
宏来快速定义。
#define SEG(type, base, lim, dpl) (struct Segdesc) \
{ ((lim) >> 12) & 0xffff, (base) & 0xffff, ((base) >> 16) & 0xff, \
type, 1, dpl, 1, (unsigned) (lim) >> 28, 0, 0, 1, 1, \
(unsigned) (base) >> 24 }
type:访问权限(可执行STA_X,可读STA_R,可写STA_W)
base:基地址,在JOS中所有段描述符的基地址都定义为0
lim:长度,都定义为0xFFFFFFFF
dpl : DESCRIPTOR PRIVILEGE LEVEL(描述符权限级别),在*nix系统中分为0-3(越低权限越高),0为kernel态,1-3为用户态。在JOS中定义了0(kernel态)和3(user态)(Linux也是这样定义的)。
在kern/env.c中定义了段描述符表gdc
struct Segdesc gdt[NCPU + 5] =
{
// 0x0 - unused (always faults -- for trapping NULL far pointers)
SEG_NULL,
// 0x8 - kernel code segment
[GD_KT >> 3] = SEG(STA_X | STA_R, 0x0, 0xffffffff, 0),
// 0x10 - kernel data segment
[GD_KD >> 3] = SEG(STA_W, 0x0, 0xffffffff, 0),
// 0x18 - user code segment
[GD_UT >> 3] = SEG(STA_X | STA_R, 0x0, 0xffffffff, 3),
// 0x20 - user data segment
[GD_UD >> 3] = SEG(STA_W, 0x0, 0xffffffff, 3),
// Per-CPU TSS descriptors (starting from GD_TSS0) are initialized
// in trap_init_percpu()
[GD_TSS0 >> 3] = SEG_NULL
};
段选择符(selector):
公式1:Linear Address=Base+Offset
由于段描述符定义的base=0
,所以有
公式2:Linear Address=Offset
页机制
概述:
页机制通过多层页表,把Linear Address映射到实际内存地址空间。
Linear Address:
线性地址(linear address)是一个32位长的数,DIR(10位长)是在第一层页表中的index,PAGE是在第二层页表中的index(10位长),OFFSET是在该页中的偏移量(12位长)。由此我们可以看出,第一层页表有1024项,第二层页表也有1024项,一个单独的页(one page)的大小时4K。
具体的寻址方式见:
其中CR3是一个寄存器,用来存放第一层页表(Page Directory)的基地址。
总结:由于禁用了段机制的寻址功能(只用来做访问控制),实际用户和开发者使用的(虚拟)地址(virtual memory)即等于线性地址(Linear Address),再通过两层页表,最终映射到了物理地址(Physical Address)空间。
参考:
1.Intel 80386 Programmer’s Reference Manual
2.GuoJing’s Blog/linux-kernel-architecture/segment-selector