免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 8984 | 回复: 15
打印 上一主题 下一主题

X86 head_32.S文件中内存映射详解(附图) [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2011-02-20 22:18 |只看该作者 |倒序浏览
本帖最后由 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, 下载次数: 48)

临时内核映射.jpg

评分

参与人数 1可用积分 +24 收起 理由
Godbach + 24 感谢分享

查看全部评分

论坛徽章:
0
2 [报告]
发表于 2011-02-20 22:38 |只看该作者
看看

论坛徽章:
22
丑牛
日期:2014-08-15 14:32:0015-16赛季CBA联赛之同曦
日期:2017-12-14 15:28:14黑曼巴
日期:2017-08-10 08:14:342017金鸡报晓
日期:2017-02-08 10:39:42黑曼巴
日期:2016-11-15 15:48:38CU十四周年纪念徽章
日期:2016-11-09 13:19:1015-16赛季CBA联赛之同曦
日期:2016-04-08 18:00:03平安夜徽章
日期:2015-12-26 00:06:30程序设计版块每日发帖之星
日期:2015-12-03 06:20:002015七夕节徽章
日期:2015-08-21 11:06:17IT运维版块每日发帖之星
日期:2015-08-09 06:20:002015亚冠之吉达阿赫利
日期:2015-07-03 08:39:42
3 [报告]
发表于 2011-02-21 08:59 |只看该作者
总结得很不错哦~ lz发的都是好帖啊!

论坛徽章:
36
IT运维版块每日发帖之星
日期:2016-04-10 06:20:00IT运维版块每日发帖之星
日期:2016-04-16 06:20:0015-16赛季CBA联赛之广东
日期:2016-04-16 19:59:32IT运维版块每日发帖之星
日期:2016-04-18 06:20:00IT运维版块每日发帖之星
日期:2016-04-19 06:20:00每日论坛发贴之星
日期:2016-04-19 06:20:00IT运维版块每日发帖之星
日期:2016-04-25 06:20:00IT运维版块每日发帖之星
日期:2016-05-06 06:20:00IT运维版块每日发帖之星
日期:2016-05-08 06:20:00IT运维版块每日发帖之星
日期:2016-05-13 06:20:00IT运维版块每日发帖之星
日期:2016-05-28 06:20:00每日论坛发贴之星
日期:2016-05-28 06:20:00
4 [报告]
发表于 2011-02-21 09:48 |只看该作者
感谢分享
一路征程一路笑 该用户已被删除
5 [报告]
发表于 2011-02-21 09:52 |只看该作者
提示: 作者被禁止或删除 内容自动屏蔽

论坛徽章:
0
6 [报告]
发表于 2011-02-21 13:20 |只看该作者
支持并感谢楼主分享哈

论坛徽章:
0
7 [报告]
发表于 2011-02-25 15:05 |只看该作者
本帖最后由 JackyBsh 于 2011-02-25 16:09 编辑

回复 1# cluter


有不明之处,请教楼主,我参考的内核版本是 2.6.35.4:

实际上,页表在段 brk 开始的地方,也就是占据的空间在符号 “_end” 前,根据下面链接脚本 arch/x86/kernel/vmlinux.lds.S 中片段可以确定这点。

------------------------------------------------------------------------
    . = ALIGN(PAGE_SIZE);
    .brk : AT(ADDR(.brk) - LOAD_OFFSET) {
        __brk_base = .;
        . += 64 * 1024;     /* 64k alignment slop space */
        *(.brk_reservation) /* areas brk users have reserved */
        __brk_limit = .;
    }

    _end = .;
-----------------------------------------------------------------------

问题是:

1 映射到 “_end” 应该就可以了,因为页表应该在 __brk_base 和 _end 之间。那为什么还要在 “_end” 后多映射 MAPPING_BEYOND_END 个字节。根据变量 MAPPING_BEYOND_END 的定义,其确实代表着映射1G内核空间需要的页表要占用的内存大小。或者是因为担心 brk 段预留的空间不足?

2 页表是从 __brk_base 开始建立的,如果这样,映射的最终物理地址是否应该是 $pa(__brk_base) + MAPPING_BEYOND_END,而不是 $pa(_end) + MAPPING_BEYOND_END 呢?

论坛徽章:
0
8 [报告]
发表于 2011-02-26 12:12 |只看该作者
回复 7# JackyBsh


页表虽然在 _brk_base 和 _end之间
但是 这个只是启动时的页表大小---size非常小

RESERVE_BRK(pagetables, INIT_MAP_SIZE)
由代码可以得出INIT_MAP_SIZE小于MAPPING_BEYOND_END,差不多是MAPPING_BEYOND_END的一半

reserve数据段是 给启动时页表映射用的。--->其实基本上也用不到,因为感觉前64k基本上够了。

而 mapping_beyond_end是给 后来建立内存映射页表用的。

后来内核要建立物理内存直接映射的时候,这段区域就不够用了。所以要从_end开始。

在i386上代码比较清晰,没有这么多的reserve段。
现在合并后,确实有点繁琐。。。

话说我也是抛砖引玉,也有很多地方不是时分清晰。

论坛徽章:
0
9 [报告]
发表于 2011-02-26 17:07 |只看该作者
回复 8# cluter

针对您的这句解释:“而 mapping_beyond_end是给 后来建立内存映射页表用的”, 不清楚您所说的后来是否指的是内核第二次建立完善的页面映射?

论坛徽章:
0
10 [报告]
发表于 2011-02-26 17:15 |只看该作者
回复 9# JackyBsh


    是的, 在setup_arch--》Init_memory_mapping函数中 建立物理内存直接映射的页表。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP