⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 memory.c

📁 一个用于学习的操作系统
💻 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 + -