start_kernel->setup_arch->paging_init->alloc_bootmem_low_pages

#define alloc_bootmem_low_pages(x) /
    __alloc_bootmem((x), PAGE_SIZE, 0)

 

__alloc_bootmem -->__alloc_bootmem_limit

void * __init __alloc_bootmem_limit (unsigned long size, unsigned long align, unsigned long goal,
                unsigned long limit)
{ // size = 4k, align = 4k, goal = 0, limit = 0
    pg_data_t *pgdat = pgdat_list;
    void *ptr;

    for_each_pgdat(pgdat)
        if ((ptr = __alloc_bootmem_core(pgdat->bdata, size,
                         align, goal, limit)))
            return(ptr);

    /*
     * Whoops, we cannot satisfy the allocation request.
     */
    printk(KERN_ALERT "bootmem alloc of %lu bytes failed!/n", size);
    panic("Out of memory");
    return NULL;
}

static void * __init
__alloc_bootmem_core(struct bootmem_data *bdata, unsigned long size,
          unsigned long align, unsigned long goal, unsigned long limit)
// size = 4k, align = 4k, goal = 0, limit = 0
    unsigned long offset, remaining_size, areasize, preferred;
    unsigned long i, start = 0, incr, eidx, end_pfn = bdata->node_low_pfn;
    void *ret;

    if(!size) {
        printk("__alloc_bootmem_core(): zero-sized request/n");
        BUG();
    }
    BUG_ON(align & (align-1));

    if (limit && bdata->node_boot_start >= limit)
        return NULL;

        limit >>=PAGE_SHIFT;
    if (limit && end_pfn > limit)
        end_pfn = limit;

    eidx = end_pfn - (bdata->node_boot_start >> PAGE_SHIFT);
    offset = 0;
    if (align &&
        (bdata->node_boot_start & (align - 1UL)) != 0)
        offset = (align - (bdata->node_boot_start & (align - 1UL)));
    offset >>= PAGE_SHIFT;

    /*
     * We try to allocate bootmem pages above 'goal'
     * first, then we try to allocate lower pages.
     */
    if (goal && (goal >= bdata->node_boot_start) &&
        ((goal >> PAGE_SHIFT) < end_pfn)) {
        preferred = goal - bdata->node_boot_start;

        if (bdata->last_success >= preferred)
            if (!limit || (limit && limit > bdata->last_success))
                preferred = bdata->last_success;
    } else
        preferred = 0;

    preferred = ALIGN(preferred, align) >> PAGE_SHIFT;
    preferred += offset;
    areasize = (size+PAGE_SIZE-1)/PAGE_SIZE;      //areasize = 1
    incr = align >> PAGE_SHIFT ? : 1;                        //incr = 1

restart_scan:
    for (i = preferred; i < eidx; i += incr) {
        unsigned long j;
        i = find_next_zero_bit(bdata->node_bootmem_map, eidx, i);   //通过页帧位码表查找为0的页帧位,即可以使用的页
        i = ALIGN(i, incr);
        if (test_bit(i, bdata->node_bootmem_map))
            continue;
        for (j = i + 1; j < i + areasize; ++j) {
            if (j >= eidx)
                goto fail_block;
            if (test_bit (j, bdata->node_bootmem_map))
                goto fail_block;
        }
        start = i;
        goto found;
    fail_block:
        i = ALIGN(j, incr);
    }

    if (preferred > offset) {
        preferred = offset;
        goto restart_scan;
    }
    return NULL;

found:
    bdata->last_success = start << PAGE_SHIFT;
    BUG_ON(start >= eidx);

    /*
     * Is the next page of the previous allocation-end the start
     * of this allocation's buffer? If yes then we can 'merge'
     * the previous partial page with this allocation.
     */
    if (align < PAGE_SIZE &&
        bdata->last_offset && bdata->last_pos+1 == start) {
        offset = ALIGN(bdata->last_offset, align);
        BUG_ON(offset > PAGE_SIZE);
        remaining_size = PAGE_SIZE-offset;
        if (size < remaining_size) {
            areasize = 0;
            /* last_pos unchanged */
            bdata->last_offset = offset+size;
            ret = phys_to_virt(bdata->last_pos*PAGE_SIZE + offset +
                        bdata->node_boot_start);
        } else {
            remaining_size = size - remaining_size;
            areasize = (remaining_size+PAGE_SIZE-1)/PAGE_SIZE;
            ret = phys_to_virt(bdata->last_pos*PAGE_SIZE + offset +
                        bdata->node_boot_start);
            bdata->last_pos = start+areasize-1;
            bdata->last_offset = remaining_size;
        }
        bdata->last_offset &= ~PAGE_MASK;
    } else {
        bdata->last_pos = start + areasize - 1;
        bdata->last_offset = size & ~PAGE_MASK;
        ret = phys_to_virt(start * PAGE_SIZE + bdata->node_boot_start);      //返回找到的物理页面对应的虚拟地址
    }

    /*
     * Reserve the area now:
     */
    for (i = start; i < start+areasize; i++)
        if (unlikely(test_and_set_bit(i, bdata->node_bootmem_map)))
            BUG();
    memset(ret, 0, size);                                                                                 //返回之前先将页面内容清空
    return ret;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值