📄 memory.c
字号:
/*文件名: memory.c 说明: 页级内存管理函数 作者: 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处开始,根据物理实际内存大小计算mem_map的大小static s32 mem_start_index; //从2M + mem_map_size开始处开始管理内存页static int page_num; //系统中所有的页数static u32 max_mem; //物理内存的大小,字节为单位static int mem_map_size; //mem_map的大小/*| || || || || 可分配内存 || || || || || ||__________________________|max_mem / 4096 * sizeof(MEM_INFO) + 2M| mem_map,用来管理系统内存 || 实际大小根据系统的物理 || 内存计算,max_men / 4096 * sizeof(MEM_INFO)| max_men为系统物理内存的 || 大小(单位:字节) ||__________________________|2M| ||1M和2M之间存放内核 || ||__________________________|1M| ||1M以下不连续空间废弃不用 || ||__________________________|0*///取得一个空闲页,返回页号int get_free_page(){ int i; for (i = mem_start_index; i < page_num; ++i) { if (! mem_map[i].used) { //如果引用计数为0,则表示页没有被使用 mem_map[i].used = 1; //设置引用数为1 //printk("get_free_page index:%d\n", i); return i; //返回页号 } } return 0;}//释放一页,addr为逻辑地址int free_page(u32 addr){ int index; printk("free_page:%XH", addr); if (addr & 0x00000FFF) { //如果要释放的页不在4k边界上则死机 char sztmp[128] = {0}; sprintf(sztmp, "free_page addr: %d", addr); panic(sztmp); return 0; } index = paddr_to_index(vaddr_to_paddr(addr)); //根据逻辑地址转为页号 if (! mem_map[index].used) { //如果待释放的页没有占用,则死机 char sztmp[128] = {0}; sprintf(sztmp, "free_page addr not used: %d", addr); panic(sztmp); return 0; } mem_map[index].used = 0; //设置页面引用数为0 return 0;}//获取一个空闲页映射到当前进程的addr地址处s32 put_page(addr_t addr){ addr_t addr_in_page_dir; //所在页目录中的地址 s32 page_table_index; // addr_t page_table_vaddr; //获取在页目录中的位置,转化为逻辑地址 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(); //申请一页作为页表项 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 { //页表已经建立 } //获取待映射的内存(一页) 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页面的写保护,如果页面共享,则复制页面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); //取消页面的写保护即 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) { //如果页面引用数为1,则说明没有与之共享的页面了 *table_item |= PAGE_RW; } else { //不然说明有多个进程共享页面// printk("mem_map[%d].used:%d\n", index, mem_map[index].used); mem_map[index].used--; //减少页面引用数 //获取空闲页面 page_index = get_free_page(); if (! page_index) { panic("do_wp_page get_free_page\n"); } //复制页面 err_addr = addr & 0xFFFFF000; if (err_addr < PAGE_OFFSET) { //如果在user区域,则进行地址转换// 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 { //这里似乎不需要,因为内核不会发生写保护异常的 panic("kernel do_wp_page\n"); //memcpy(index_to_vaddr(page_index), addr & 0xFFFFF000, PAGE_SIZE); } //复制页面后,建立映射 *table_item = index_to_paddr(page_index) | 7; } __flush_tlb(); //刷新TLB printk("do_wp_page ok\n");}//未实现,应该很简单void do_no_page(u32 addr){ panic("do_no_page\n");}//复制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; //复制用户态的空间 for (page_item_index = 0; page_item_index < 768; ++page_item_index) { if (! (from_pg_item[page_item_index])) { //如果页目录项未使用则跳过,不复制相应的页表项 continue; } page_index = get_free_page(); //获取新页作为子进程的页表 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]); //给子进程的页目录项赋值 //开始复制页表项 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; //设置页面为只读 from_table_item[table_item_index] &= ~PAGE_RW; //设置页面为只读,这样可读性更好些 //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"); //复制内核态的空间,原封不动的复制 for (page_item_index = 768; page_item_index < 1024; ++page_item_index) { if (! (from_pg_item[page_item_index])) { //如果页目录项未使用则跳过,不复制相应的页表项 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;}//初始化内存管理//主要是初始化内存页的使用计数器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; } } } //系统的物理内存应该是4M的倍数,丢弃不是4M倍数的内存 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; //开始对mem_map初始化 max_mem = get_max_mem_size(); if (max_mem < 16 * _1M_SIZE) { //如果物理内存小于16M则提示后死机(这个在启动时保证过) panic("memory is to small!"); } if (max_mem > 1024 * _1M_SIZE) { //目前只支持1G的物理内存 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; //获取需要管理系统内存的页数 printk("page_num:%d\n", page_num); mem_map_size = page_num * sizeof(MEM_INFO); //获取管理内存的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开始处开始管理内存页的索引值 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) { //将不在管理之内的内存页设置为1 mem_map[i].used = 1; } for (i = mem_start_index; i < page_num; ++i) { //从2M + mem_map_size开始处开始管理内存页 mem_map[i].used = 0; } //开始影射16M以后的内存 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);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -