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