LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
楼主: westroom

内核页表的建立

[复制链接]
 楼主| 发表于 2004-12-27 17:15:17 | 显示全部楼层
那么内核页表的作用其实就是让内核线程能找到想要的东西了,那么干嘛映射真个物理内存到内核空间,使得有一个896M的物理内存大小限制?这个有什么用?
另外,__pa(addr)不是用来完成线性地址转无理地址吗(只针对内核而言),内核线程干嘛不直接把addr通过pa()转化为无理地址,用内核页表干嘛?
我也觉得我问题真多,自己也在拼命找答案,只是threeseconds太厚道了,止不住要问个明白了,版主见谅哈!
发表于 2004-12-27 19:56:25 | 显示全部楼层
Post by westroom
那么内核页表的作用其实就是让内核线程能找到想要的东西了,那么干嘛映射真个物理内存到内核空间,使得有一个896M的物理内存大小限制?这个有什么用?
另外,__pa(addr)不是用来完成线性地址转无理地址吗(只针对内核而言),内核线程干嘛不直接把addr通过pa()转化为无理地址,用内核页表干嘛?
我也觉得我问题真多,自己也在拼命找答案,只是threeseconds太厚道了,止不住要问个明白了,版主见谅哈!



1.页面表、页表是硬件机制,一旦进入保护模式,cr0的PE位 置位之后就开始启动。硬件是软件的老大,这无论对ring0(内核)还是ring3(用户)的代码都是一样的,引用的地址都会经过分段和分页机制(硬件)的转化。__pa的作用只是在内核需要物理地址的时候才会用到,比如填入cr3中内容是页面表的物理地址,而就需要用它来转化。

2.很佩服threeseconds的厚道和对i386 MM的详细知识。
发表于 2004-12-28 09:19:12 | 显示全部楼层
内核肯定要求可以对整个物理内存进行寻址,以便从全局来掌握整个物理内存的管理,因此映射整个物理内存(如果可能的话)给它,让它当仲裁者;至于896M严格来说也不能说是限制,因为32位地址空间留给内核映射物理内存的只有1G,还要留下128M用于其它映射,这就出现了896M这个分界;大于896小于4G的内存就要进行动态映射,映射到后128M,前面896正常映射;大于4G就要开启PAE,启动三级分页了;当然,对于64位机器,就没有这些麻烦事了,2^64地址空间,够它臭屁一阵子的了:)
对于__pa版大说的对,实际内核应用__pa挺有限的;你想硬件要寻找页目录,必然要有一个物理地址,而保护方式下开启了分页,在程序运行中都是采用虚拟地址,那么要对内存寻址的话,必然要经历从逻辑地址到线性地址再到物理地址的过程,只不过LINUX简化了段的用法,让段都从虚拟地址0开始,这样逻辑地址偏移就等于线性地址了;但是对于页全局目录,页表来说,他们放在内存里面,你首先要找页全局目录,找不到就没法利用分页。如果你不给定物理地址,你怎么能找到它呢?也就是说你总要给硬件一个起点,不能说我给硬件一个虚拟地址,硬件去找页目录吧,可是要找页目录,硬件也得知道它的物理地址在哪啊,这样就用到__pa了,把物理地址装入CR3,以后就都是硬件自己完成的了;还是要结合硬件来理解,版大说得对,硬件是基础。

呵呵,我其实也不是厚道,因为我看书想问题不多,就闷头看;这里看看大家的问题就发现很多事情都没有想过,所以可以让我也沾光能跟着大伙想想问题:)
版大可不要夸我了,我也是菜鸟,理解错误的地方还需要老大指出啊!!!
 楼主| 发表于 2004-12-28 10:31:52 | 显示全部楼层
二位都如此谦虚,小生真觉不如!
讲解的不错,原来pa多用于硬件需要直接访问物理内存的情况,而段式,页式是所有程序都必须走的过程哈。而内核对全部物理内存的映射是为了对系统的一个整体掌握(掌握什么呢?)。
剩下的事情就需要我去看看书,再消化一下二位传授的知识了。:)
发表于 2004-12-28 11:20:15 | 显示全部楼层
掌握如何合理分配动态内存(分配给内核本身固定占有的内存以外的内存)给那些请求的进程函数啊:)
发表于 2004-12-28 18:17:58 | 显示全部楼层
Post by threeseconds
二级分页的话,IA-32把高十位做为页目录索引,中间10位是页表索引,最后12位是OFFSET;那么内核页目录的前768项相当于占位作用,一直是0。比如我找页目录中第800项,那么首先从CR3寄存器找到页目录所在地址,然后找索引为800的项;这些低项就是占着个位置,否则因为是0就删除这些低项的话就无法按照高10位索引找到正确的项。
每个进程都有自己的页目录,页表,即自己的地址空间;也可能进程之间某个页表相同,这意味着共享这块地址区域。
系统运行在内核态,那么需要对内核空间寻址,那么就利用内核页目录,页表寻址;但是对于需要
                                                                                                               ~~~~~~~~
访问某进程地址空间的情况(比如发生系统调用,给该系统调用传递了一个进程地址空间的参
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
数),那么处于内核态的例程就可以访问该进程地址空间的页目录,页表,从而实现寻址。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
但是进程不可以访问内核地址空间,比如如果发生系统调用,给该系统调用传递了一个进程地址空间的参数,而这个参数是在PAGE_OFFSET以上的,那就会引发异常。只有给内核传递PAGE_OFFSET以下的地址参数才合法。
应该说清楚了吧:内核寻址内核空间的时候(>=PAGE_OFFSET),那肯定要用内核页目录,页表了;需要寻址进程地址空间(<AGE_OFFSET),就利用进程页目录,页表。处于用户地址空间的进程是无权直接访问内核空间的,也就无法使用内核页表了。只有通过系统调用,进入内核态执行,这时候才可以访问内核页表。

对于楼上所说的这个我有点不明白,在进行系统调用的时侯难道不会把内核的页目录地址放到cr3寄存器里吗?如果把内核的页目录地址放到cr3寄存器里的话,那内核不就不能访问了用户空间了?可是如果不这样子做的话,那进行系统调用的时候怎么访问到内核空间?
发表于 2004-12-29 11:24:11 | 显示全部楼层
每个进程都是拥有4G地址空间,只是用户态下面无法访问高1G空间;内核空间是被所有进程共享的,那么该进程的页目录表的高项部分就应该是内核页表的内容,只是USER/SUPERVISOR位是0,用户态无法访问而已;CR3寄存器就是该进程的页目录地址,进程从用户态切换到内核态,CR3没变,但是却拥有可以访问高项的内核空间的权限了,这样发生系统调用的时候,内核也直接访问当前进程的用户空间,使用的虚拟地址也和当前进程处于用户空间时候使用的虚拟地址是一样的。
下面这段代码是get_pgd_slow(pgd_alloc调用)中的:
memcpy(pgd + USER_PTRS_PER_PGD,
        swapper_pg_dir + USER_PTRS_PER_PGD,
(PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
pgd_alloc可以为新进程建立一个页全局目录,swapper_pg_dir是内核页全局目录地址,USER_PTRS_PER_PGD是页全局目录中用户空间所占的表项数目,这里应该可以看到把内核页目录复制到进程的页目录的高项部分了。
由此看进程应该是不会直接使用内核页表,都是用的复制品。

前面说得概念有点混淆,而且我的理解也很片面,还请兄弟继续指正。
发表于 2004-12-29 13:18:17 | 显示全部楼层
太佩服了
能搞得那么清楚,我现在在看内存管理,看的稀里糊涂的
问题一大堆,而且很多东西根本窜不起来
发表于 2004-12-29 14:51:40 | 显示全部楼层
很多地方我说得也不准确,我也是看了一些皮毛就到这里来瞎说一通,希望有不对的地方大家指正,有问题大家也一起讨论讨论!!
我觉得一个人单干还是有点难度,有时候几个人一起,有问题大家一起考虑,讨论,比较有气氛,进步的也会比较快:)
 楼主| 发表于 2004-12-30 11:18:28 | 显示全部楼层
很想弄明白在用户程序中,突然执行到一句系统调用的时候,为什么就可以访问页表目录的高项了呢?是不是在段式映射那里进行的这种转换,我想了想页映射没有这种控制吧?
您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表