X86 head_32.S文件中内存映射详解(附图)

本帖最后由 cluter 于 2011-02-20 22:29 编辑

Non-PAE模式:

在non-PAE模式下,x86系统采用2-level页表。

相关的宏定义如下:

在Pgtable-2level_types.h文件中
//页全局目录的掩码
#define PGDIR_SHIFT            22
//页全局目录1024项
#define PTRS_PER_PGD        1024
//页表1024项
#define PTRS_PER_PTE        1024

在Page_32_types.h文件中
//定义内核大小为512MB---只是限制内核最大512MB
#define KERNEL_IMAGE_SIZE        (512 * 1024 * 1024)

代码分析:

1 相关的宏定义

//页表的大小=页数量 / 每个页表中页目录的个数
#define PAGE_TABLE_SIZE(pages) ((pages) / PTRS_PER_PGD)

//映射内核线性地址空间需要的内存大小
MAPPING_BEYOND_END = \
        PAGE_TABLE_SIZE(((1<<32) - __PAGE_OFFSET) >> PAGE_SHIFT) << PAGE_SHIFT

//内核页数量==(内核的大小+映射内核线性地址空间的页表的大小) / 页大小
//可以看出这个是 worst-case 下需要的内核页数量
KERNEL_PAGES = (KERNEL_IMAGE_SIZE + MAPPING_BEYOND_END)>>PAGE_SHIFT

//INIT_MAP_SIZE=初始化的时候必须要映射的内存大小,也就是上面kernel_pages的大小
INIT_MAP_SIZE = PAGE_TABLE_SIZE(KERNEL_PAGES) * PAGE_SIZE_asm

//在brk段 预留名字为pagetables大小为INIT_MAP_SIZE的空间
RESERVE_BRK(pagetables, INIT_MAP_SIZE)

2 页表相关数据的内存分配

//为页全局目录(pgd)分配1024*4byte的内存空间
ENTRY(swapper_pg_dir)
      .fill 1024,4,0


//为固定映射页表分配1024*4byte的内存空间
swapper_pg_fixmap:
        .fill 1024,4,0
//分配一页并初始化为0
ENTRY(empty_zero_page)
        .fill 4096,1,0

3 临时页表初始化代码

  //内核线性地址开始的地方在pgd中的偏移位置
  //__PAGE_OFFSET>>12>>10计算出在pgd中的页目录项index
  //(__PAGE_OFFSET>>12>>10)<<2计算出偏移地址(因为每个页目录项4byte)
  page_pde_offset = (__PAGE_OFFSET >> 20);
   
    //把开始存放页表(page table)的物理地址写入edi
        movl $pa(__brk_base), %edi
    //把页全局目录(pgd)的物理地址写入edx
        movl $pa(swapper_pg_dir), %edx
        //把页表项(pte)属性写入eax
    movl $PTE_IDENT_ATTR, %eax
10:
    //创建一个页表项(地址+属性)
        leal PDE_IDENT_ATTR(%edi),%ecx                /* Create PDE entry */
        //把页表项存入页全局目录(pgd)
    movl %ecx,(%edx)                        /* Store identity PDE entry */
    movl %ecx,page_pde_offset(%edx)                /* Store kernel PDE entry */
        //指向页全局目录的下一项
        addl $4,%edx
        //建立一个页表
        movl $1024, %ecx
11:
    //把eax中的内容(页地址+页属性)写入edi指向的物理地址,同时edi+4
        stosl
        addl $0x1000,%eax
        loop 11b
        //必须映射(KERNEL_IMAGE_SIZE+PAGE_TABLE_SIZE)大小的内存区域
        movl $pa(_end) + MAPPING_BEYOND_END + PTE_IDENT_ATTR, %ebp
        cmpl %ebp,%eax
    //如果还没有映射到则继续
        jb 10b
        //把页表结束的线性地址写入_brk_end变量中--->safe location
        addl $__PAGE_OFFSET, %edi
        movl %edi, pa(_brk_end)
        //把最大映射的页框数量写入max_pfn_mapped变量中
    shrl $12, %eax
        movl %eax, pa(max_pfn_mapped)

        //把pgd中的最后一个页全局目录项(pgd entry)设置成固定内存映射(fixmap)项
        movl $pa(swapper_pg_fixmap)+PDE_IDENT_ATTR,%eax
        movl %eax,pa(swapper_pg_dir+0xffc)

临时内核映射.jpg (45.7 KB)

下载次数:1

2011-02-20 22:24

作者: cluter   发布时间: 2011-02-20

看看

作者: ww2000e   发布时间: 2011-02-20