日期:2014-05-16  浏览次数:20781 次

《linux 内核完全剖析》上帝为什么是右移20,而不是22! dir = (unsigned long *) ((from>>20) & 0xffc)

在memory.c里面有这么一段代码。为了其中的一句话,让我内牛满面啊!

 dir = (unsigned long *) ((from>>20) & 0xffc)



int free_page_tables(unsigned long from,unsigned long size)
{
    unsigned long *pg_table;
    unsigned long * dir, nr;

    if (from & 0x3fffff)
        panic("free_page_tables called with wrong alignment");
    if (!from)
        panic("Trying to free up swapper memory space");
    size = (size + 0x3fffff) >> 22;
    dir = (unsigned long *) ((from>>20) & 0xffc); /* _pg_dir = 0 */
    for ( ; size-->0 ; dir++) {
        if (!(1 & *dir))
            continue;
        pg_table = (unsigned long *) (0xfffff000 & *dir);
        for (nr=0 ; nr<1024 ; nr++) {
            if (*pg_table) {
                if (1 & *pg_table)
                    free_page(0xfffff000 & *pg_table);
                else
                    swap_free(*pg_table >> 1);
                *pg_table = 0;
            }
            pg_table++;
        }
        free_page(0xfffff000 & *dir);
        *dir = 0;
    }
    invalidate();
    return 0;

}


搞定这段代码如果分页机制不过关,是不能真正领悟其精髓的 

<注释>的讲80x86的时候有讲分页机制

http://blog.csdn.net/cinmyheart/article/details/24354735

Moder operating system 讲的memory management

http://blog.csdn.net/cinmyheart/article/details/24888847




 dir = (unsigned long *) ((from>>20) & 0xffc); /* _pg_dir = 0 */

from是个线性地址,如果右移22bit,那么刚好可以得到目录号,wait!有一个极具“陷阱” 的概念,我看了两本书上都没有讲,MOS不讲还情有可原,理论高度比较好,但是<注释> 没讲,让我觉得有点坑爹了。

花了好长时间才理清楚

这里的31~22 bit存放的是页目录的目录号,主内存区这部分必须从1开始,不能从0开始,换句话说,就是目录号(注意这个概念),他是从1开始的,而不是0

目录号指向页目录的指针,之间有一个联系,这个联系基于一个事实,就是系统初始化完成之后,地址0x00开始存放的是内存页目录表GDT!





那么页目录号对应页目录地址的话,仅仅只需要把页目录号左移两位,或者,右移20位,并且& 0xffc 那么就可以得到指向页目录的指针(不指向内核段内存页目录表)

那么最小的页目录号是1,对应的地址就是0x0004(在这之前的4个表供内核使用,即指向内核的4M区域)

注意,右移22位即可得到页目录号,而右移20位并且&0xffc再强制转换成指针,即可得到指向主内存区域的页表目录指针!