static unsigned long __init bootmem_init_node(int node, struct meminfo *mi)

in arch/arm/mm/init.c

1.1 根据内存信息重新映射页表,此处为低端内存的线性映射

  -->map_memory_bank(bank);

    -->create_mapping(&map);

      -->alloc_init_section(pgd, addr, next, phys, type);

        -->/*如果地址按SECTION对齐,只需一级页表,映射1MB空间*/

        /*如果地址不是SECTION对齐,需二级页表*/

        -->alloc_init_pte(pmd, addr, end, __phys_to_pfn(phys), type);

          /*最终调用的是proc_info_list->proc->set_pte_ext,汇编代码在arch/arm/mm/proc-macros.S*/

          -->set_pte_ext(pte, pfn_pte(pfn, __pgprot(type->prot_pte)), );

map_memory_bank(bank)

1.2 Allocate the bootmem bitmap page

bootmem分配器用每一bit表示一个物理页框的使用情况,该函数计算表示所有的物理页框共需申请多少页的内存。

函数以总的物理页框数为输入参数,返回bitmap需要使用的页数。

/*

Convert a physical address to a Page Frame Number and back

#define __phys_to_pfn(paddr) ((paddr) >> PAGE_SHIFT)
#define __pfn_to_phys(pfn) ((pfn) << PAGE_SHIFT) end_pfn,start_pfn物理内存的起止页框号, */
/**
* bootmem_bootmap_pages - calculate bitmap size in pages
* @pages: number of pages the bitmap has to represent
*/
unsigned long __init bootmem_bootmap_pages(unsigned long pages)
{
unsigned long bytes = bootmap_bytes(pages); return PAGE_ALIGN(bytes) >> PAGE_SHIFT;
}
static unsigned long __init bootmap_bytes(unsigned long pages)
{
unsigned long bytes = (pages + ) / ; return ALIGN(bytes, sizeof(long));
}

bootmem_bootmap_pages

1.3 boot_pfn = find_bootmap_pfn(node, mi, boot_pages);

寻找1.2中计算出的bitmap使用的若干页该对应到物理页框的什么位置。寻找的依据是从kernel的bss段结束位置开始寻找,找到能够放置bootmap_pages个页框的内存位置。

static unsigned int __init
find_bootmap_pfn(int node, struct meminfo *mi, unsigned int bootmap_pages)
{
unsigned int start_pfn, i, bootmap_pfn; start_pfn = PAGE_ALIGN(__pa(_end)) >> PAGE_SHIFT;
bootmap_pfn = ; for_each_nodebank(i, mi, node) {
struct membank *bank = &mi->bank[i];
unsigned int start, end; start = bank_pfn_start(bank);
end = bank_pfn_end(bank); if (end < start_pfn)
continue; if (start < start_pfn)
start = start_pfn; if (end <= start)
continue; if (end - start >= bootmap_pages) {
bootmap_pfn = start;
break;
}
} if (bootmap_pfn == )
BUG(); return bootmap_pfn;
}

find_bootmap_pfn

1.4 init_bootmem_node

初始化pg_data_t->bdtat结构体,

将不同node的bdata添加到以bdata_list为首的链表。标记所有的bitmap位为1。

/*
* node_bootmem_map is a map pointer - the bits represent all physical
* memory pages (including holes) on the node.
*/
typedef struct bootmem_data {
unsigned long node_min_pfn;
unsigned long node_low_pfn;
void *node_bootmem_map;
unsigned long last_end_off;
unsigned long hint_idx;
struct list_head list;
} bootmem_data_t;
/*
* Called once to set up the allocator itself.
*/
static unsigned long __init init_bootmem_core(bootmem_data_t *bdata,
unsigned long mapstart, unsigned long start, unsigned long end)
{
unsigned long mapsize; mminit_validate_memmodel_limits(&start, &end);
bdata->node_bootmem_map = phys_to_virt(PFN_PHYS(mapstart));
bdata->node_min_pfn = start;
bdata->node_low_pfn = end;
link_bootmem(bdata); /*
* Initially all pages are reserved - setup_arch() has to
* register free RAM areas explicitly.
*/
mapsize = bootmap_bytes(end - start);
memset(bdata->node_bootmem_map, 0xff, mapsize); bdebug("nid=%td start=%lx map=%lx end=%lx mapsize=%lx\n",
bdata - bootmem_node_data, start, mapstart, end, mapsize); return mapsize;
} init_bootmem_core

init_bootmem_core

1.5 free_bootmem_node(pgdat, bank_phys_start(bank), bank_phys_size(bank));

把节点下所有的页框对应的bitmap位都设为0,标记为空闲。

这里最终调用bootmem底层的__free函数和__reserve函数。

static int __init mark_bootmem_node(bootmem_data_t *bdata,            unsigned long start, unsigned long end,int reserve, int flags)
{
unsigned long sidx, eidx; bdebug("nid=%td start=%lx end=%lx reserve=%d flags=%x\n",
bdata - bootmem_node_data, start, end, reserve, flags); BUG_ON(start < bdata->node_min_pfn);
BUG_ON(end > bdata->node_low_pfn); sidx = start - bdata->node_min_pfn;
eidx = end - bdata->node_min_pfn; if (reserve)
return __reserve(bdata, sidx, eidx, flags);
else
__free(bdata, sidx, eidx);
return ;
}
static int __init __reserve(bootmem_data_t *bdata, unsigned long sidx,
unsigned long eidx, int flags)
{
unsigned long idx;
int exclusive = flags & BOOTMEM_EXCLUSIVE; bdebug("nid=%td start=%lx end=%lx flags=%x\n",
bdata - bootmem_node_data,
sidx + bdata->node_min_pfn,
eidx + bdata->node_min_pfn,
flags); for (idx = sidx; idx < eidx; idx++)
if (test_and_set_bit(idx, bdata->node_bootmem_map)) {
if (exclusive) {
__free(bdata, sidx, idx);
return -EBUSY;
}
bdebug("silent double reserve of PFN %lx\n",
idx + bdata->node_min_pfn);
}
return ;
}

__reserve

static void __init __free(bootmem_data_t *bdata,
unsigned long sidx, unsigned long eidx)
{
unsigned long idx; bdebug("nid=%td start=%lx end=%lx\n", bdata - bootmem_node_data,
sidx + bdata->node_min_pfn,
eidx + bdata->node_min_pfn); if (bdata->hint_idx > sidx)
bdata->hint_idx = sidx; for (idx = sidx; idx < eidx; idx++)
if (!test_and_clear_bit(idx, bdata->node_bootmem_map))
BUG();
}

__free

1.6 在bitmap中标记bitmap所占用的页框为使用状态

    /*
* Reserve the bootmem bitmap for this node.
*/
reserve_bootmem_node(pgdat, boot_pfn << PAGE_SHIFT, boot_pages << PAGE_SHIFT, OOTMEM_DEFAULT);

bootmem_init_node的更多相关文章

  1. Uboot与Linux之间的参数传递

    U-boot会给Linux Kernel传递很多参数,如:串口,RAM,videofb等.而Linux kernel也会读取和处理这些参数.两者之间通过struct tag来传递参数. U-boot把 ...

  2. linux内存管理初始化

    内存管理子系统是linux内核最核心最重要的一部分,内核的其他部分都需要在内存管理子系统的基础上运行.而对其初始化是了解整个内存管理子系统的基础.对相关数据结构的初始化是从全局启动例程start_ke ...

  3. 内存管理 初始化(二)bootmem位图分配器建立 及 使用

    本地的笔记有点长,先把bootmem位图分配器的建立 及  使用过程做下梳理. 都是代码,上面做了标注.开始的汇编部分省略了(涉及的内容不多,除了swapper_pg_dir的分配). 该记录不会再添 ...

  4. ARM Linux内核源码剖析索引

    start_kernel -->asm-offset.h 生成 -->proc_info_list   -->machine_desc -->__vet_atags --> ...

随机推荐

  1. C#微信支付

    回归主题,16年1月初我对微信开发比较好奇,由于自己是一个比较喜欢钱的人,所以对支付功能颇为冲动,就用公司信息在微信平台申请了一个服务号,还给腾讯打赏了300大洋做了下认证,抽空看了下微信支付官方的文 ...

  2. VS2010/OpenGL配置

    1.下载glut:http://www.opengl.org/resources/libraries/glut/glutdlls37beta.zip 2.把解压得到的glut.h放到"C:\ ...

  3. 【Unity3D】资源对象、预设、查找对象、组合模式等知识点

    1.解释对象与资源区别于联系,根据官方案例,分别总结资源和对象组织的规则/规律.    下载并查看了Adam和Survival Shooter tutorial两个官方资源案例,这些案例作为资源,可以 ...

  4. countUp 动画展示数字变化

    html <p id="countUp" style="font-size:25px;height:25px;background-color:#0aa;" ...

  5. python os,sys模块的使用

    首先,os模块是用来与操作系统进行交互的模块,可以对操作系统上的一些东西进行操作 而sys是用来对解释器进行一些操作的 一.os os.getcwd() 获取当前工作目录,即当前python脚本工作的 ...

  6. 网站安全webshell扫描

    做个记录,使用Detector进行php网站webshell扫描 开源项目托管地址:https://github.com/emposha/PHP-Shell-Detector安装使用都很简单

  7. NVM for Windows下载与安装

    下载NVM for Windows https://github.com/coreybutler/nvm-windows/releases nvm-noinstall.zip: 这个是绿色免安装版本, ...

  8. COGS 147. [USACO Jan08] 架设电话线

    ★★☆   输入文件:phoneline.in   输出文件:phoneline.out   简单对比时间限制:1 s   内存限制:16 MB Farmer John打算将电话线引到自己的农场,但电 ...

  9. 编写C#程序,自动将bing首页图片设为壁纸

    任务目标: 1,获取图片 2,设为壁纸 3,自动化 环境需求: .NET Framework 4.0+, Visual Studio 2017 ==================== 1,获取图片 ...

  10. 【TensorFlow入门完全指南】神经网络篇·MLP多层感知机

    前面的不做过多解释了. 这里定义了两个占位符,各位也知道,在训练时,feed_dict会填充它们. 定义相关网络. 这里是权值矩阵和偏差. 这里是实例化了网络,定义了优化器和损失,和上一篇一样. 最后 ...