首页 > 代码库 > 《linux 内核完全剖析》上帝为什么是右移20,而不是22! dir = (unsigned long *) ((from>>20) & 0xffc)
《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再强制转换成指针,即可得到指向主内存区域的页表目录指针!