搜索
bottom↓
回复: 5

仿照linux中使用的内存管理机制改写的程序

[复制链接]

出0入0汤圆

发表于 2011-10-16 18:19:40 | 显示全部楼层 |阅读模式
为了给自己DIY的操作系统完善内存管理模块,课余时间仿照linux系统中常用的buddy页内存分配基址,按照自己的理解简化后写了一个小程序,请大家帮看看逻辑上有没有问题,我尽量注释清楚本人的思路,谢谢。
#include <page.h>
static struct list_node page_list[MAX_ORDER];
/**内部函数,获取满足需求内存页数的最小order
* @param cnt:申请的页面大小
* @return :满足要求的最小order
*/
static unsigned int cnt_to_min_order(unsigned int cnt){
        if (cnt <=          1) return 0;
        if (cnt <=          2) return 1;
        if (cnt <=          4) return 2;
        if (cnt <=          8) return 3;
        if (cnt <=         16) return 4;
        if (cnt <=         32) return 5;
        if (cnt <=         64) return 6;
        if (cnt <=        128) return 7;
        if (cnt <=        256) return 8;
        if (cnt <=        512) return 9;
        if (cnt <=   1 * 1024) return 10;
        if (cnt <=   2 * 1024) return 11;       
}
/**内部函数,获取最接近(小于)释放page数量的order
* @param cnt:释放的页数量
* @return :满足要求的最大order
*/
static unsigned int cnt_to_max_order(unsigned int cnt){

        if(cnt  >=        1024)return 10;
        if(cnt  >=        512 )return 9;
        if(cnt  >=        256 )return 8;
        if(cnt  >=        128 )return 7;
        if(cnt  >=        64  )return 6;
        if(cnt  >=        32  )return 5;
        if(cnt  >=        16  )return 4;
        if(cnt  >=        8   )return 3;
        if(cnt  >=        4   )return 2;
        if(cnt  >=        2   )return 1;
        return 0;
}

/**内部函数,获取指定order值的内存页
* @param _order
*/
static struct page *_get_pages(unsigned int _order){
        struct page *page;
        unsigned int order = _order;
        struct list_node *page_nod;
        for(;order<=MAX_ORDER;order++){ //查找该order链表是否空闲
                page_nod = &page_list[order]
                if(!list_is_empty(page_nod))//不空闲则在该order上分配,否则到更高一级的border上找
                    break;
        }
       
        if(oder<=MAX_ORDER){
                list_del_node(&page_nod->next);
                page = list_entry(&page_nod->next,struct page,list);
                //下面的程序将多余的页面分配到各自的order中,例如需要4页内存,但是找到1块包含32个页面的块,则分成16,8,4
                //个页面分别挂在各自的order上,并返回剩下的4个页面
                while(order>_order){
                    free_pages(page+(1<<(order-1)),order-1);
                    order--;
                }
        return page;
        }
        return NULL;
}
/**查询伙伴是否空闲
* @param order:需要查询的内存块(在指定的内存块查询)
* @param page_idx:指定页码
* return 0:非空闲,1:空闲
*/
static bool_t is_buddy_empty(unsigned int order,unsigned int page_idx){
        struct list_nod *iter;
        struct page *page = pfn_to_page(page_idx);
        list_for_each(iter,&page_list[order]){
            if(((unsigned int)list_entry(iter,struct page,list)) == (unsigned int)page)
                    return 1;
        }
        return 0;
}
/**函数,释放一页内存
* @param page 页指针
*/
void free_one_page(struct page *page){
        free_pages(page,0);
}
/**释放多个页面
* @param page 第一页指针
* @param order order值
* return 0:失败 1:成功
*/
bool_t free_pages(struct page *page,unsigned int order){
        unsigned int buddy_idx;
        struct list_nod *iter;
        unsigned int page_idx=page_to_pfn(page); //通过页指针返回该页对应的页表pfn
        if(page_idx%(1<<order)==0){ //参数检查,释放的page的第一页标必须是该order值的整数倍,否则出错
                while(order<MAX_ORDER-1){
                        buddy_idx = page_idx^(1<<order);     //找到其伙伴对应的页标
                        if(is_buddy_empty(order,buddy_idx)){  //*查看伙伴是否空闲*//
                                                //如果找到伙伴并且是空闲的,则合并到上级链表上
                                list_del_node(&pfn_to_page(buddy_idx)->list); //先在该链表上删除伙伴
                                page_idx=page_idx<buddy_idx?page_idx:buddy_idx; //合并
                                order++;    //上级buddy
                        }
                        else break;
                }
                //伙伴非空闲或者其他已经到了最高级buddy,挂在本order链表上,插入顺序按照页标pfn从小到大
                list_for_each(iter,&page_list[order]){
                       if((unsigned int)list_entry(iter,struct page,list)) > (unsigned int)page){
                             break;
                       }
                }
                list_add_head(&page->list,iter); //挂接在该buddy上
                return 1;
        }
        return 0;
}
/**申请多个页面
* @param cnt 需要申请的页面数
* return 页面指针
*/
void *get_pages(unsigned int cnt){
        struct page *page,*_page;
        unsigned int _page_cnt;
        unsigned int order,order1;
        order = cnt_to_min_order(cnt);//找到符合要求的最小order值
        page = _get_pages(order);    //分配页内存
        _page_cnt = (1<<order)-cnt;  //计算剩余的页
        _page = page +(1<<order);    //指向分配的页块末尾
        while(_page_cnt !=0)        //将多余的页返回给内存管理模块 比如需要分配33块页内存,经过order计算分配了64块
                                //剩余31块则分为16 8 4 2 1块分别返回给各自的order
            {
                    order1 = cnt_to_max_order(_page_cnt);
                    free_pages(_page -(1<<1oredr1) ,oredr1);
                    _page_cnt -= (1 << oredr1);
            }
        return (void *)page;
}
/**内存初始化函数
* @param bss_end:链接脚本传过来的bss段末地址
*/
void men_init(unsigned int bss_end){
        unsigned int cnt,used_page;
        page_start = (struct page *page)align_up(bss_end);//page结构放在bss_end的下一个页面开始的地方
        used_page = (unsigned int)(align_up(bss_end)+align_up(sizeof(struct page)*max_mapnr))/PAGE_SIZE;//已经使用的page数量,包含内核以及page结构本身的空间,并对齐到页边界
        memset((void *)page_start,0,align_up(sizeof(struct page)*max_mapnr));//将page结构占用空间清零,max_mapnr为整个内存需要的page数
        for(cnt=0;cnt < used_page;cnt++){  //将内核以及page结构本身所占用的内存填充进对应的page结构,防止被下面的释放程序给释放
                (page_start+cnt)->_count=0xff;//页面引用计数
        }
        for(;cnt < max_mapnr;cnt++){  //释放空闲内存,同时初始化buddy结构
            if((page_start+cnt)->_count==0)//该页面未被使用
                free_one_page(page_start+cnt);
        }
}
如果这一步没什么问题下一步将改造slub分配器,适合更小内存分配策略。纯粹是DIY性质。所以各位看客如果有质疑写这个程序有什么用处的请绕道,这是用在内存比较大的开发板上,有一篇帖子介绍os和app分开编译的,所以准备写一个这样的os,如有兴趣的可以关注,帖子地址http://www.ourdev.cn/bbs/bbs_content.jsp?bbs_sn=5036621&bbs_page_no=1&search_mode=4&search_text=s200661524&bbs_id=9999

阿莫论坛20周年了!感谢大家的支持与爱护!!

一只鸟敢站在脆弱的枝条上歇脚,它依仗的不是枝条不会断,而是自己有翅膀,会飞。

出0入0汤圆

发表于 2011-10-16 20:31:55 | 显示全部楼层
关注

出0入0汤圆

发表于 2011-10-16 23:10:46 | 显示全部楼层
专业了~ 顶一下

出0入0汤圆

发表于 2012-8-25 20:30:19 | 显示全部楼层
关注中。同样关注楼主的OS

出0入17汤圆

发表于 2012-8-25 23:35:59 | 显示全部楼层
学习了~
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-5-20 16:08

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表