linux内存管理基本框架

来源:互联网 发布:反宋复唐 知乎 编辑:程序博客网 时间:2024/05/21 09:12
        为了兼容64位CPU,linux使用三层页式结构管理,分为页面目录PGD,中间目录PMD, 页表PT(其实是3个数组),页表中的项成为PTE
实际在i386架构上,因为硬件只支持2层,所以PMD被忽略了与PGD一样,所以,就是说经过PMD映射后,还是原来PGD的值。
        内核为MMU设置好PGD、PT,然后根据线性地址中的相应段作为下标找到最后的PTE。
 
        linux把高1G地址(0xC0000000-0xFFFFFFFF)用于系统空间,低的3G空间为用户空间。
        每个进程都有4G虚拟空间,系统空间所有进程共享。对于系统空而言,其物理地址到虚拟地址的映射就是线性映射,
所以把系统的虚拟地址减去0xC0000000就是其物理地址,同理从物理地址可以转换到虚拟地址。
 
        linux内核才用页式存储,但I386硬件是先段式再页式,内核在建立一个进程时都会设置他的段寄存器设置好。
#define start_thread(regs, new_eip, new_esp)    do    {    \
    __asm__("movl %0, %%fs;     movl %0, %%gs":     :"r"(0)); \
    set_fs(USER_DS);    \
    regs->xds    = __USER_DS;    \
    regs->xes    = __USER_DS;    \
    regs->xss    = __USER_DS;    \
    regs->xcs    = __USER_CS;    \
    regs->eip    = new_eip;    \
    regs->esp    = new_esp;    \
}   while (0)  
        上面的代码说明linux下除CS外,数据段和堆栈段是不分的。
以下是CS和DS段寄存器的值定义:
#define __KERNEL_CS       0x10     // 0000    0000    00010    0    00 ;   index=2
#define __KERNEL_DS       0x18    // 0000    0000    00011    0    00 ;    index=3
#define __USER_CS            0x23    // 0000    0000    00100    0    11;    index=4
#define __USER_DS            0x2b    // 0000    0000    00101    0    11;    index=5
   
        从上看出,linux只用GDT,而且GDT数组的2、3、4、5位固定存放了一个线性地址。
        GDT在arch/i386/kernel/head.S里初始化,其主要内容在运行中不变。
ENTER(gdt_table)
    .quad    0x0000000000000000
    .quad    0x0000000000000000
    .quad    0x00CF9A000000FFFF  // 0000   0000   1100   1111   1001   1010   0000   0000   0000000000000000   1111111111111111
    .quad    0x00CF92000000FFFF
    .quad    0x00CFFA000000FFFF
    .quad    0x00CFF2000000FFFF
        上面看出 基地址都是0,段上限0xFFFFF,段长单位是4K,段都在内存,有区别的是DPL(0是运行级别0级,3是3级), type 1010是代码段,0010是数据段。(图在38页)
        因为基地址是0,所以经过段映射后,地址不变,下面再做页式转换。
 
        页式映射时,每个进程都有各自的页面目录PGD,保存在mm_struct结构体里。
当调度一个进程运行时,内核都先调用switch_mm()函数设置好CR3,MMU会从CR3里取得PGD地址。
switch_mm()函数里有关键一行:
__asm__("movl %0, %%cr3":     :"r"(__pa(next->pgd))); // __pa是转换成物理地址 
 
        比如call一个地址0x12345678,段式映射后还是这个值,根据10、10、12位的分布,经过页式映射,可以获得物理存储地址,然后去取。
原创粉丝点击