babyos2(11)——物理内存管理,伙伴系统

来源:互联网 发布:淘宝打针织打底衫长款 编辑:程序博客网 时间:2024/06/06 04:44

这里写图片描述
由于babyos2采用了类似于linux的获取current进程指针的方法,这要求process_t的内存按8K对齐,继续采用boot阶段m_start_mem递增的方式就很笨拙了,而要实现后续的vma,虚拟内存管理等功能,一个好用的物理页分配函数是必须的,所以实现了一个buddy system来管理物理内存。

#define MAX_ORDER           6#define MAP_NR(addr)        (((unsigned long)(addr)) >> PAGE_SHIFT)typedef struct page_s {    struct page_s*  next;    struct page_s*  prev;} page_t;typedef struct free_list_s {    struct free_list_s* next;    struct free_list_s* prev;    unsigned*           map;} free_list_t;typedef struct free_area_s {    free_list_t free_list[MAX_ORDER+1];    unsigned char*      base;} free_area_t;

用于管理的数据结构比较简单,每个area有若干个free_list及一个base address,每个free_list是一个链表加一个bitmap,bitmap用于方便看自己的buddy是否空闲。

void mm_t::init_free_area(){    uint32 mask = PAGE_MASK;    uint32 bitmap_size;    for (int i = 0; i <= MAX_ORDER; i++) {        m_free_area.free_list[i].prev = m_free_area.free_list[i].next = &m_free_area.free_list[i];        mask += mask;        m_mem_end = (uint8 *)(((uint32)m_mem_end) & mask);        bitmap_size = (uint32 (m_mem_end - m_mem_start)) >> (PAGE_SHIFT + i);        bitmap_size = (bitmap_size + 7) >> 3;        bitmap_size = (bitmap_size + sizeof(uint32) - 1) & ~(sizeof(uint32)-1);        m_free_area.free_list[i].map = (uint32 *) m_mem_start;        memset((void *) m_mem_start, 0, bitmap_size);        m_mem_start += bitmap_size;    }    m_free_area.base = (uint8*)(((uint32)m_mem_start + ~mask) & mask);}

m_free_area的初始化,依次初始化每个free_list的表头及为bitmap分配空间。

void mm_t::free_pages(void* addr, uint32 order){    uint32 address = (uint32) addr;    uint32 index = MAP_NR(address - (uint32)m_free_area.base) >> (1 + order);    uint32 mask = PAGE_MASK << order;    address &= mask;    while (order < MAX_ORDER) {        if (!change_bit(index, m_free_area.free_list[order].map)) {            break;        }        uint32 buddy = get_buddy(address, mask);        remove_head(m_free_area.free_list+order, (free_list_t *)buddy);        order++;        index >>= 1;        mask <<= 1;        address &= mask;    }    add_to_head(m_free_area.free_list+order, (free_list_t *) address);}uint32 mm_t::get_buddy(uint32 addr, uint32 mask){    uint32 buddy = ((addr - (uint32)m_free_area.base) ^ (-mask)) + (uint32)m_free_area.base;    return buddy;}int mm_t::mark_used(uint32 addr, uint32 order){    return change_bit(MAP_NR(addr - (uint32)m_free_area.base) >> (1+order), m_free_area.free_list[order].map);}

释放页,释放时会查找自己的buddy释放已空闲,若已空闲则合并为一个更高order的块并继续向上合并。

void* mm_t::expand(free_list_t* addr, uint32 low, uint32 high){    uint32 size = PAGE_SIZE << high;    while (low < high) {        high--;        size >>= 1;        add_to_head(m_free_area.free_list+high, addr);        mark_used((uint32) addr, high);        addr = (free_list_t *) (size + (uint32) addr);    }    return addr;}void* mm_t::alloc_pages(uint32 order){    free_list_t* queue = m_free_area.free_list + order;    uint32 new_order = order;    do {        free_list_t* next = queue->next;        if (queue != next) {            queue->next = next->next;            next->next->prev = queue;            mark_used((uint32) next, new_order);            return expand(next, order, new_order);        }        new_order++;        queue++;    } while (new_order <= MAX_ORDER);    return NULL;}

分配过程则相反,从当前所要求的order开始找,若无空闲,则向上找,找到后依次向下拆分,然后分配所要求的order的页。

int32 sys_exec(trap_frame_t* frame){    // 1. read init from hd    clb1.flags = 0;    clb1.read = 1;    clb1.dev = 0;    clb1.lba = 512;    memset(clb1.buffer, 0, 512);    os()->get_ide()->request(&clb1);    // 2. allocate a page and map to va 0-4k,    pde_t* pg_dir = os()->get_mm()->get_pg_dir();    void* mem = os()->get_mm()->alloc_pages(1);    uint32* p = (uint32 *) 0;    os()->get_mm()->map_pages(pg_dir, p, VA2PA(mem), 2*PAGE_SIZE, PTE_W | 0x04);    // 3. load init to 0x0    memcpy(p, clb1.buffer, 512);    // frame    frame->cs = (SEG_UCODE << 3 | 0x3);    frame->ds = (SEG_UDATA << 3 | 0x3);    frame->es = (SEG_UDATA << 3 | 0x3);    frame->ss = (SEG_UDATA << 3 | 0x3);    frame->fs = (SEG_UDATA << 3 | 0x3);    frame->gs = (SEG_UDATA << 3 | 0x3);    // eip & esp    frame->eip = 0;         // need get eip by load elf and get address    frame->esp = PAGE_SIZE*2;    return 0;}

修改了exec系统调用的代码,使用伙伴系统分配内存。

原创粉丝点击