kenrel: 5.10
arch: aarch64
启动阶段经过arm64_memblock_init之后,通过gdb可以查看到memblock布局如下,此处的memblock可以理解为在线的memory
(gdb) p/x memblock
$5 = {
bottom_up = 0x0,
current_limit = 0xffffffffffffffff,
memory = {
cnt = 0x1,
max = 0x80,
total_size = 0x40000000,
regions = 0xffff8000120a8848,
name = 0xffff80001139cc28
},
reserved = {
cnt = 0x5,
max = 0x181,
total_size = 0x58a20c4,
regions = 0xffff8000120a9448,
name = 0xffff80001127e258
}
}
其中memblock.memory如下:
(gdb) p/x *(struct memblock_region *)0xffff8000120a8848
$6 = {
base = 0x40000000,
size = 0x40000000,
flags = 0x0,
nid = 0x10
}
memblock.reserved如下:
(gdb) p/x *(struct memblock_region *)0xffff8000120a9448@5
$9 = {{
base = 0x40200000,
size = 0x2592000,
flags = 0x0,
nid = 0x10
},
{
base = 0x42797000,
size = 0x9000,
flags = 0x0,
nid = 0x10
},
{
base = 0x48000000,
size = 0x100000,
flags = 0x0,
nid = 0x10
},
{
base = 0x7cdf8f38,
size = 0x90c4,
flags = 0x0,
nid = 0x10
},
{
base = 0x7ce02000,
size = 0x31fe000,
flags = 0x0,
nid = 0x10
}}
从如上可以看出,只有一个memory区域,5个reserved区域
__next_mem_pfn_range
void __init_memblock __next_mem_pfn_range(int *idx, int nid,
unsigned long *out_start_pfn,
unsigned long *out_end_pfn, int *out_nid)
{
struct memblock_type *type = &memblock.memory;
struct memblock_region *r;
int r_nid;
while (++*idx < type->cnt) {
r = &type->regions[*idx];
r_nid = memblock_get_region_node(r);
if (PFN_UP(r->base) >= PFN_DOWN(r->base + r->size))
continue;
if (nid == MAX_NUMNODES || nid == r_nid)
break;
}
if (*idx >= type->cnt) {
*idx = -1;
return;
}
if (out_start_pfn)
*out_start_pfn = PFN_UP(r->base);
if (out_end_pfn)
*out_end_pfn = PFN_DOWN(r->base + r->size);
if (out_nid)
*out_nid = r_nid;
}
上面的函数主要是通过遍历memblock.memory下的每个memblock_region区域,找到node id为nid的memblock_region区域将其起始物理地址和结束物理地址转换为物理页帧号分别保存在out_start_pfn和out_end_pfn返回。
注意:物理页帧号与物理地址是紧密关联的,如物理地址为0x40000000,则物理页帧号为0x40000
这里列出memblock, memblock_type, memblock_region 结构体定义,以说明他们之间的关系
struct memblock_region {
phys_addr_t base;
phys_addr_t size;
enum memblock_flags flags;
#ifdef CONFIG_NEED_MULTIPLE_NODES
int nid;
#endif
};
struct memblock_type {
unsigned long cnt;
unsigned long max;
phys_addr_t total_size;
struct memblock_region *regions;
char *name;
};
struct memblock {
bool bottom_up;
phys_addr_t current_limit;
struct memblock_type memory;
struct memblock_type reserved;
};
for_each_mem_pfn_range
#define for_each_mem_pfn_range(i, nid, p_start, p_end, p_nid)
for (i = -1, __next_mem_pfn_range(&i, nid, p_start, p_end, p_nid);
i >= 0; __next_mem_pfn_range(&i, nid, p_start, p_end, p_nid))
根据前面__next_mem_pfn_range的定义,for_each_mem_pfn_range实际上就是遍历memblock.memory下的每个memblock_region区域,找到node id与参数 nid相等 的memblock_region区域,将它的起始pfn和结束pfn,node id,分别保存在p_start,p_end,p_nid返回。这里注意的是如果nid为MAX_NUMNODES,则表示遍历所有的node



