linux核心頁表

來源:互聯網
上載者:User

曾 幾何時,我一直被迷惑著,我知道所有進程和所有核心線程共用核心頁表,也就是在頁全域目錄的768項以上的目錄項指向的頁表,我一直以為在建立新的進程的 時候建立新進程的頁全域目錄的時候會連帶的把核心的基礎全域目錄複寫過去,實際上這是合理的,當我看到網上很多文章都這麼說時,我似乎感到一種欣慰:我太有才了!但是當我讀到2.6.17的原始碼時, 夢被打碎了,在pgd_alloc裡面沒有上述的動作,代碼如下:

pgd_t *pgd_alloc(struct mm_struct *mm)
{
int i;
pgd_t *pgd = quicklist_alloc(0, GFP_KERNEL, pgd_ctor);
if (PTRS_PER_PMD == 1 || !pgd)
return pgd;
for (i = 0; i UNSHARED_PTRS_PER_PGD; ++i) {
pmd_t *pmd = pmd_cache_alloc(i);
if (!pmd)
goto out_oom;
paravirt_alloc_pd(__pa(pmd) >> PAGE_SHIFT);
set_pgd(&pgd[i], __pgd(1 + __pa(pmd)));
}
return pgd;
out_oom:
for (i--; i >= 0; i--) {
pgd_t pgdent = pgd[i];
void* pmd = (void *)__va(pgd_val(pgdent)-1);
paravirt_release_pd(__pa(pmd) >> PAGE_SHIFT);
pmd_cache_free(pmd, i);
}
quicklist_free(0, pgd_dtor, pgd);
return NULL;
}
我們看到,僅僅初始化了768之前的頁目錄項,沒有核心頁目錄的蹤跡,怎麼回事呢?網上的那麼多文章的依據又是什麼呢?迷茫中,我想到了版本問題,於是我查閱了2.4的系列核心原始碼,果然是那麼回事:
172 pgd_t *pgd_alloc(struct mm_struct *mm)
{
int i;
pgd_t *pgd = kmem_cache_alloc(pae_pgd_cachep, GFP_KERNEL);
if (pgd) {
unsigned long pmd;
for (i = 0; i USER_PTRS_PER_PGD; i++) {
pmd = __get_free_page(GFP_KERNEL);
if (!pmd)
goto out_oom;
clear_page(pmd);
set_pgd(pgd + i, __pgd(1 + __pa(pmd)));
}
memcpy(pgd + USER_PTRS_PER_PGD,
swapper_pg_dir + USER_PTRS_PER_PGD,
(PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
}
return pgd;
out_oom:
for (i--; i >= 0; i--)
free_page((unsigned long)__va(pgd_val(pgd[i])-1));
kmem_cache_free(pae_pgd_cachep, pgd);
return NULL;
}
看起來比2.6的核心長很多,這麼做合理是合理,但是有必要嗎?使用者進程真的會那麼頻繁的進入核心從而訪問核心嗎?想想malloc庫函數,再想想庫提供使用者io緩衝區,如果你沒有研究過前面的兩個,那麼mmap總該知道吧,為什麼要用到前面的庫函數,而且他們的庫層級實現非常複雜,有自己的一套策略,有何誘惑可以值得庫設計者付出這麼大的代價呢?究其原因就是為了儘可能少的進行系統調用從而進入核心空間,要知道電腦的目的是為人服務,為人服務就是運行使用者的程式,也就是使用者進程,並不是為了讓人去研究作業系統,作業系統核心只是提供服務,進行全域統籌管理,遺憾的是,他和使用者進程是共用
處理器資源的,這就要求它必須在最短的時間內完成自己的任務,全程只需分清一個主次關係,使用者進程為主,核心運行為輔,使用者不求助,核心別插手使用者事務,只有當使用者真正要核心時,核心再挺身而出,這樣就把核心事務拖到了不能再拖為止,於是乎再拷掠前面的問題時我想到了缺頁中斷,下面看看缺頁中斷是怎麼處理的:
asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code)
{
......
if (unlikely(address >= TASK_SIZE)) {
if (!(error_code & 5))
goto vmalloc_fault;
......
vmalloc_fault:
{
......
int index = pgd_index(address);//得到缺頁地址應該所在的頁全域目錄的目錄項索引
pgd_t *pgd, *pgd_k;
pmd_t *pmd, *pmd_k;
pte_t *pte_k;
asm("movl %%cr3,%0":"=r" (pgd));//讀出當前進程的頁全域目錄的位置
pgd = index + (pgd_t *)__va(pgd);//得到具體的對應於缺頁地址的目錄項
pgd_k = init_mm.pgd + index;//swapper_pgd_dir中隊應的目錄項
if (!pgd_present(*pgd_k))//如果swapper_pgd_dir模板中都沒有,準備後事吧
goto no_context;//善後
......
pmd = pmd_offset(pgd, address);//以下的分析方法同上
pmd_k = pmd_offset(pgd_k, address);
if (!pmd_present(*pmd_k))
goto no_context;//善後
set_pmd(pmd, *pmd_k);
pte_k = pte_offset_kernel(pmd_k, address);//核心和使用者進程共用核心頁表,因此以下也就沒有set_pmd(pmd, *pmd_k)之類的了
if (!pte_present(*pte_k))
goto no_context;
return;//最終引起缺頁的地址的MMU元素被建立,訪問重新開始
}
}
以上的分析應該很明了了,在此再小聲說一句,網上的文章只是作者的理解,僅僅可以幫你理解問題,真正解決問題,你還得自己來,比如讀核心,你必須自親自閱讀才能悟道。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.