关于内核页表和进程页表的一个问题
昨天回復了一封電子郵件,有朋友問個問題很有代表性,內核初始化時會將896M前的物理頁面作一一映射,那么用戶進程分配到896M前的頁面建立用戶映射時是否要清除內核的一一映射。
關于這個問題,我的前面的文章已經有了解釋,但是不甚詳細,現在通過一個例子詳細解釋一下。實際上并不需要清除內核的一一映射,內核的一一映射只有內核自己使用,而且帶來了很多的方便,內核巧妙的通過一一映射快速的執行內核路徑,其實內核的一一映射也只有內核自己知道,用戶進程根本涉及不到,內核只要管理好自己的內存沒有什么是不可以的。頁面的頁表映射是硬件MMU的機制,而OS內核中擁有的是內存管理機制,二者并不沖突,它們都是獨立的機制,并且層次不同,完全可以獨立存在,比如你可以在沒有MMU的嵌入式設備上實現復雜的內存管理,同時你也可以在同一個硬件MMU下實現不同的內存管理,比如windows和linux的就不同,我的觀點大致總結如下(缺漏的部分前面的文章中有):在linux中內核一般不會介入用戶的策略,它只是提供機制,向上就到系統調用接口為止,它沒有upcall接口;只要用戶不會訪問內核,內核不會隨意訪問用戶內存就不會有沖突,用戶是難纏的,而且行為是不確定的,內核的行為是確定的,用戶顯然不能訪問內核內存,但是內核卻可以訪問用戶內存,然而內核十分清楚自己擁有哪些內存,比如初始化的時候將896以下頁面作了一一映射,可是內核不一定用得了那么多,當用戶進程需要內存時,完全可以從還在伙伴系統的512M處拽一個頁面分配之并且映射到用戶空間同時保留著內核的一一映射,這時這個512M處的頁面已經從伙伴系統脫離了,內核如果這時也需要內存是不會被分配到該頁面的,這樣就不會有沖突,如果該頁面本來就由內核所使用,那么它就不會在伙伴系統也不可能分配到用戶進程,這么來說也不會有沖突,linux的內存管理和硬件的 MMU是兩碼事,如果說有聯系那就是映射,影射僅僅是一個紐帶和一個適配器而已。
下面我就通過一個例子來說明,當然要寫內核模塊了,我的機器是512M內存,少于896M,也就是全部作了一一映射。我們首先執行以下命令得到insmod程序的一些信息,因為模塊加載是在insmod進程的上下文中:
[root@zhaoya ~]#objdump -d /sbin/insmod
...
08048ab0 <.fini>:
8048ab0: 55 push %ebp
8048ab1: 89 e5 mov %esp,%ebp
8048ab3: 53 push %ebx
...//0xcebe0000
我們看到進程地址空間0x8048ab3處是53,我們如果直接訪問0x8048ab3,那么得到的就是53,這是顯然的,但是我們還可以得到0x8048ab3所在頁面的內核一一映射地址,然后訪問那個地址看是不是還是53,如果是,那么就說明用戶頁面可能存在兩份映射,接下來寫一個模塊:
#include
#include
#include
#include
#include
#include
static __init int test_init(void)
{
char * user_addr = (char *)0x8048ab3; //常規訪問這個地址
printk("%x/n",*str);
struct page *page;
int n = get_user_pages(current, current->mm, user_addr, 1, 0, 1,&page,NULL);
printk("count:%d/n",n);
if(n>0)
{
unsigned long addr = page_address(page);
printk("address:%X/n",addr);
unsigned char * p = (unsigned char *)(address + user_addr&0xfff) ;//最后加入偏移
printk("%x/n",*p); //按照內核一一映射訪問頁面的內核地址
}
return 0;
}
static __exit void test_exit(void)
{
return ;
}
module_init(test_init);
module_exit(test_exit);
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("Zhaoya");
MODULE_DESCRIPTION("kernel map");
MODULE_VERSION("Ver 0.1");
我們實在沒有必要用cr3得到頁目錄,然后用二級或者三級乃至多級頁面映射的方式去得到頁面,那是非常復雜的,而且和體系結構相關,如果非要那樣做的話首先你必須熟悉你的機器,其次還要熟悉C語言,幸運的是,內核提供了get_user_pages這個函數,我們可以輕而易舉的根據虛擬地址得到頁面。結果當然顯而易見了,兩次打印都是53,如果覺得不保險可以多試幾個虛擬地址。
實際上一個頁面保持多個映射并不是稀罕事,原因還是前面說的,內存管理和MMU管理是兩碼事。比如共享內存頁面就可能保持多個映射。
?本文轉自 dog250 51CTO博客,原文鏈接:http://blog.51cto.com/dog250/1273945
總結
以上是生活随笔為你收集整理的关于内核页表和进程页表的一个问题的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 魔兽世界怀旧服魔精有什么用
- 下一篇: 用键盘来操纵鼠标指针(鼠标损坏时的应急措