日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

关于内核页表和进程页表的一个问题

發(fā)布時間:2023/12/31 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 关于内核页表和进程页表的一个问题 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

昨天回復(fù)了一封電子郵件,有朋友問個問題很有代表性,內(nèi)核初始化時會將896M前的物理頁面作一一映射,那么用戶進程分配到896M前的頁面建立用戶映射時是否要清除內(nèi)核的一一映射。

關(guān)于這個問題,我的前面的文章已經(jīng)有了解釋,但是不甚詳細,現(xiàn)在通過一個例子詳細解釋一下。實際上并不需要清除內(nèi)核的一一映射,內(nèi)核的一一映射只有內(nèi)核自己使用,而且?guī)砹撕芏嗟姆奖?#xff0c;內(nèi)核巧妙的通過一一映射快速的執(zhí)行內(nèi)核路徑,其實內(nèi)核的一一映射也只有內(nèi)核自己知道,用戶進程根本涉及不到,內(nèi)核只要管理好自己的內(nèi)存沒有什么是不可以的。頁面的頁表映射是硬件MMU的機制,而OS內(nèi)核中擁有的是內(nèi)存管理機制,二者并不沖突,它們都是獨立的機制,并且層次不同,完全可以獨立存在,比如你可以在沒有MMU的嵌入式設(shè)備上實現(xiàn)復(fù)雜的內(nèi)存管理,同時你也可以在同一個硬件MMU下實現(xiàn)不同的內(nèi)存管理,比如windows和linux的就不同,我的觀點大致總結(jié)如下(缺漏的部分前面的文章中有):在linux中內(nèi)核一般不會介入用戶的策略,它只是提供機制,向上就到系統(tǒng)調(diào)用接口為止,它沒有upcall接口;只要用戶不會訪問內(nèi)核,內(nèi)核不會隨意訪問用戶內(nèi)存就不會有沖突,用戶是難纏的,而且行為是不確定的,內(nèi)核的行為是確定的,用戶顯然不能訪問內(nèi)核內(nèi)存,但是內(nèi)核卻可以訪問用戶內(nèi)存,然而內(nèi)核十分清楚自己擁有哪些內(nèi)存,比如初始化的時候?qū)?96以下頁面作了一一映射,可是內(nèi)核不一定用得了那么多,當(dāng)用戶進程需要內(nèi)存時,完全可以從還在伙伴系統(tǒng)的512M處拽一個頁面分配之并且映射到用戶空間同時保留著內(nèi)核的一一映射,這時這個512M處的頁面已經(jīng)從伙伴系統(tǒng)脫離了,內(nèi)核如果這時也需要內(nèi)存是不會被分配到該頁面的,這樣就不會有沖突,如果該頁面本來就由內(nèi)核所使用,那么它就不會在伙伴系統(tǒng)也不可能分配到用戶進程,這么來說也不會有沖突,linux的內(nèi)存管理和硬件的 MMU是兩碼事,如果說有聯(lián)系那就是映射,影射僅僅是一個紐帶和一個適配器而已。

下面我就通過一個例子來說明,當(dāng)然要寫內(nèi)核模塊了,我的機器是512M內(nèi)存,少于896M,也就是全部作了一一映射。我們首先執(zhí)行以下命令得到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,我們?nèi)绻苯釉L問0x8048ab3,那么得到的就是53,這是顯然的,但是我們還可以得到0x8048ab3所在頁面的內(nèi)核一一映射地址,然后訪問那個地址看是不是還是53,如果是,那么就說明用戶頁面可能存在兩份映射,接下來寫一個模塊:

#include

#include

#include

#include

#include

#include

static __init int test_init(void)

{

char * user_addr = (char *)0x8048ab3; //常規(guī)訪問這個地址

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); //按照內(nèi)核一一映射訪問頁面的內(nèi)核地址

}

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得到頁目錄,然后用二級或者三級乃至多級頁面映射的方式去得到頁面,那是非常復(fù)雜的,而且和體系結(jié)構(gòu)相關(guān),如果非要那樣做的話首先你必須熟悉你的機器,其次還要熟悉C語言,幸運的是,內(nèi)核提供了get_user_pages這個函數(shù),我們可以輕而易舉的根據(jù)虛擬地址得到頁面。結(jié)果當(dāng)然顯而易見了,兩次打印都是53,如果覺得不保險可以多試幾個虛擬地址。

實際上一個頁面保持多個映射并不是稀罕事,原因還是前面說的,內(nèi)存管理和MMU管理是兩碼事。比如共享內(nèi)存頁面就可能保持多個映射。


?本文轉(zhuǎn)自 dog250 51CTO博客,原文鏈接:http://blog.51cto.com/dog250/1273945


總結(jié)

以上是生活随笔為你收集整理的关于内核页表和进程页表的一个问题的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。