|
最近在看《深入理解linux内核》这本书,书中的内核版本是2.2.14,在内存管理部分有个疑问:
在内核源码\include\asm-i386\Page.h中有这样几个宏:
#define __pa(x) ((unsigned long)(x)-PAGE_OFFSET)
#define __va(x) ((void *)((unsigned long)(x)+PAGE_OFFSET))
#define MAP_NR(addr) (__pa(addr) >> PAGE_SHIFT)
分别用于实现内核空间中线性地址和物理地址之间的转换,MAP_NR(addr)则是用来获得线性地址addr所对应的页框在MEM_MAP中的索引。
从PAGE_OFFSET开始的线性地址范围(这个线性范围通常为1个G,即PAGE_OFFSET=0xc0000000)必须要能够映射整个物理内存。但是通常实际内存并没有1个G这么大,假设物理内存有256M,那么剩余的700多M的线性地址范围linux可以用来映射非连续内存区,当用vmalloc()申请内存区时,内核分配非连续内存区,返回这段内存区的起始的线性地址,在vmalloc()内部改变了一部分页表,使得我们获得的线性地址可以映射新获得的非连续的内存区。
我的第一个疑问是:
对于可以用来映射非连续内存区的线性地址,用__pa()宏的方法为什么也能获得正确的物理地址?
假设这个线性地址为address, address-0xc0000000得到的值是不是已经超过了实际的物理内存的大小?疑惑中,请各位指点
我的第二个疑问是:
在内核中我们获得内存通常会用到get_free_page(),kmalloc(),vmalloc() 等函数,但是这些函数在根本上其实还是调用基于伙伴算法的__get_free_pages()来获得空闲的内存块,同样以上三个函数释放内存时根本上也调用了基于伙伴算法的free_pages_ok()函数。可是在free_pages_ok()函数里,仅仅是完成了类似注册该块为空闲块,并根据伙伴算法作了一些相应的处理,而对原来这个内存块里存放的内容并没有作任何处理,比如说清零等,那样的话,下一个请求到来,如果获得了这个块,岂不是可以窃取这个块里原来的内容?不知道linux里在这一点上是不是有别的处理,请教各位
谢谢! |
|