1. <var id="fe6gj"></var>

    <rp id="fe6gj"><nav id="fe6gj"></nav></rp>

    <noframes id="fe6gj"><cite id="fe6gj"></cite>

    <ins id="fe6gj"><button id="fe6gj"><p id="fe6gj"></p></button></ins>
    1. <tt id="fe6gj"><i id="fe6gj"><sub id="fe6gj"></sub></i></tt>
        始創于2000年 股票代碼:831685
        咨詢熱線:0371-60135900 注冊有禮 登錄
        • 掛牌上市企業
        • 60秒人工響應
        • 99.99%連通率
        • 7*24h人工
        • 故障100倍補償
        您的位置: 網站首頁 > 幫助中心>文章內容

        深入理解Linux內存映射機制 (3)

        發布時間:  2012/8/15 18:18:47

        向了第768個表項。

        然后函數開始一個循環即開始填充從768到1024這256個目錄項的內容。
        one_md_table_init()函數根據pgd找到指向的pmd表。

        它同樣在mm/init.c中定義:
        static pmd_t * __init one_md_table_init(pgd_t *pgd)
        {
        pmd_t *pmd_table;

        #ifdef CONFIG_X86_PAE
        pmd_table = (pmd_t *) alloc_bootmem_low_pages(PAGE_SIZE);
        set_pgd(pgd, __pgd(__pa(pmd_table) | _PAGE_PRESENT));
        if (pmd_table != pmd_offset(pgd, 0))
        BUG();
        #else
        pmd_table = pmd_offset(pgd, 0);
        #endif
        return pmd_table;
        }
        可以看出, 如果內核不啟用PAE選項, 函數將通過 pmd_offset返回pgd的地址。因為linux的二級映射模型,本來就是忽略pmd中間目錄表的。
        接著又個判斷語句:
        >> if (pfn >= max_low_pfn)
        >> continue;
        這個很關鍵, max_low_pfn代表著整個物理內存一共有多少頁框。 當pfn大于max_low_pfn的時候,表明內核已經把整個物理內存都映射到了系統空間中, 所以剩下有沒被填充的表項就直接忽略了。因為內核已經可以映射整個物理空間了, 沒必要繼續填充剩下的表項。
        緊接著的第2個for循環,在linux的3級映射模型中,是要設置pmd表的, 但在2級映射中忽略, 只循環一次,直接進行頁表pte的設置。
        >> address = pfn * PAGE_SIZE PAGE_OFFSET;
        address是個線性地址, 根據上面的語句可以看出address是從0xc000000開始的,也就是從內核空間開始,后面在設置頁表項屬性的時候會用到它.
        >> pte = one_page_table_init(pmd);
        根據pmd分配一個頁表, 代碼同樣在mm/init.c中:
        static pte_t * __init one_page_table_init(pmd_t *pmd)
        {
        if (pmd_none(*pmd)) {
        pte_t *page_table = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE);
        set_pmd(pmd, __pmd(__pa(page_table) | _PAGE_TABLE));
        if (page_table != pte_offset_kernel(pmd, 0))
        BUG();
        return page_table;
        }
        return pte_offset_kernel(pmd, 0);
        }
        pmd_none宏判斷pmd表是否為空, 如果為空則要利用alloc_bootmem_low_pages分配一個4k大小的物理頁面。 然后通過set_pmd(pmd, __pmd

        (__pa(page_table) | _PAGE_TABLE));來設置pmd表項。page_table顯然屬于線性地址,先通過__pa宏轉化為物理地址,在與上_PAGE_TABLE宏,此時它們還是無符號整數,在通過__pmd把無符號整數轉化為pmd類型,經過這些轉換, 就得到了一個具有屬性的表項, 然后通過set_pmd宏設置pmd表項.

        接著又是一個循環,設置1024個頁表項。

        is_kernel_text函數根據前面提到的address來判斷address線性地址是否屬于內核代碼段,它同樣在mm/init.c中定義:

        static inline int is_kernel_text(unsigned long addr)
        {
        if (addr >= (unsigned long)_stext && addr <= (unsigned long)__init_end)
        return 1;
        return 0;
        }

        _stext, __init_end是個內核符號, 在內核鏈接的時候生成的, 分別表示內核代碼段的開始和終止地址.

        如果address屬于內核代碼段, 那么在設置頁表項的時候就要加個PAGE_KERNEL_EXEC屬性,如果不是,則加個PAGE_KERNEL屬性.

        #define _PAGE_KERNEL_EXEC \
        (_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED)

        #define _PAGE_KERNEL \
        (_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_NX)

        最后通過set_pte(pte, pfn_pte(pfn, PAGE_KERNEL));來設置頁表項, 先通過pfn_pte宏根據頁框號和頁表項的屬性值合并成一個頁表項值,

        然戶在用set_pte宏把頁表項值寫到頁表項里。
        當pagetable_init()函數返回后,內核已經設置好了內核頁表,緊著調用load_cr3(swapper_pg_dir);
        #define load_cr3(pgdir) \
        asm volatile("movl %0,%%cr3": :"r" (__pa(pgdir)))
        將控制swapper_pg_dir送入控制寄存器cr3. 每當重新設置cr3時, CPU就會將頁面映射目錄所在的頁面裝入CPU內部高速緩存中的TLB部分. 現在內存中(實際上是高速緩存中)的映射目錄變了,就要再讓CPU裝入一次。由于頁面映射機制本來就是開啟著的, 所以從這條指令以后就擴大了系統空間中有映射區域的大小, 使整個映射覆蓋到整個物理內存(高端內存)除外. 實際上此時swapper_pg_dir中已經改變的目錄項很可能還在高速緩存中, 所以還要通過__flush_tlb_all()將高速緩存中的內容沖刷到內存中,這樣才能保證內存中映射目錄內容的一致性。
        3.4 對如何構建頁表的總結
        通過上述對pagetable_init()的剖析, 我們可以清晰的看到, 構建內核頁表, 無非就是向相應的表項寫入下一級地址和屬性。 在內核空間保留著一部分內存專門用來存放內核頁表.當cpu要進行尋址的時候,無論在內核空間,還是在用戶空間, 都會通過這個頁表來進行映射。對于這個函數, 內核把整個物理內存空間都映射完了, 當用戶空間的進程要使用物理內存時, 豈不是不能做相應的映射了? 其實不會的, 內核只是做了映射, 映射不代表使用, 這樣做是內核為了方便管理內存而已。

        四. 實例分析映射機制
        4.1示例代碼
        通過前面的理論分析,我們通過編寫一個簡單的程序, 來分析內核是如何把線性地址映射到物理地址的。
        [root@localhost temp]# cat test.c
        #include <stdio.h>
        void test(void)
        {
        printf("hello, world.\n");
        }
        int main(void)
        {
        test();
        }
        這段代碼很簡單, 我們故意要main調用test函數, 就是想看下test函數的虛擬地址是如何映射成物理地址的。
        4.2 段式映射分析
        我們先編譯, 在反匯編下test文件
        [root@localhost temp]# gcc -o test test.c
        [root@localhost temp]# objdump -d test
        08048368 <test>:
        8048368: 55 push %ebp
        8048369: 89 e5 mov %esp,%ebp
        804836b: 83 ec 08 sub $0x8,%esp
        804836e: 83 ec 0c sub $0xc,%esp
        8048371: 68

        億恩科技地址(ADD):鄭州市黃河路129號天一大廈608室 郵編(ZIP):450008 傳真(FAX):0371-60123888
           聯系:億恩小凡
           QQ:89317007
           電話:0371-63322206


        本文出自:億恩科技【www.endtimedelusion.com】

        服務器租用/服務器托管中國五強!虛擬主機域名注冊頂級提供商!15年品質保障!--億恩科技[ENKJ.COM]

      1. 您可能在找
      2. 億恩北京公司:
      3. 經營性ICP/ISP證:京B2-20150015
      4. 億恩鄭州公司:
      5. 經營性ICP/ISP/IDC證:豫B1.B2-20060070
      6. 億恩南昌公司:
      7. 經營性ICP/ISP證:贛B2-20080012
      8. 服務器/云主機 24小時售后服務電話:0371-60135900
      9. 虛擬主機/智能建站 24小時售后服務電話:0371-60135900
      10. 專注服務器托管17年
        掃掃關注-微信公眾號
        0371-60135900
        Copyright© 1999-2019 ENKJ All Rights Reserved 億恩科技 版權所有  地址:鄭州市高新區翠竹街1號總部企業基地億恩大廈  法律顧問:河南亞太人律師事務所郝建鋒、杜慧月律師   京公網安備41019702002023號
          0
         
         
         
         

        0371-60135900
        7*24小時客服服務熱線

         
         
        av不卡不卡在线观看_最近2018年中文字幕_亚洲欧美一区二区三区_一级A爱做片免费观看国产_日韩在线中文天天更新_伊人中文无码在线