Chinaunix首页 | 论坛 | 博客
  • 博客访问: 380043
  • 博文数量: 56
  • 博客积分: 1449
  • 博客等级: 中尉
  • 技术积分: 822
  • 用 户 组: 普通用户
  • 注册时间: 2010-10-08 10:24
文章分类

全部博文(56)

文章存档

2014年(7)

2012年(13)

2011年(10)

2010年(26)

分类:

2010-11-01 10:43:14

/* 还没有加入到现有的代码中进行测试.不过把first fit的核心代码提出来编写了模拟的内存分配.貌似没有什么问题 */
#include
#include
#include
#include
unsigned long max_low_pfn;
unsigned long min_low_pfn;
unsigned long highstart_pfn;
unsigned long highend_pfn;
unsigned long max_pfn;

static unsigned long bootmem_init_core(struct bootmem_data *bdata, unsigned long bootmap_start, \
                                    unsigned long startpfn, unsigned long endpfn)
{
    unsigned long bootmap_size;
    bootmap_size = ((endpfn - startpfn) + 7) / 8;
    bdata->boot_start_pfn = startpfn;
    bdata->boot_end_pfn = endpfn;
    bdata->boot_map = bootmap_start;
    bdata->boot_map_size = bootmap_size;
#if 1
    bdata->boot->last_offset = 0;
    bdata->boot->last_pfn = 0;
    bdata->boot->last_bit = 0;
#endif
    /* mark all the already-known page frames reserved */
    memset(bdata->boot_map, 0xff, bootmap_size);
    return bootmap_size;
}

    


void bootmap_init(void)
{
    struct bootmem_data *bdata = &contig_pg_data.bdata;
    struct e820_map *e_map = e820_map_table + 0;
    int i;
    int j;
/* high32?! */
    for(i = 0; i < e820_map_nr; i++, e_map++) {
        unsigned long start;
        int size;
        if(e_map->type != E820_TYPE_AVAIL)
            continue;
        start = PFN_UP(e_map->base_addr_low32);
        size = PFN_DOWN(e_map->len_low32);
        if(start < max_low_pfn && (start + size) > max_low_pfn)
            size = PFN_DOWN(max_low_pfn - start);
        if(start >= max_low_pfn)
            break;
        for(j = 0; j < size; j++)
            clear_bit(start + j, bdata);
        reserve_bootmem(__start, PFN_UP(__end - __start));
        reserve_bootmem(bdata->boot_map, PFN_UP(bdata->boot_map_size));
}

void reserve_bootmem(unsigned long phys_addr, unsigned long _size)
{
    struct bootmem_data *bdata = &contig_pg_data.bdata;
    unsigned long start = PFN_UP(phys_addr);
    int size = PFN_DOWN(_size);
    int i;
    for(i = 0; i < size; i++)
        set_bit(start + i; bdata->boot_mem);
}

unsigned long bootmem_init(unsigned long bootmap_start, unsigned long endpfn)
{
    return bootmem_init_core(&contig_pg_data.bdata, bootmap_start, 0, endpfn);
}


static void free_bootmem_core(struct bootmem_data *bdata, unsigned long pfn, \
                                                                                unsigned long nr_pfns)
{
    int i;
    for(i = 0;  i < nr_pfns; i++)
        if(test_and_set_bit(pfn + i, bdata->boot_map))
            BUG("try to free a page frame twice!\n");
}


void free_bootmem(unsigned long addr, unsigned long size)
{
    unsigned long pfn = virt_to_pfn(PFN_UP(addr));
    unsigned long nr_pfns = PFN_DOWN(size);
    nr_pfns >>= PAGE_SHIFT;
    free_bootmem_core(&contig_pg_dat.bdata, pfn, nr_pfns);
}




static void *alloc_bootmem_core(struct bootmem_data *bdata, unsigned long size, \
                                                unsigned long align, unsigned long goal)
{
#if 0
    BUG_ON(!size);
    BUG_ON(align & (align - 1));
#endif
    int merged = 0;
    int start_over = 0;
    int i = 0;
    unsigned long start_bit, nr_bit, step;
    char *last_scan;
    void *addr;
    step = (align >> PAGE_SHIFT) ? : 1;
    if(!goal) {
        start_bit = bdata->last_pfn;
        last_scan = bdata->last_scan;
    } else {
        start_bit = ALIGN(goal, align);
        start_bit >>= PAGE_SHIFT;
        last_scan = bdata->boot_map;
    }
    nr_bit = PFN_UP(size);
    nr_bit >>= PAGE_SHIFT;
    while(1) {
        unsigned long map_size = bdata->boot_map_size;
try_again:
        if(step != 1)
            start_bit += ((i + step - 1) / step) * step;
        else
            start_bit += i;
        if(start_bit + nr_bit >= map_size / 8) {
            if(goal) {
                if(!start_over) {
                    start_over = 1;
                } else {
                    return NULL;
                }
                start_bit = ALIGN(goal, align);
                start_bit >>= PAGE_SHIFT;
                last_scan = bdata->boot_map;
            } else
                return NULL;
        }
        for(i = start_bit; i < start_bit + nr_bit; i++) {
            if(test_bit(i, last_scan)) {
                i = i - start_bit + 1;
                goto try_again;
            }
        }
        break;
    }
    /* check if we could merge */
    if(!PAGE_ALIGN(bdata->last_offset) && PFN_DOWN(bdata->last_offset) + 1 == start_bit \
            &&    (PAGE_SIZE - bdata->last_offset) > align) {
            merged = 1;
            start_bit--;
        if((size & PAGE_MASK) < (PAGE_SIZE - ALIGN(bdata->last_offset, align)))
            nr_bit--;
    }
    /* reserve the memory being allocated */
    for(i = 0;  i < nr_bit; i++)
        set_bit(start_bit + i, last_scan);
    if(merged)
        addr = (void *)((start_bit << PAGE_SHIFT) + ALIGN(bdata->last_offset, align));
    else
        addr = (void *)(start_bit << PAGE_SHIFT);
        /* update bootmem_data */
    bdata->last_offset = ((unsigned long)addr + size) & PAGE_MASK;
    bdata->last_pfn = start_bit;
    if(!goal)
        bdata->last_scan = bdata->boot_map + start_bit / 8;
    return addr;
}

阅读(3276) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~