|
为了给自己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周年了!感谢大家的支持与爱护!!
一只鸟敢站在脆弱的枝条上歇脚,它依仗的不是枝条不会断,而是自己有翅膀,会飞。
|