3.5.1.151. __map_init_section
static void __init __map_init_section(pmd_t *pmd, unsigned long addr,
unsigned long end, phys_addr_t phys, const struct mem_type *type, bool ng)
{
pmd_t *p = pmd;
#ifndef CONFIG_ARM_LPAE
if(addr & SECTION_SIZE)
pmd++;
#endif
do {
*pmd = __pmd(phys | type->prot_sect | (ng ? PMD_SECT_nG : 0));
phys += SECTION_SIZE;
} while(pmd++, addr += SECTION_SIZE, addr != end);
flush_pmd_entry(p);
}
__map_init_section
用于建立一个section一级页表
3.5.1.152. map_lowmem
static void __init map_lowmem(void)
{
struct memblock_region *reg;
//计算内核镜像的起始物理地址和终止物理地址
phys_addr_t kernel_x_start = round_down(__pa(KERNEL_START), SECTION_SIZE);
phys_addr_t kernel_x_end = round_up(__pa(__init_end), SECTION_SIZE);
//遍历系统中所有的可用物理内存
for_each_memblock(memory, reg) {
phys_addr_t start = reg->base;
phys_addr_t end = start + reg->size;
struct map_desc map;
//判断这段物理内存块是否建立页表
if(memblock_is_nomap(reg))
continue;
//如果物理内存的终止地址大于低端物理内存,则end设置为arm_lowmem_limit
if(end > arm_lowmem_limit)
end = arm_lowmem_limit;
if(start >= end)
break;
if(end < kernel_x_start) {
map.pfn = __phys_to_pfn(start);
map.virtual = __phys_to_pfn(start);
map.length = end - start;
map.type = MT_MEMORY_RWX;
create_mapping(&map);
} else if(start >= kernel_x_end) {
map.pfn = __phys_to_pfn(start);
map.virtual = __phys_to_pfn(start);
map.length = end - start;
map.type = MT_MEMORY_RW;
create_mapping(&map);
} else {
if(start < kernel_x_start) {
map.pfn = __phys_to_pfn(start);
map.virtual = __phys_to_virt(start);
map.length = kernel_x_start - start;
map.type = MT_MEMORY_RW;
create_mapping(&map);
}
map.pfn = __phys_to_pfn(kernel_x_start);
map.virtual = __phys_to_virt(kernel_x_start);
map.length = end - kernel_x_end;
map.type = MT_MEMORY_RW;
create_mapping(&map);
}
}
}
map_lowmem
用于映射低端物理内存,低端物理内存的起始地址为DRM,低端物理内存的结束地址是arm_lowmem_limit.
3.5.1.153. memblock_add
int __init_memblock memblock_add(phys_addr_t base, phys_addr_t size)
{
phys_addr_t end = base + size - 1;
return memblock_add_range(&memblock.memory, base, size, MAX_NUMNODES, 0);
}
memblock_add
用于将一块可用物理内存加入到memblock.memory内存区
3.5.1.154. memblock_add_range
//type: 指向内存区
//base: 需要加入的内存块的基地址
//size: 需要加入内存块的长度
//nid: NUMA节点
//flags: 新加入内存块对应的flags
int __init_memblock memblock_add_range(struct memblock_type *type, phys_addr_t base,
phys_addr_t size, int nid, enum memblock_flags flags)
{
bool insert = false;
phys_addr_t obase = base;
phys_addr_t end = base + memblock_cap_size(base, &size);
int idx, nr_new;
struct memblock_region *rgn;
//如果size为0,则返回
if(!size)
return 0;
//检查参数type->regions[0].size以此判断内存区是不是不包含其他内存区块
//由于内存区内的所有内存区块都是按其首地址从低到高排列,如果第一个内存区块的长度为0
//那么认为这个内存区可能为空,但不能确认
if(type->regions[0].size == 0) {
//继续检查内存区的cnt变量,这个变量统计内存区内存块的数量
//如果内存区的cnt为1表示内存区内不包含内存块的数量
//如果内存区的total_size不为零,那么内存区含有内存区块,内核报错
WARN_ON(type->cnt != 1 || type->total_size);
type->regions[0].base = base;
type->regions[0].size = size;
type->regions[0].flags = flags;
memblock_set_region_node(&type->regions[0], nid);
type->total_size = size;
return 0;
}
repeat:
base = obase;
nr_new = 0;
//遍历内存区内的所有内存区块
for_earch_memblock_type(idx, type, rgn) {
phys_addr_t rbase = rgn->base;
phys_addr_t rend = rbase + rgn->size;
if(rbase >= end)
break;
if(rend <= base)
continue;
if(rbase > base) {
nr_new++;
if(insert)
memblock_insert_region(type, idx++, base, rbase - base, nid, flags);
}
base = min(rend, end);
}
if(base < end) {
nr_new++;
if(insert)
memblock_insert_region(type, idex, base, end - base, nid, flags);
}
if(!nr_new)
return 0;
if(!insert) {
while(type->cnt + nr_new > type_max)
if(memblock_double_array(type, obase, size) < 0)
return -ENOMEM;
insert = true;
goto repeat;
} else {
memblock_merge_regions(type);
return 0;
}
}
memblock_add_range
用于将一块物理内存插入到内存区里面,内存区可以是物理内存区,也可以是预留区
遍历到的内存区块的起始地址大于或等于新内存区块的结束地址,新的内存区块位于遍历到内存区块的前端
1) rbase > end
base end rbase rend
+-----------------------+ +-------------------+
| | | |
| New region | | Exist regions |
| | | |
+-----------------------+ +-------------------+
2)rbase == endi
rbase rend
| <----------------------> |
+----------------------+--------------------------+
| | |
| New region | Exist regions |
| | |
+----------------------+--------------------------+
| <------------------> |
base end
遍历到的内存区块的终止地址小于或等于新内存区块的起始地址,新的内存区块位于遍历到内存区块的后面
1) base > rend
rbase rend base end
+--------------------+ +---------------------+
| | | |
| Exist regions | | new region |
| | | |
+--------------------+ +---------------------+
2) base == rend
base
rbase rend end
+--------------------+------------------------+
| | |
| Exist regions | new region |
| | |
+--------------------+------------------------+
其他情况,两个内存区块存在重叠部分
rbase Exist regions rend
| <--------------------------> |
+---------------+--------+---------------------+
| | | |
| | | |
| | | |
+---------------+--------+---------------------+
| <--------------------> |
base New region end
* rbase rend
| <---------------------> |
+----------------+--------+----------------------+
| | | |
| Exist regions | | |
| | | |
+----------------+--------+----------------------+
| <---------------------------> |
base new region end
3.5.1.155. memblock_addrs_overlap
static unsigned long __init_memblock memblock_addrs_overlap(phys_addr_t base1, phys_addr_t size1,
phys_addr_t base2, phys_addr_t size2)
{
return ((base1 < (base2 + size2)) && (base2 < (base1 + size1)));
}
memblock_addrs_overlap
用于确认两块内存区块是否存在重叠
3.5.1.156. memblock_alloc_base
phys_addr_t __init memblock_alloc_base(phys_addr_t size, phys_addr_t align, phys_addr_t max_addr)
{
phys_addr_t alloc;
alloc = __memblock_alloc_base(size, align, max_addr);
if(alloc == 0)
panic("ERROR: Failed to allocate %pa bytes below %pa.\n", &size, &max_addr);
return alloc;
}
phys_addr_t __init __memblock_alloc_base(phys_addr_t size, phys_addr_t align, phys_addr_t max_addr)
{
return memblock_alloc_base_nid(size, align, max_addr, NUMA_NO_NODE, MEMBLOCK_NONE);
}
memblock_alloc_base
用于获得指定长度的物理内存
3.5.1.157. memblock_alloc_base_nid
phys_addr_t __init memblock_alloc_base_nid(phys_addr_t size, phys_addr_t align, phys_addr_t max_addr,
int nid, enum memblock_flags flags)
{
return memblock_alloc_range_nid(size, align, 0, max_addr, nid, flags);
}
memblock_alloc_base_nid
用于从指定NUMA节点上分配物理内存
3.5.1.158. memblock_alloc_internal
static void * __init memblock_alloc_internal(phys_addr_t size, phys_addr_t align,
phys_addr_t min_addr, phys_addr_t max_addr, int nid)
{
phys_addr_t alloc;
void *ptr;
enum memblock_flags flags = choose_memblock_flags();
if(WARN_ONCE(nid == MAX_NUMNODES, "Usage of MAX_NUMNODES is deprecated. Use NUMA_NO_NODE instead\n"))
nid = NUMA_NO_NODE;
//判断slab内存分配器是否启用
//如果启用直接调用kzalloc_node分配内存,并返回
if(WARN_ON_ONCE(slab_is_available()))
return kzalloc_node(size, GFP_NOWAIT, nid);
//如果align参数为0,那么打印堆栈信息,并将align设置为SMP_CACHE_BYTES
if(!align) {
dump_stack();
align = SMP_CACHE_BYTES;
}
//如果max_addr大于MEMBLOCK内存分配器最大设置current_limit,则将其设置为MEMBLOCK最大限制
if(max_addr > memblock.current_limit)
max_addr = memblock.current_limit;
again:
//从MEMBLOCK分配器中获得指定物理内存
alloc = memblock_find_in_range_node(size, align, min_addr, max_addr, nid, flags);
//分配成功后,将其加入到预留区
if(alloc && !memblock_reserve(alloc, size))
goto done;
//如果nid不是NUMA_NO_NODE,那么重新从NUMA_NO_NODE中分配内存,并将该区域加入到系统预留区
if(nid != NUMA_NO_NODE) {
alloc memblock_find_in_range_node(size, align, min_addr, max_addr, NUMA_NO_NODE, flags);
if(alloc && !memblock_reserve(alloc, size))
goto done;
}
if(min_addr) {
min_addr = 0;
goto again;
}
if(flags & MEMBLOCK_MIRROR) {
flags &= ~MMEBLOCK_MIRROR;
goto again;
}
return NULL;
done:
//如果内存分配成功,那么函数调用phys_to_virt获得物理地址对应的虚拟地址
ptr = phys_to_virt(alloc);
if(max_addr != MEMBLOCK_ALLOC_KASAN)
kmemleak_alloc(ptr, size, 0, 0);
return ptr;
}
static inline void *phys_to_virt(phys_addr_t x)
{
return (void *)__phys_to_virt(x);
}
membock_alloc_internal
用于从MEMBLOCK内存分配器中获得指定大小的物理内存
3.5.1.159. memblock_alloc_node_nopanic
void * __init memblock_alloc_try_nid_nopanic(phys_addr_t size, phys_addr_t align,
phys_addr_t min_addr, phys_addr_t max_addr, int nid)
{
void *ptr;
ptr = memblock_alloc_internal(size, align, min_addr, max_addr, nid);
if(ptr)
memset(ptr, 0, size);
return ptr;
}
static inline void * __init memblock_alloc_node_nopanic(phys_addr_t size, int nid)
{
return memblock_alloc_try_nid_nopanic(size, SMP_CACHE_BYTES, MEMBLOCK_LOW_LIMIT, MEMBLOCK_ALLOC_ACCESSIBLE, nid);
}
memblock_alloc_node_nopanic
用于从指定的NUMA中分配物理内存
3.5.1.160. memblock_alloc_range
phys_addr_t __init memblock_alloc_range(phys_addr_t size, phys_addr_t align,
phys_addr_t start, phys_addr_t end, enum memblock_flags flags)
{
return memblock_alloc_range_nid(size, align, start, end, NUMA_NO_NODE, flags);
}
memblock_alloc_range
用于从MEMBLOCK可用物理内存指定范围内分配物理内存.
3.5.1.161. memblock_alloc_range_nid
static phys_addr_t __init memblock_alloc_range_nid(phys_addr_t size, phys_addr_t align,
phys_addr_t start, phys_addr_t end, int nid, enum memblock_flags flags)
{
phy_addr_t found;
if(!align) {
dump_stack();
align = SMP_CACHE_BYTES;
}
found = memblock_find_in_range_node(size, align, start, end, nid, flags);
if(found && !memblock_reserve(found, size)) {
kmemleak_alloc_phy(found, size, 0, 0);
return found;
}
return 0;
}
memblock_alloc_range_nid
用于从指定NUMA上分配物理内存
3.5.1.162. memblock_allow_resize
void __init memblock_allow_reize(void)
{
memblock_can_resize = 1;
}
memblock_allow_resize
用于设置MEMBLOCK内存分配器的memblock_can_resize变量
3.5.1.163. memblock_bottom_up
static inline bool memblock_bottom_up(void)
{
return memblock.bottom_up;
}
memblock_bottom_up
用于获得当前MEMBLOCK分配的方向,如果为true那么MEMBLOCK从低地址向高地址分配,反之则高地址向低地址分配
3.5.1.164. memblock_cap_size
static inline phys_addr_t memblock_cap_size(phys_addr_t base, phys_addr_t *size)
{
return *size = min(*size, PHYS_ADDR_MAX - base);
}
memblock_cap_size
用于获得一个有效的长度值,函数确保size不会超出系统支持的物理内存
3.5.1.165. memblock_double_array
//type: 需要扩编的memblock_type
//new_area_start: 新物理内存区的起始物理地址
//new_area_size: 新物理内存区的长度
static int __init_memblock memblock_double_array(struct memblock_type *type,
phys_addr_t new_area_start, phys_addr_t new_area_size)
{
struct memblock_region *new_array, *old_array;
phys_addr_t old_alloc_size, new_alloc_size;
phys_addr_t old_size, new_size, addr, new_end;
//获取当前slab内存分配器是否可用
int use_slab = slab_is_available();
int *in_slab;
if(!memblock_can_resize)
return -1;
//计算原先memblock_type支持的最大物理内存数
old_size = type->max * sizeof(struct memblock_region);
new_size = old_size << 1;
//进行页对齐
old_alloc_size = PAGE_ALIGN(old_size);
new_alloc_size = PAGE_ALIGN(new_size);
//如果type对应的类型是可用物理内存区,那么读取memblock_memory_in_slab的值到in_slab中
if(type == &memblock.memory)
in_slab = &memblock_memory_in_slab;
else
in_slab = &memblock_reserved_in_slab;
//如果此时slab内存分配器已经可以使用,使用kmalloc分配内存
if(use_slab) {
new_array = kmalloc(new_size, GFP_KERNEL);
addr = new_array ? __pa(new_array) : 0;
} else {
if(type != &memblock.reserved)
new_area_start = new_area_size = 0;
//查找一块空闲的物理内存
addr = memblock_find_in_range(new_area_start + new_area_size,
memblock.current_limit, new_alloc_size, PAGE_SIZE);
//如果没有找到,那么函数从0地址重新查找物理内存
if(!addr && new_area_size)
addr = mmeblock_find_in_range(0, min(new_area_start, memblock.current_limit),
new_alloc_size, PAGE_SIZE);
new_array = addr ? __va(addr) : NULL;
}
if(!addr) {
pr_err("memblock: Failed to double %s array from %ld to %ld enties!\n",
type->name, type->max, type->max * 2);
return -1;
}
new_end = addr + new_size - 1;
//将原始regions信息拷贝到新分配的物理内存上,然后清零new_array+type->max之后的物理内存
memcpy(new_array, type->regions, old_size);
memset(new_array + type->max, 0, old_size);
old_array = type->regions;
type->regions = new_array;
type->max <<= 1;
if(*in_slab)
kfree(old_array);
else if(old_array != memblock_memory_init_regions &&
old_array != memblock_reserved_init_regions)
memblock_free(__pa(old_array), old_alloc_size);
if(!use_slab)
BUG_ON(memblock_reserve(addr, new_alloc_size));
*in_slab = use_slab;
return 0;
}
memblock_double_array
将memblock_type支持的regions数扩大两倍
3.5.1.166. memblock_end_of_DRAM
phys_addr_t __init_memblock memblock_end_of_DRAM(void)
{
int idx = memblock.memory.cnt - 1;
return (memblock.memory.regions[idx].base + memblock.memory.regions[idx].size);
}
memblock_end_of_DRAM
用于获得MEMBLOCK内存分配器memory区域的最大物理地址.
3.5.1.167. memblock_find_in_range
phys_addr_t __init_memblock memblock_find_in_range(phys_addr_t start, phys_addr_t end,
phys_addr_t size, phys_addr_t align)
{
phys_addr_t ret;
enum memblock_flags flags = choose_memblock_flags();
again:
ret = memblock_find_in_range_node(size, align, start, end, NUMA_NO_NODE, flags);
if(!ret && (flags & MEMBLOCK_MIRROR)) {
flags &= ~MEMBLOCK_MIRROR;
goto again;
}
return ret;
}
memblock_find_in_range
在指定区间内查找一块可用的物理内存
3.5.1.168. memblock_find_in_range_node
//size: 需要查找内存的大小
//align: 对齐方式
//start: 需要查找内存区域的起始地址
//end: 需要查找内存区域的终止地址
//nid: 代表NUMA节点信息
//flags: 代表内存区的标志
phys_addr_t __init_memblock memblock_find_in_range_node(phys_addr_t size, phys_addr_t align,
phys_addr_t start, phys_addr_t end, int nid, enum memblock_flags flags)
{
phys_addr_t kernel_end, ret;
//对end参数进行检测
if(end == MEMBLOCK_ALLOC_ACCESSIBLE || end == MEMBLOCK_ALLOC_KASAN)
end = memblock.current_current_limit;
//对start和end进行处理
start = max_t(phys_addr_t, start, PAGE_SIZE);
end = max(start, end);
//获得kernel镜像的终止物理地址
kernel_end = __pa_symbol(_end);
//如果MEMBLOCK支持从低向上分配以及查找的终止地址大于内核的终止物理地址
if(memblock_bottom_up() && end > kernel_end) {
phys_addr_t bottom_up_start;
bottom_up_start = max(start, kernel_end);
ret = __memblock_find_range_bottom_up(bottom_up_start, end, size, align, nid, flags);
if(ret)
return ret;
WARN_ONCE(IS_ENABLED(CONFIG_MEMORY_HOTREMOVE),
"memblock: bottom-up allocaton failed, memory hotremove may be affected\n");
}
return __memblock_find_range_top_down(start, end, size, align, nid, flags);
}
memblock_find_in_range_node
在指定的节点区间内查找一块可用的物理内存
3.5.1.169. __memblock_find_range_bottom_up
static phys_addr_t __init_memblock __memblock_find_range_bottom_up(phys_addr_t start, phys_addr_t end,
phys_addr_t size, phys_addr_t align, int nid, enum memblock_flags flags)
{
phys_addr_t this_start, this_end, cand;
u64 i;
//遍历所有可用的物理内存region
for_each_free_mem_range(i, nid, flags, &this_start, &this_end, NULL) {
//使用clamp找到符合要求的范围
this_start = clamp(this_start, start, end);
this_end = clamp(this_end, start, end);
//对this_start进行对齐
cand = round_up(this_start, align);
if(cand < this_end && this_end - cand >= size)
return cand;
}
return 0;
}
__memblock_find_range_bottom_up
用于从MEMBLOCK的底部开始,查找一块可用的物理内存region.
3.5.1.170. __memblock_find_range_top_down
static phys_addr_t __init_memblock __memblock_find_range_top_down(phys_addr_t start, phys_addr_t end,
phys_addr_t size, phys_addr_t align, int nid, enum memblock_flags flags)
{
phys_addr_t this_start, this_end, cand;
u64 i;
//倒序遍历所有的空闲物理区块
for_each_free_mem_range_reverse(i, nid, flags, &this_start, &this_end, NULL) {
//找到符合要求的起始物理地址和终止物理地址
this_start = clamp(this_start, start, end);
this_end = clamp(this_end, start, end);
if(this_end < size)
continue;
cand = round_down(this_end - size, align);
if(cand >= this_start)
return cand;
}
return 0;
}
__memblock_find_rage_top_down
作用是从顶端往低端,查找满足需求的空闲物理块
3.5.1.171. memblock_free
int __init_memblock memblock_free(phys_addr_t base, phys_addr_t size)
{
phys_addr_t end = base + size - 1;
kmemleak_free_part_phys(base, size);
return memblock_remove_range(&memblock.reserved, base, size);
}
memblock_free
作用是释放物理内存区块
3.5.1.172. memblock_insert_region
static void __init_memblock memblock_insert_region(struct memblock_type *type,
int idx, phys_addr_t base, phys_addr_t size, int nid, enum memblock_flags flags)
{
struct memblock_region *rgn == &type->regions[idx];
BUG_ON(type->cnt >= type->max);
memmove(rgn + 1, rgn, (type->cnt - idx) * sizeof(*rgn));
rgn->base = base;
rgn->size = size;
rgn->flags = flags;
memblock_set_region_node(rgn, nid);
type->cnt++;
type->total_size += size;
}
memblock_insert_region
用于将一个新的memblock_region插入到MEMBLOCK指定类型里.
3.5.1.173. memblock_is_hotpluggable
static inline bool memblock_is_hotpluggable(struct memblock_region *m)
{
return m->flags & MEMBLOCK_HOTPLUG;
}
memblock_is_hotpluggable
判断当前region是否具有热插拔属性.
3.5.1.174. memblock_is_mirror
static inline bool memblock_is_mirror(struct memblock_region *m)
{
return m->flags & MEMBLOCK_MIRROR;
}
memblock_is_mirror
用于判断当前regions是否是MIRROR
3.5.1.175. memblock_is_nomap
static inline bool memblock_is_nomap(struct memblock_region *m)
{
return m->flags & MEMBLOCK_NOMAP;
}
memblock_is_nomap
判断当前region是否不需要映射页表
3.5.1.176. memblock_is_region_memory
bool __init_memblock memblock_is_region_memory(phys_addr_t base, phys_ddr_t size)
{
//查找base参数在memory regions的索引
int idx = memblock_search(&memblock.memory, base);
phys_addr_t end = base + memblock_cap_size(base, &size);
if(idx == -1)
return false;
return (memblock.memory.regions[idx].base + memblock.memory.regions[idx].size) >= end;
}
static int __init_memblock memblock_search(struct memblock_type *type, phys_addr_t addr)
{
unsigned int left = 0, right = type->cnt;
do {
unsigned int mid = (right + left) / 2;
if(addr < type->regions[mid].base)
right = mid;
else if(addr >= (type->regions[mid].base + type->regions[mid].size))
lef = mid + 1;
else
return mid;
} while(left < right);
return -1;
}
memblock_is_region_memory
用于确认内存区块是否在MEMBLOCK内存分配器memory regions里
3.5.1.177. memblock_is_region_reserved
bool __init_memblock memblock_is_region_reserved(phys_addr_t base, phys_addr_t size)
{
//得到查找区域的安全长度
memblock_cap_size(base, &size);
return memblock_overlaps_region(&memblock.reserved, base, size);
}
memblock_is_region_reserved
检查参数对应的内存区块是否在MEMBLOCK内存分配器的预留区内
3.5.1.178. memblock_isolate_range
//type: 指向特定的memblock_type
//base: 孤立物理内存块的起始物理地址
//size: 孤立物理内存块的长度
static int __init_memblock memblock_isolate_range(struct memblock_type *type, phys_addr_t base,
phys_addr_t size, int *start_rgn, int *end_rgn)
{
//计算孤立物理块的终止物理地址
phys_addr_t end = base + memblock_cap_size(base, &size);
int idx;
struct memblock_region *rgn;
*start_rgn = *end_rgn = 0;
if(!size)
return 0;
while(type->cnt + 2 > type->max)
if(memblock_double_array(type, base, size) < 0)
return -ENOMEM;
//遍历type对应的所有物理内存region
for_each_memblock_type(idx, type, rgn) {
phys_addr_t rbase = rgn->base;
phys_addr_t rend = rbase + rgn->size;
//找到符合要求的region
if(rbase >= end)
break;
if(rend <= base)
continue;
//如果rbase小于base那么需要孤立的内存区块可能可遍历到的region存在重叠的情况
//首先将重叠的部分从原先的region中移除,并将剩余的region插入到memblock_type的regions里
if(rbase < base) {
rgn->base = base;
rgn->size -= base - rbase;
type->total_size -= base - rbase;
memblock_insert_region(type, idx, rbase, base - rbase,
memblock_get_region_node(rgn), rgn->flags);
} else if(rend > end) {
rgn->base = end;
rgn->size -= end - rbase;
type->total_size = end - rbase;
memblock_insert_region(type, idx--, rbase, end - rbase,
memblock_get_region_node(rgn), rgn->flags);
} else {
if(!*end_rgn)
*start_rgn = idx;
*end_rgn = idx + 1;
}
}
return 0;
}
memblock_isolate_range
用于将指定范围的物理内存从内存区块孤立出来
3.5.1.179. memblock_merge_regions
static void __init_memblock memblock_merge_regions(struct memblock_type *type)
{
int i = 0;
//遍历所有region
while(i < type->cnt - 1)
{
struct memblock_region *this = &type->regions[i];
struct memblock_region *next = &type->regions[i + 1];
if(this->base + this->size != next->base ||
memblock_get_region_node(this) != memblock_get_region_node(next) ||
this->flags != next->flags){
BUG_ON(this->base + this->size > next->base);
i++;
continue;
}
//如果两个region正好相连,并且flags和numa都相同,则将两个region合并成一个region
this->size += next->size;
memmove(next, next + 1, (type->cnt - (i + 2)) * sizeof(*next));
//type的cnt减一,进入下一次循环
type->cnt--;
}
}
memblock_merge_regions
用于合并特定memblock_type内的regions
3.5.1.180. memblock_overlaps_region
bool __init_memblock memblock_overlaps_region(struct memblock_type *type,
phys_addr_t base, phys_addr_t size)
{
unsigned long i;
for(i = 0; i < type->cnt; i++)
if(memblock_addrs_overlap(base, size, type->regions[i].base, type->regions[i].size))
break;
return i < type->cnt;
}
memblock_overlaps_region
用于判断内存区块在MEMBLOCK内存分配器指定type的regions内是否存在重叠部分
3.5.1.181. memblock_phys_alloc
phys_addr_t __init memblock_phys_alloc(phys_addr_t size, phys_addr_t align)
{
return memblock_alloc_base(size, align, MEMBLOCK_ALLOC_ACCESSIBLE);
}
phys_addr_t __init memblock_alloc_base(phys_addr_t size, phys_addr_t align, phys_addr_t max_addr)
{
phys_addr_t alloc;
alloc = __memblock_alloc_base(size, align, max_addr);
if(alloc == 0)
panic("ERROR: Failed to allocate %pa bytes below %pa.\n");
return alloc;
}
phys_addr_t __init __memblock_alloc_base(phys_addr_t size, phys_addr_t align, phys_addr_t max_addr)
{
return memblock_alloc_base_nid(size, align, max_addr, NUMA_NO_NODE, MEMBLOCK_NONE);
}
memblock_phys_alloc
用于获得指定长度的物理内存
3.5.1.182. memblock_resion_memory_base_pfn
static inline unsigned long memblock_region_memory_base_pfn(const struct memblock_region *reg)
{
return PFN_UP(reg->base);
}
memblock_region_memory_base_pfn
用于获得memblock_region起始物理地址对应的页帧
3.5.1.183. memblock_region_memory_end_pfn
static inline unsigned long memblock_region_memory_end_pfn(const struct memblock_region *reg)
{
return PFN_DOWN(reg->base + reg->size);
}
memblock_region_memory_end_pfn
用于获得memblock_region终止物理地址对应的页帧号
3.5.1.184. memblock_remove_range
static int __init_memblock memblock_remove_range(struct memblock_type *type,
phys_addr_t base, phys_addr_t size)
{
int start_rgn, end_rgn;
int i, ret;
ret = memblock_isolate_range(type, base, size, &start_rgn, &end_rgn);
if(ret)
return ret;
for(i = end_rgn - 1; i >= start_rgn; i--)
memblock_remove_region(type, i);
return 0;
}
memblock_remove_range
从指定的memblock_type中移除一定范围的内存区块
3.5.1.185. memblock_remove
int __init_memblock memblock_remove(phys_addr_t base, phys_addr_t size)
{
phys_addr_t end = base + size - 1;
return memblock_remove_range(&memblock.memory, base, size);
}
3.5.1.186. memblock_remove_region
static void __init_memblock memblock_remove_region(struct memblock_type *type, unsigned long r)
{
type->total_size -= type->regions[r].size;
memmove(&type->regions[r], &type->regions[r + 1],
(type->cnt - (r + 1)) * sizeof(type->regions[r]));
type->cnt--;
if(type->cnt == 0)
{
WARN_ON(type->total_size != 0);
type->cnt = 1;
type->regions[0].base = 0;
type->regions[0].size = 0;
type->regions[0].flags = 0;
memblock_set_region_node(&type->regions[0], MAX_NUMNODES);
}
}
memblock_remove_region
用于从memblock_type region中移除指定的region
3.5.1.187. memblock_reserve
int __init_memblock memblock_reserve(phys_addr_t base, phys_addr_t size)
{
phys_addr_t end = base + size - 1;
return memblock_add_range(&memblock.reserved, base, size, MAX_NUMNODES, 0);
}
memblock_reserve
将内存区块加入到MEMBLOCK的保留区
3.5.1.188. memblock_search
static int __init_memblock memblock_search(struct memblock_type *type, phys_addr_t addr)
{
unsigned int left = 0, right = type->cnt;
do {
unsigned int mid = (right + left) / 2;
if(addr < type->regions[mid].base)
right = mid;
else if(addr >= (type->regions[mid].base + type->regions[mid].size))
left = mid + 1;
else
return mid;
} while(left < right);
return -1;
}
3.5.1.189. memblock_start_of_DRAM
phys_addr_t __init_memblock memblock_start_of_DRAM(void)
{
return memblock.memory.regions[0].base;
}
3.5.1.190. movable_node_is_enabled
static inline bool movable_node_is_enabled(void)
{
return movable_node_enabled;
}