青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

天衣有縫

冠蓋滿京華,斯人獨憔悴~
posts - 35, comments - 115, trackbacks - 0, articles - 0
   :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理

 

8課:內存管理    下載源代碼

 

聲明:轉載請保留:

譯者:http://www.shnenglu.com/jinglexy

原作者:xiaoming.mo at skelix dot org

MSN & Email: jinglexy at yahoo dot com dot cn

 

 

目標

 

抱歉,其實還沒有實現。在任務分配獨立的4G地址空間上調試失敗了,現在只使能了分頁機制,頁異常。大量的工作未實現,有興趣的同學可以搜索buddyslab的相關資料,經典的內存管理算法。


分頁

 

386處理器的內存管理單元可以實現任務獨立地址空間,任務間內存保護。每個任務可以擁有獨立的4G虛擬地址空間。內存映射是內存管理很重要的一步,可以分為兩部分:分段和分頁。前面的課程中已經討論過分段機制了,通過分段可以隔開不同的代碼,數據,堆棧等;分頁單元把虛擬地址映射成物理地址,還可以用來實現虛擬內存(和硬盤分區進行交換),現在我們來了解一下它。

 

對于每個任務,我們無法分配4G的物理內存,所以使用了一些機制來管理內存:及虛擬內存機制。該機制有處理器的分頁部分來實現,首先我們將內存分成一些塊,每個塊大小為4k,通常我們稱之為一個頁幀。操作系統通過頁目錄和頁表來管理這些頁幀。頁目錄是相當于第一級頁表,其中的每一項再管理一個下級頁表。(更詳細過程請參考intelIA 32/64手冊)

當分頁機制開啟時,處理器把任務中的虛擬地址轉換成物理地址,步驟如下:
1.
查找段選擇子在GDT LDT 中的描述符,做一些權限檢查,看看能否訪問

2.以描述符中的基址相加頁目錄基址得到一個線性地址

3.在頁表中索引虛擬地址所對應的頁表項,得到頁地址

4.查找偏移得到實際物理地址。

如果實際物理頁不存在(可能交換到硬盤中去了),則引發異常,可以在這個異常里面做想要做的事情(加載硬盤中的交換頁,或者kill這個程序:Segment Fault,等等)

處理器使用的頁目錄或者頁表,都是由32 位的項組成:

頁目錄項:

 31                    12    11    9    876   5   43    2     1     0

┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓

┃   指向頁表的物理地址  ┃ 用戶定義 ┃  X  ┃ A┃ X ┃ U/S┃ R/W┃ P ┃

┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛

 

頁表項:

 31                    12    11    9   87  6  5   43    2     1     0

┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓

┃   指向頁幀的物理地址  ┃ 用戶定義 ┃ X┃D┃ A┃ X ┃ U/S┃ R/W┃ P ┃

┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛

 

從上面可以知道,頁目錄項和頁表項的結構很類似,下面逐個說明一下其中的域:

 

Bit  0

P

存在位(present),為0 表示該頁幀或頁表不在內存中。如果訪問該項將發生異常。

Bit  1

R/W

表示頁表或頁幀指向的內存只讀(=0),或可寫(=1

Bit  2

U/S

表示頁表或頁幀的權限,當特權級為0時,只有ring02的特權級可以訪問它,否則所有的ring3任務都可以訪問。這個域非常重要。

Bits 3, 4, (6), 7, 8

X

Intel 保留位,設置為0就行了

Bit  5

A

該頁是否已訪問

Bits 9-11

用戶定義

我們使用第11位,表示該頁幀是否被交互到硬盤上了

 

頁目錄的每一項:即頁表的物理地址,它的高20 位地址表示有個頁幀的起始地址,正好和4k對齊。2^20可以表示1M范圍,每個頁幀大小是4k,所以可以索引1M * 4K地址空間。頁目錄項中還有一個D 位,它用來表示一個頁幀是否已修改,linux用它來表示一個頁面釋放是臟頁面,這個位非常有用,當一個頁幀交換到硬盤上后,如果該頁幀還沒有被修改,而且是已經從硬盤交換出來的,則簡單取消以后的交換。

 

為了將邏輯地址轉換成物理地址,邏輯地址被分成3 部分:

Bits 31-22

頁目錄項的索引下標,由它可以得到頁表的物理地址

Bits 21-12

頁表項的索引下標,由它可以得到頁幀的物理地址

Bits 11-0

相對頁幀起始地址的偏移

 

舉例來說,我們有一個邏輯地址:0x3E837B0A。前提條件:CR3寄存器指向的頁目錄地址是 0x0005C000,這個寄存器存儲了當前頁目錄所使用的頁幀的物理地址,通常也叫做 PDBR

 

先取它的高10位, 就是0x0FA,由它可以索引到頁目錄的第0x0FA項,我們取得這一項的值,假設得到的地址值是0x0003F000。然后我們取虛擬地址的中間10位,就是0x037,再取出0x0003F000指向頁幀的第0x037項的值,假設是0x0001B000。這個地址就是我們要找的虛擬地址對應的物理地址的頁幀的起始地址,最后加上偏移值(低12位),即0xB0A,得到實際的物理地址是:0x0001BB0A

相關的知識可以參考 Intel IA 32/64手冊。

CR3寄存器必須在分頁機制開啟前就裝載好,可以使用MOV 指令或者在任務切換時使用TSS中的CR3域的值。當處理器訪問不存在的頁幀時,發生一個異常,CR2 寄存器存引發異常的邏輯地址,同時錯誤碼也會壓入到堆棧中,錯誤碼格式如下:

 31                                                 3   2     1     0

┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓

┃                    未使用                         ┃ U/S┃ R/W┃ P ┃

┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛

 

異常處理例程通常采取如下的步驟:

查找一個空閑的頁幀或從硬盤中將頁幀交換出來,重新設置正確的頁目錄項或頁表項的值,刷新TLB。處理器通常保存最近最多訪問的頁目錄或頁表項到一個cache中,以避免每次都進行虛擬地址到物理地址的轉換,這個cache就叫做TLB。只有我們改動了頁目錄或頁表項,就應當刷新TLB。方法很簡單,就是重新加載CR3 寄存器。


現在我們來看看代碼段,內存管理通常少不了大量的宏定義:

08/include/kernel.h

#define PAGE_DIR    ((HD0_ADDR+HD0_SIZE+(4*1024)-1) & 0xfffff000)

物理內存安排:IDT(在0x40000),接下來是GDT,接下來是HD0使用,然后才是頁目錄,

所以這個宏看起來有點長。


08/include/mm.h
#define PAGE_SIZE    (4*1024)                    /*
頁幀粒度 */
#define PAGE_TABLE    (PAGE_DIR+PAGE_SIZE)       /*
頁表物理地址 */
#define MEMORY_RANGE (4*1024)                    /* skelix
只管理4M 內存暫時 */


08/mm.c

/* 物理內存使用情況的位圖表 */

static char mmap[MEMORY_RANGE/PAGE_SIZE] = {PG_REVERSED, };

void
mm_install(void) {
    unsigned int *page_dir = ((unsigned int *)PAGE_DIR);
    unsigned int *page_table = ((unsigned int *)PAGE_TABLE);
    unsigned int address = 0;
    int i;
    for(i=0; i<MEMORY_RANGE/PAGE_SIZE; ++i) {
        /*
頁表項屬性設置為: kernel, r/w, present */
        page_table[i] = address|7;
        address += PAGE_SIZE;
    };

    // 上面循環初始化了0~4M對應的所有頁表項


    page_dir[0] = (PAGE_TABLE|7);

    // 頁目錄項只需要第一個就可以了,因為只有4M內存

    for (i=1; i<1024; ++i)
        page_dir[i] = 6;

    // 其他的1023個頁目錄項設置為空,如果這1024項都設置,可訪問4G內存空間

    // 設置01M內存為已使用。
    for (i=(1*1024*1024)/PAGE_SIZE-1; i>=0; --i)
        mmap[i] = PG_REVERSED;

    // 因為內核只用到了低于1M的內存,所以保留它們,這樣就不會被交換出去了



    __asm__ (
        "movl    %%eax,    %%cr3\n\t"        //
加載頁目錄基址到寄存器
        "movl    %%cr0,    %%eax\n\t"
        "orl    $0x80000000,    %%eax\n\t"
        "movl    %%eax,    %%cr0"::"a"(PAGE_DIR));    //
開啟分頁機制,CR0的最高位
}

 

通過mmap位圖,我們可以清楚的知道內存的使用情況,這樣就可以分配空閑頁幀了,如下:
08/mm.c

unsigned int
alloc_page(int type) {
    int i;

    for (i=(sizeof mmap)-1; i>=0 && mmap[i]; --i)
        ;

    if (i < 0) {
        kprintf(KPL_PANIC, "NO MEMORY LEFT");
        halt();
    }
    mmap[i] = type;
    return i;            //
返回頁幀號
}

void *
page2mem(unsigned int nr) {            //
轉換為虛擬地址
    return (void *)(nr * PAGE_SIZE);
}

void
do_page_fault(enum KP_LEVEL kl,
              unsigned int ret_ip, unsigned int ss, unsigned int gs,
              unsigned int fs, unsigned int es, unsigned int ds,
              unsigned int edi, unsigned int esi, unsigned int ebp,
              unsigned int esp, unsigned int ebx, unsigned int edx,
              unsigned int ecx, unsigned int eax, unsigned int isr_nr,
              unsigned int err, unsigned int eip, unsigned int cs,
              unsigned int eflags,unsigned int old_esp, unsigned int old_ss) {
    unsigned int cr2, cr3;
    (void)ret_ip; (void)ss; (void)gs; (void)fs; (void)es;
    (void)ds; (void)edi; (void)esi; (void)ebp; (void)esp;
    (void) ebx; (void)edx; (void)ecx; (void)eax;
    (void)isr_nr; (void)eip; (void)cs; (void)eflags;
    (void)old_esp; (void)old_ss; (void)kl;
    __asm__ ("movl %%cr2, %%eax":"=a"(cr2));
    __asm__ ("movl %%cr3, %%eax":"=a"(cr3));
    kprintf(KPL_PANIC, "\n  The fault at %x cr3:%x was caused by a %s. "
            "The accessing cause of the fault was a %s, when the "
            "processor was executing in %s mode, page %x is free\n",
            cr2, cr3,
            (err&0x1)?"page-level protection voilation":"not-present page",
            (err&0x2)?"write":"read",
            (err&0x4)?"user":"supervisor",
            alloc_page(PG_NORMAL));
}

頁異常函數,它什么也沒有做,知識顯示一些錯誤信息。

現在我們來動態的分配一些內存,我們修改一下任務函數:
08/init.c

static void
new_task(unsigned int eip) {
    struct TASK_STRUCT *task = page2mem(alloc_page(PG_TASK));
    memcpy(&(task->tss), &(TASK0.tss), sizeof(struct TSS_STRUCT));

    task->tss.esp0 = (unsigned int)task + PAGE_SIZE;
    task->tss.eip = eip;
    task->tss.eflags = 0x3202;
    task->tss.esp = (unsigned int)page2mem(alloc_page(PG_TASK))+PAGE_SIZE;
    task->tss.cr3 = PAGE_DIR;
    task->priority = INITIAL_PRIO;
    task->ldt[0] = DEFAULT_LDT_CODE;
    task->ldt[1] = DEFAULT_LDT_DATA;

    task->next = current->next;
    current->next = task;
    task->state = TS_RUNABLE;
}

自己分配的任務數據結構和任務堆棧,是不是很有成就感:)

 

 

最后在init.c中添加初始化代碼:
08/init.c

void
init(void) {
    char wheel[] = {'\\', '|', '/', '-'};
    int i = 0;

    idt_install();
    pic_install();
    mm_install();      /* 
初始化函數調用 */
    kb_install();
    timer_install(100);
    set_tss((unsigned long long)&TASK0.tss);
    set_ldt((unsigned long long)&TASK0.ldt);
    __asm__ ("ltrw    %%ax\n\t"::"a"(TSS_SEL));
    __asm__ ("lldt    %%ax\n\t"::"a"(LDT_SEL));

    kprintf(KPL_DUMP, "Verifing disk partition table....\n");
    verify_DPT();
    kprintf(KPL_DUMP, "Verifing file systes....\n");
    verify_fs();
    kprintf(KPL_DUMP, "Checking / directory....\n");
    verify_dir();

    sti();
    new_task((unsigned int)task1_run);
    new_task((unsigned int)task2_run);
    __asm__ ("movl %%esp,%%eax\n\t" \
             "pushl %%ecx\n\t" \
             "pushl %%eax\n\t" \
             "pushfl\n\t" \
             "pushl %%ebx\n\t" \
             "pushl $1f\n\t" \
             "iret\n" \
             "1:\tmovw %%cx,%%ds\n\t" \
             "movw %%cx,%%es\n\t" \
             "movw %%cx,%%fs\n\t" \
             "movw %%cx,%%gs" \
             ::"b"(USER_CODE_SEL),"c"(USER_DATA_SEL));
    __asm__ ("incb 0xeeffeeff");         /* 
測試:觸發一個異常 */
    for (;;) {
        __asm__ ("movb    %%al,    0xb8000+160*24"::"a"(wheel[i]));
        if (i == sizeof wheel)
            i = 0;
        else
            ++i;
    }
}

 

異常處理例程中什么也沒做,訪問內存出錯則死機:

08/exceptions.c

void
page_fault(void) {
    __asm__ ("pushl    %%eax;call    do_page_fault"::"a"(KPL_PANIC));
    halt();
}

最后把mm.o 添加到 Makefile KERNEL_OBJS 中去:

08/Makefile

KERNEL_OBJS= load.o init.o isr.o timer.o libcc.o scr.o kb.o task.o kprintf.o hd.o exceptions.o fs.o mm.o

 

 

Feedback

# re: 自己動手寫內核(第8課:內存管理)(原創)  回復  更多評論   

2007-06-08 13:24 by 星夢情緣
嘿嘿,有點意思
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            欧美日韩精品三区| 久久精品首页| 久久一二三国产| 欧美一级日韩一级| 欧美日韩99| 欧美成人一区在线| 国际精品欧美精品 | 午夜日韩在线| 欧美日本一区二区三区| 欧美高清视频在线观看| 韩日成人在线| 欧美在线视频观看| 欧美一区二区性| 欧美日韩综合视频网址| 亚洲精品国产视频| 亚洲免费观看高清完整版在线观看| 欧美在线高清| 欧美在线视频观看| 国产精品一区三区| 亚洲欧美日韩国产综合在线| 午夜精品免费| 国产欧美日本一区视频| 亚洲欧美日本国产专区一区| 亚洲欧美日韩综合aⅴ视频| 国产精品99免视看9| 亚洲一区二区三区影院| 欧美一级理论性理论a| 国产午夜精品久久久久久免费视 | 亚洲欧美区自拍先锋| 欧美日韩一区在线观看视频| 艳妇臀荡乳欲伦亚洲一区| 亚洲婷婷综合久久一本伊一区| 欧美日韩亚洲免费| 亚洲一区二区三区激情| 久久gogo国模啪啪人体图| 国产亚洲午夜高清国产拍精品| 久久国产精品久久久久久| 久久亚洲欧美国产精品乐播| 精品成人在线| 欧美久久一级| 亚洲一区二区精品在线| 久久三级福利| 亚洲区在线播放| 欧美三日本三级少妇三2023| 亚洲在线视频一区| 久久综合九九| 99精品99| 国产日韩欧美电影在线观看| 久久偷看各类wc女厕嘘嘘偷窃| 亚洲第一在线视频| 亚洲一区在线免费观看| 国模套图日韩精品一区二区| 美国成人毛片| 夜夜嗨av一区二区三区免费区| 欧美在线免费视屏| 亚洲破处大片| 国产精品一区二区a| 久久亚洲午夜电影| 99国产一区二区三精品乱码| 久久久噜噜噜久久中文字免| 亚洲精品久久久久中文字幕欢迎你 | 欧美在线看片| 亚洲欧洲精品一区二区| 新67194成人永久网站| 亚洲国产婷婷香蕉久久久久久99| 欧美日韩在线视频首页| 久久久91精品| 亚洲视频在线观看三级| 欧美电影免费观看高清| 午夜视频在线观看一区二区三区| 在线观看亚洲精品视频| 国产精品久久久久久亚洲调教| 久久精品国产亚洲aⅴ| 一区二区三区成人| 欧美国产高清| 久久久国产91| 亚洲欧美国产精品va在线观看| 91久久精品美女高潮| 国产欧美日韩综合一区在线观看| 欧美**人妖| 久久精视频免费在线久久完整在线看| 日韩视频在线一区| 欧美福利一区二区| 久久嫩草精品久久久久| 欧美亚洲综合久久| 亚洲视频在线一区观看| 最近中文字幕日韩精品| 欧美在线1区| 尤物九九久久国产精品的分类| 欧美日韩一区二区三区视频| 美女视频一区免费观看| 欧美伊人久久久久久久久影院| 亚洲视频在线观看视频| 亚洲国产第一| 免费观看在线综合色| 久久精品欧美日韩| 久久成人免费电影| 羞羞色国产精品| 亚洲一级片在线观看| 一本大道久久a久久综合婷婷| 亚洲激情一区| 亚洲国产欧美精品| 亚洲国产日韩美| 亚洲电影网站| 亚洲国产一区二区三区在线播| 影音先锋日韩资源| 一区在线观看| 亚洲第一福利在线观看| 亚洲国产mv| 亚洲国产日韩欧美在线图片| 亚洲国产一区二区视频| 亚洲欧洲一区二区在线观看| 精品动漫3d一区二区三区| 一区在线电影| 亚洲国产经典视频| 日韩亚洲成人av在线| 99在线精品视频在线观看| aa级大片欧美三级| 亚洲伊人第一页| 欧美怡红院视频一区二区三区| 久久精品人人做人人综合| 久久久国产一区二区| 久久综合色天天久久综合图片| 久久久一二三| 欧美激情一区二区三区| 亚洲精品精选| 中国女人久久久| 午夜欧美理论片| 久久爱www.| 猛干欧美女孩| 欧美视频日韩视频在线观看| 国产视频一区在线观看一区免费| 狠狠色狠狠色综合日日小说| 一区二区在线视频| 亚洲美女中出| 香蕉乱码成人久久天堂爱免费 | 欧美激情一区二区三区蜜桃视频| 欧美伦理一区二区| 国产精品日韩电影| 极品少妇一区二区三区精品视频| 亚洲精品一线二线三线无人区| 亚洲先锋成人| 久久永久免费| 99国产精品99久久久久久| 欧美一区二区久久久| 欧美黄色视屏| 国产精品日日摸夜夜添夜夜av| 精品999在线播放| 亚洲视频久久| 鲁大师影院一区二区三区| 99香蕉国产精品偷在线观看| 欧美一区二区三区四区在线观看地址| 美国十次了思思久久精品导航| 欧美日韩在线综合| 在线精品视频在线观看高清| 亚洲专区在线视频| 欧美黄色日本| 欧美一区午夜精品| 欧美日韩精品久久| 在线日韩欧美| 欧美一区二视频在线免费观看| 亚洲国产精品久久人人爱蜜臀 | 久久久久久欧美| 欧美性大战久久久久| 亚洲激情在线观看视频免费| 欧美一区二区三区免费视频| 亚洲国产小视频在线观看| 欧美一区二区三区视频免费| 欧美精品在欧美一区二区少妇| 永久555www成人免费| 久久福利电影| 亚洲丝袜av一区| 欧美精品一区二区三区在线看午夜| 伊人久久久大香线蕉综合直播| 欧美夜福利tv在线| 亚洲一区二区在线播放| 欧美日韩视频免费播放| 亚洲肉体裸体xxxx137| 久久青草久久| 欧美在线综合视频| 国产视频一区二区在线观看 | 久久精品二区三区| 亚洲性视频网站| 欧美性大战久久久久| 亚洲先锋成人| 一区二区三区免费在线观看| 欧美伦理影院| 一区二区三区四区国产| 亚洲国产一区二区三区在线播| 牛人盗摄一区二区三区视频| 在线观看视频日韩| 美乳少妇欧美精品| 久久青青草综合| 亚洲高清久久网| 亚洲国产精品热久久| 欧美精品亚洲精品| 一区二区日韩伦理片| 在线亚洲成人| 国产精品免费一区二区三区在线观看 | 国产一区二区久久|