?? memory.c
字號(hào):
/*文件名: memory.c 說明: 頁級(jí)內(nèi)存管理函數(shù) 作者: marsinfan 日期: 2005/12/20*/#include <fairysky/defs.h>#include <fairysky/types.h>#include <fairysky/kernel.h>#include <fairysky/string.h>#include <fairysky/scheduler.h>#include <fairysky/e820.h>#include <asm/memory.h>PARAMS_INFO *pparams;MEM_INFO *mem_map = (MEM_INFO *)0xC0200000; //mem_map從2M處開始,根據(jù)物理實(shí)際內(nèi)存大小計(jì)算mem_map的大小static s32 mem_start_index; //從2M + mem_map_size開始處開始管理內(nèi)存頁static int page_num; //系統(tǒng)中所有的頁數(shù)static u32 max_mem; //物理內(nèi)存的大小,字節(jié)為單位static int mem_map_size; //mem_map的大小/*| || || || || 可分配內(nèi)存 || || || || || ||__________________________|max_mem / 4096 * sizeof(MEM_INFO) + 2M| mem_map,用來管理系統(tǒng)內(nèi)存 || 實(shí)際大小根據(jù)系統(tǒng)的物理 || 內(nèi)存計(jì)算,max_men / 4096 * sizeof(MEM_INFO)| max_men為系統(tǒng)物理內(nèi)存的 || 大小(單位:字節(jié)) ||__________________________|2M| ||1M和2M之間存放內(nèi)核 || ||__________________________|1M| ||1M以下不連續(xù)空間廢棄不用 || ||__________________________|0*///取得一個(gè)空閑頁,返回頁號(hào)int get_free_page(){ int i; for (i = mem_start_index; i < page_num; ++i) { if (! mem_map[i].used) { //如果引用計(jì)數(shù)為0,則表示頁沒有被使用 mem_map[i].used = 1; //設(shè)置引用數(shù)為1 //printk("get_free_page index:%d\n", i); return i; //返回頁號(hào) } } return 0;}//釋放一頁,addr為邏輯地址int free_page(u32 addr){ int index; printk("free_page:%XH", addr); if (addr & 0x00000FFF) { //如果要釋放的頁不在4k邊界上則死機(jī) char sztmp[128] = {0}; sprintf(sztmp, "free_page addr: %d", addr); panic(sztmp); return 0; } index = paddr_to_index(vaddr_to_paddr(addr)); //根據(jù)邏輯地址轉(zhuǎn)為頁號(hào) if (! mem_map[index].used) { //如果待釋放的頁沒有占用,則死機(jī) char sztmp[128] = {0}; sprintf(sztmp, "free_page addr not used: %d", addr); panic(sztmp); return 0; } mem_map[index].used = 0; //設(shè)置頁面引用數(shù)為0 return 0;}//獲取一個(gè)空閑頁映射到當(dāng)前進(jìn)程的addr地址處s32 put_page(addr_t addr){ addr_t addr_in_page_dir; //所在頁目錄中的地址 s32 page_table_index; // addr_t page_table_vaddr; //獲取在頁目錄中的位置,轉(zhuǎn)化為邏輯地址 addr_in_page_dir = paddr_to_vaddr(current->tss.cr3) + ((addr >> 20) & 0x0FFC); if (*(addr_t *)addr_in_page_dir == 0) { //頁表還沒有建立 page_table_index = get_free_page(); //申請(qǐng)一頁作為頁表項(xiàng) if (page_table_index == 0) { free_page(page_table_vaddr); return 0; } else { //建立頁表 page_table_vaddr = index_to_vaddr(page_table_index); memset((void *)page_table_vaddr, 0, PAGE_SIZE); *(addr_t *)addr_in_page_dir = index_to_paddr(page_table_index) + 7; __flush_tlb(); } } else { //頁表已經(jīng)建立 } //獲取待映射的內(nèi)存(一頁) page_table_index = get_free_page(); if (page_table_index == 0) { return 0; } page_table_vaddr = index_to_vaddr(page_table_index); memset((void *)page_table_vaddr, 0, PAGE_SIZE); //完成映射 *(addr_t *)(paddr_to_vaddr((*(addr_t *)(addr_in_page_dir) & 0xFFFFF000) + ((addr >> 10) & 0x0FFC))) = index_to_paddr(page_table_index) + 7; __flush_tlb(); //需要刷新TLB return page_table_vaddr;}//取消地址addr頁面的寫保護(hù),如果頁面共享,則復(fù)制頁面void do_wp_page(u32 addr){ addr_t *table_item; s32 page_index; u32 index; addr_t addr_in_page_dir; addr_t err_addr;// printk("do_wp_page:%0XH\n", addr); //取消頁面的寫保護(hù)即 addr_in_page_dir = paddr_to_vaddr(current->tss.cr3) + ((addr >> 20) & 0x0FFC); table_item = (addr_t *)(paddr_to_vaddr((*(addr_t *)(addr_in_page_dir) & 0xFFFFF000) + ((addr >> 10) & 0x0FFC))); index = paddr_to_index(((*table_item) & 0xFFFFF000));// printk("mem_map[%d].used:%d\n", index, mem_map[index].used); if (mem_map[index].used == 1) { //如果頁面引用數(shù)為1,則說明沒有與之共享的頁面了 *table_item |= PAGE_RW; } else { //不然說明有多個(gè)進(jìn)程共享頁面// printk("mem_map[%d].used:%d\n", index, mem_map[index].used); mem_map[index].used--; //減少頁面引用數(shù) //獲取空閑頁面 page_index = get_free_page(); if (! page_index) { panic("do_wp_page get_free_page\n"); } //復(fù)制頁面 err_addr = addr & 0xFFFFF000; if (err_addr < PAGE_OFFSET) { //如果在user區(qū)域,則進(jìn)行地址轉(zhuǎn)換// printk("from: %XH, to: %XH\n", paddr_to_vaddr(*table_item) & 0xFFFFF000, index_to_vaddr(page_index)); memcpy((void *)index_to_vaddr(page_index), (void *)(paddr_to_vaddr(*table_item) & 0xFFFFF000), PAGE_SIZE); } else { //這里似乎不需要,因?yàn)閮?nèi)核不會(huì)發(fā)生寫保護(hù)異常的 panic("kernel do_wp_page\n"); //memcpy(index_to_vaddr(page_index), addr & 0xFFFFF000, PAGE_SIZE); } //復(fù)制頁面后,建立映射 *table_item = index_to_paddr(page_index) | 7; } __flush_tlb(); //刷新TLB printk("do_wp_page ok\n");}//未實(shí)現(xiàn),應(yīng)該很簡單void do_no_page(u32 addr){ panic("do_no_page\n");}//復(fù)制4G的空間的頁目錄和頁表s32 copy_page_table(u32 to, u32 from){ s32 page_item_index; s32 table_item_index; u32 *from_pg_item; u32 *to_pg_item; u32 *to_page_table; s32 page_index; u32 *from_table_item; u32 *to_table_item; u32 *table; from_pg_item = (u32 *)from; to_pg_item = (u32 *)to; memset((void *)to, 0, PAGE_SIZE); /*for (page_item_index = 0; page_item_index < 768; ++page_item_index) { if (! from_pg_item[page_item_index]) continue; printk(":%d, %XH \n", page_item_index, from_pg_item[page_item_index]); }*/ //panic("view\n"); //return 0; //復(fù)制用戶態(tài)的空間 for (page_item_index = 0; page_item_index < 768; ++page_item_index) { if (! (from_pg_item[page_item_index])) { //如果頁目錄項(xiàng)未使用則跳過,不復(fù)制相應(yīng)的頁表項(xiàng) continue; } page_index = get_free_page(); //獲取新頁作為子進(jìn)程的頁表 if (! page_index) { return -1; } to_page_table = (u32 *)index_to_paddr(page_index); table = (u32 *)index_to_vaddr(page_index); memset(table, 0, PAGE_SIZE); to_pg_item[page_item_index] = (u32)to_page_table | 7; //printk("to_page_table:%XH", to_page_table); //printk("to_pg_item[page_item_index]:%d, %XH \n", page_item_index, to_pg_item[page_item_index]); //給子進(jìn)程的頁目錄項(xiàng)賦值 //開始復(fù)制頁表項(xiàng) from_table_item = (u32 *)(paddr_to_vaddr(from_pg_item[page_item_index]) & 0xFFFFF000); to_table_item = (u32 *)(paddr_to_vaddr(to_pg_item[page_item_index]) & 0xFFFFF000); for (table_item_index = 0; table_item_index < 1024; ++table_item_index) { if (! (from_table_item[table_item_index])) { continue; } //printk("from_table_item[table_item_index]:%XH \n", from_table_item[table_item_index]); //printk("copy kernel:%XH \n", to_table_item); //from_table_item[table_item_index] ^= PAGE_RW; //設(shè)置頁面為只讀 from_table_item[table_item_index] &= ~PAGE_RW; //設(shè)置頁面為只讀,這樣可讀性更好些 //printk("from_table_item[table_item_index]:%XH \n", from_table_item[table_item_index]); //panic("view\n"); to_table_item[table_item_index] = from_table_item[table_item_index]; //printk("index:%XH \n", paddr_to_index(to_table_item[table_item_index])); ++mem_map[paddr_to_index(to_table_item[table_item_index])].used; } } //printk("copy kernel \n"); //復(fù)制內(nèi)核態(tài)的空間,原封不動(dòng)的復(fù)制 for (page_item_index = 768; page_item_index < 1024; ++page_item_index) { if (! (from_pg_item[page_item_index])) { //如果頁目錄項(xiàng)未使用則跳過,不復(fù)制相應(yīng)的頁表項(xiàng) continue; } to_pg_item[page_item_index] = from_pg_item[page_item_index]; //printk("copy kernel:%d, %XH \n", page_item_index, from_pg_item[page_item_index]); } __flush_tlb(); //panic("view\n"); return 0;}//初始化內(nèi)存管理//主要是初始化內(nèi)存頁的使用計(jì)數(shù)器static u32 get_max_mem_size(){ int mapnum; int i; u32 mem_size = 0; struct e820entry *pe820entry; mapnum = *(char *)paddr_to_vaddr(PARAMS + 46);// printk("E820NR:%d\n", mapnum); pe820entry = (struct e820entry *)paddr_to_vaddr(PARAMS + 48); for (i = 0; i < mapnum; ++i, ++pe820entry) {// printk("addr:%XH\n", pe820entry->addr);// printk("size:%XH\n", pe820entry->size);// printk("type:%d\n", pe820entry->type); if (pe820entry->type == E820_RAM) { if (pe820entry->size + pe820entry->addr > mem_size) { mem_size = pe820entry->size + pe820entry->addr; } } } //系統(tǒng)的物理內(nèi)存應(yīng)該是4M的倍數(shù),丟棄不是4M倍數(shù)的內(nèi)存 return mem_size & 0xFFC00000;}void init_mem(){ int i; u32 *page_dir_entry; int pn; int temp_page_index; u32 *page_table_entry; u32 map_addr; int page_dir_num; //開始對(duì)mem_map初始化 max_mem = get_max_mem_size(); if (max_mem < 16 * _1M_SIZE) { //如果物理內(nèi)存小于16M則提示后死機(jī)(這個(gè)在啟動(dòng)時(shí)保證過) panic("memory is to small!"); } if (max_mem > 1024 * _1M_SIZE) { //目前只支持1G的物理內(nèi)存 max_mem = 1024 * _1M_SIZE; printk("The max memory is 1024M!"); } printk("memory size: %d\n", max_mem / _1M_SIZE); page_num = max_mem / PAGE_SIZE; //獲取需要管理系統(tǒng)內(nèi)存的頁數(shù) printk("page_num:%d\n", page_num); mem_map_size = page_num * sizeof(MEM_INFO); //獲取管理內(nèi)存的mem_map所占空間 printk("mem_map_size:%d\n", mem_map_size); mem_start_index = (2 * _1M_SIZE + mem_map_size) / PAGE_SIZE; //獲取從2M + mem_map_size開始處開始管理內(nèi)存頁的索引值 if ((2 * _1M_SIZE + mem_map_size) % PAGE_SIZE != 0) { ++mem_start_index; } printk("mem_start_index:%d\n", mem_start_index); //panic(""); for (i = 0; i < mem_start_index; ++i) { //將不在管理之內(nèi)的內(nèi)存頁設(shè)置為1 mem_map[i].used = 1; } for (i = mem_start_index; i < page_num; ++i) { //從2M + mem_map_size開始處開始管理內(nèi)存頁 mem_map[i].used = 0; } //開始影射16M以后的內(nèi)存 page_dir_entry = PAGE_DIR + (PAGE_OFFSET >> 20) + sizeof(u32) * 4; printk("page_dir_entry:%XH ", page_dir_entry); printk("page_num:%d\n", page_num); map_addr = 16 * _1M_SIZE + 7; //從16M開始影射 page_dir_num = max_mem / (4 * _1M_SIZE); if (max_mem % (4 * _1M_SIZE)) { ++page_dir_num; } printk("page_dir_num:%d ", page_dir_num); //panic(""); for (pn = 0; pn < page_dir_num; ++pn) { //printk("pn:%d ", pn); //建立頁目錄 temp_page_index = get_free_page(); if (! temp_page_index) { panic("init_mem: get_free_page error\n"); } *page_dir_entry = index_to_paddr(temp_page_index) + 7; ++page_dir_entry; //建立頁表 //printk("map_addr:%XH ", map_addr); for (i = 0; i < 1024; ++i) { page_table_entry = index_to_vaddr(temp_page_index); *page_table_entry = map_addr; //printk("page_table_entry:%XH", page_table_entry); //printk("map_addr:%XH", map_addr); map_addr += 0x1000; } __flush_tlb(); //刷新TLB } //printk("map_addr:%XH ", map_addr);}
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -