<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                # 五、 來源:[JOS學習筆記(五)](http://blog.csdn.net/roger__wong/article/details/8656339) > 神說、內存之間要有映射、將地址空間分為虛實。 > 神就造出兩級頁表、將變換前的地址、變換后的地址分開了.事就這樣成了。 > 有晚上、有早晨、是第二日。 來到了lab2,內存管理,該實驗分為兩部分,第一部分為物理內存管理,第二部分為虛擬內存管理,本篇先描述lab1。 做本章實驗一定頭腦中要時刻清晰的記住兩個內存分布圖:物理內存分布圖以及虛擬內存分布圖。 物理內存的分布在前面的筆記中有介紹,這里拷貝過來: ``` +------------------+ <- 0xFFFFFFFF (4GB) | 32-bit | | memory mapped | | devices | | | /\/\/\/\/\/\/\/\/\/\ /\/\/\/\/\/\/\/\/\/\ | | | Unused | | | +------------------+ <- depends on amount of RAM | | | | | Extended Memory | |------------------| | kernnel | +------------------+ <- 0x00100000 (1MB) | BIOS ROM | +------------------+ <- 0x000F0000 (960KB) | 16-bit devices, | | expansion ROMs | +------------------+ <- 0x000C0000 (768KB) | VGA Display | +------------------+ <- 0x000A0000 (640KB) | | | Low Memory | |------------------| <-0x00010000 (elf herader here!) |------------------| <-0x00007c00 (boot loader here!) | bootmain stack | +------------------+ <- 0x00000000 ``` 虛擬內存分布參見memlayout.h文件,這里也拷貝過來: ![](https://box.kancloud.cn/2015-12-24_567b6e7643c56.jpg) 好,記住這兩個圖然后開始做實驗。 ## 1、實驗內容 實驗內容很簡單,只是讓你完成下列幾個函數 ``` boot_alloc() mem_init() page_init() page_alloc() page_free() ``` mem_init()會調用你寫的函數,然后再調用check_page_free_list和check_page_alloc兩個函數來判斷你完成的函數的邏輯對不對,基本上通過驗證就沒問題了。 ## 2、原理。 JOS使用Page數據結構來管理內存,一個Page代表一個PGSIZE(4K)大小的物理頁面,Page數據結構的定義在memlayout.h中,共有兩個域,第一個域是pp_link,指向下一個空閑Page結構的指針,第二個域是一個short整形,代表當前此物理頁面的引用次數,若為0則是沒有被引用也就是空閑頁面。 其次使用free_page_list維護一個空閑物理內存的鏈表,free_page_list本身就是一個Page指針,然后通過Page結構體里面的pp_link域構成空閑鏈表。 再次一個Page代表4K,在pmap.c中的i386_memory_detect函數中檢測內存后,使用總物理內存/4k得到所需要的Page數量,賦值給npages,換句話說npages代表所需Page結構體的數量。 最后所有Page在內存(物理內存)中的存放是連續的,存放于pages處,可以通過數組的形式訪問各個Page,而pages緊接于end[]符號之上,end符號是編譯器導出符號,其值約為kernel的bss段在內存(虛擬內存)中的地址+bss段的段長,對應物理和虛擬內存布局也就是在kernel向上的緊接著的高地址部分連續分布著pages數組。 除此之外JOS提供page2pa,pa2page等函數可以進行Page數據結構的指針向物理地址的轉換,或反轉換等。 ## 3、具體函數實現 首先被調用的是boot_alloc(),它要在什么都沒做好的情況下開辟出n字節的空閑空間,并返回其首地址。 做法很簡單,end符號向上均為未使用空間,只要返回這些空間就行。 首先將end符號向上和4K字節對齊(JOS已經幫我們完成),然后將這個地址(也就是nextfree)加上你要分配的空間并依然4K字節對齊,接著返回原先的nextfree即可。 ``` char* result; result=nextfree; nextfree+=ROUNDUP(n,PGSIZE); return result; ``` 然后完成mem_init()中的部分代碼,可以看到mem_init()中首先檢查可用內存大小,然后調用boot_alloc()分配了一個頁面給kern_pgdir,這個在part2中會用,現在沒啥用。 接下來需要我們給pages分配空間。通過以上原理分析,很容易得出代碼: ``` pages=(struct Page*)boot_alloc(npages*sizeof(struct Page); ``` 接著完成page_init()。 在page_init()里系統首先給我們初始化了pages數組以及page_free_list,可以看到這個page_free_list指向了所有的Page結構,換句話說此時認為所有的頁面都是空閑可分配的,這當然是不對的,所以就要從中把一些我們已經用的內存頁面從中剔除出去,這包括0地址向上的第一個頁面(包括IDT等),IO hole(0xA0000--0x100000,包括vga display ,bios等),kernel地址之上的部分(kernel本身+kern_pgdir+pages)。巧合的是,IO hole,和kernel之上部分是連續的地址,因為kernel就加載在0x100000處,所以其實只需要剔除兩塊地址,第一塊是0地址開始的第一個頁面,第二塊就是io hole開始的向上的一組連續的頁面。 分析一下page_free_list的代碼邏輯,不難發現這個鏈表是從pages數組的末尾開始從高地址指向低地址,所以我們先計算出要剔除的Page的地址,然后通過指針操作剔除即可。 ![](https://box.kancloud.cn/2015-12-24_567b6e765c268.jpg) 首先剔除第一個頁面,只需讓第二個頁面(下標為1)的pp_link域指向空,因為原本其指向的是第一個頁面,而第一個頁面的pp_link域指向空,也等價與pages[1].pp_link=pages[0].pp_link 其次剔除一組連續頁面,使用pgstart和pgend代表這組連續地址空間的首尾所在的Page結構(所謂首是低地址,所謂尾是高地址)。 首地址也就是IOPHYSMEM所在地址,注意IOPHYSMEM已經是物理地址了,所以只需要使用pa2page得到Page結構即可。 pgend是較高位的地址,首先將end符號地址轉化成物理地址(-KERNBASE),然后再加上剛才分配的kern_pgdir(一個PGSIZE)和pages數組所占用的空間即可。當然更嚴謹點應該4K字節對齊的,不過不對其也能落在正確的4K范圍內,不影響程序正確性。 其次注意到pgstart和pgend這兩個Page也是要剔除的,所以需要找到pgend的上一個Page,和pgstart的下一個Page,這兩個Page應該是空閑的。因為所有Page的組織是按數組進行組織,所以只需要進行+1和-1的地址操作即可。 接著改變pp_link域,跳過中間的區域即可。 接下來是很簡單的page_alloc()。 代碼邏輯很簡單,從page_free_list頭剔除一個Page,然后改變page_free_list使其為其pp_link即可。 ![](https://box.kancloud.cn/2015-12-24_567b6e767351e.jpg) 接著是Page_free,直接上圖: ![](https://box.kancloud.cn/2015-12-24_567b6e7682f49.jpg) 至此part1結束: ![](https://box.kancloud.cn/2015-12-24_567b6e7692e66.jpg) 一點感想: 在用戶態編程反而覺得內存的分配是理所當然的,然而在OS內核中寫相關代碼時,產生的一種很奇妙的感覺就是這個過程是由程序員自己掌控的,并且分配的結果會反而影響后面的代碼邏輯。 What an amazing experience !
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看