- 论坛徽章:
- 0
|
为了给自己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性质。所以各位看客如果有质疑写这个程序有什么用处的请绕道。 |
|