1. Linux 內存的大小獲取過程
硬件:tiny4412
軟件:linux3.0.86,uboot-tiny4412
目的:梳理linux start-kernel階段,獲取內核大小的過程,並將內存bank個數,start ,size信息,放入meminfo中
tiny4412平臺,傳遞內存的信息,是通過 u-boot,傳遞tag的方式來傳遞內存的大小的,而不是通過dtb的方式。
【start_kernel()->setup_arch()】
//首先判斷是否從fdt中,獲取machine desc
mdesc = setup_machine_fdt(__atags_pointer);
if (!mdesc)
//以tags的方式,獲取machine desc
mdesc = setup_machine_tags(machine_arch_type);
static struct machine_desc * __init setup_machine_tags(unsigned int nr)
{
struct tag *tags = (struct tag *)&init_tags;
struct machine_desc *mdesc = NULL, *p;
char *from = default_command_line;
init_tags.mem.start = PHYS_OFFSET;
/*
* locate machine in the list of supported machines.
*/
for_each_machine_desc(p)
if (nr == p->nr) {
printk("Machine: %s\n", p->name);
mdesc = p;
break;
}
...
if (tags->hdr.tag == ATAG_CORE) {
if (meminfo.nr_banks != 0)
squash_mem_tags(tags);
save_atags(tags);
parse_tags(tags);
}
首先會通過for_each_machine_desc查找對應的 machine ID。
machine ID 是放置在 .arch.info.init 這個section的數據。 通過MACHINE_START 註冊的machine將會放在在 .arch.info.init 這個section 中。
以tag的形式傳遞過來的數據 ,不同的數據有不同的tag及進行標識
#define ATAG_CORE 0x54410001
#define ATAG_MEM 0x54410002
#define ATAG_CMDLINE 0x54410003
#define ATAG_RDIMG 0x54410004
parse_tags(tags);
static void __init parse_tags(const struct tag *t)
{
//編譯傳遞過來的tag
for (; t->hdr.size; t = tag_next(t))
if (!parse_tag(t))
printk(KERN_WARNING
"Ignoring unrecognised tag 0x%08x\n",
t->hdr.tag);
}
static int __init parse_tag(const struct tag *tag)
{
extern struct tagtable __tagtable_begin, __tagtable_end;
struct tagtable *t;
for (t = &__tagtable_begin; t < &__tagtable_end; t++)
if (tag->hdr.tag == t->tag) {
t->parse(tag);
break;
}
return t < &__tagtable_end;
}
在setup.c 中,會通過__tagtable 註冊以下執行的函數,方式在taglist.init這個setction中,
struct tagtable {
u32 tag;
int (*parse)(struct tag *);
};
#define __tag __used __attribute__((__section__(".taglist.init")))
#define __tagtable(tag, fn) \
static struct tagtable __tagtable_##fn __tag = { tag, fn
static int __init parse_tag_mem32(const struct tag *tag)
{
return arm_add_memory(tag->u.mem.start, tag->u.mem.size);
}
__tagtable(ATAG_MEM, parse_tag_mem32);
有u-boot傳遞過來的帶有ATAG_MEM 的信息,將會執行 arm_add_memory函數
int __init arm_add_memory(phys_addr_t start, unsigned long size)
{
struct membank *bank = &meminfo.bank[meminfo.nr_banks];
if (meminfo.nr_banks >= NR_BANKS) {
printk(KERN_CRIT "NR_BANKS too low, "
"ignoring memory at 0x%08llx\n", (long long)start);
return -EINVAL;
}
/*
* Ensure that start/size are aligned to a page boundary.
* Size is appropriately rounded down, start is rounded up.
*/
size -= start & ~PAGE_MASK;
bank->start = PAGE_ALIGN(start);
bank->size = size & PAGE_MASK;
/*
* Check whether this memory region has non-zero size or
* invalid node number.
*/
if (bank->size == 0)
return -EINVAL;
meminfo.nr_banks++;
return 0;
}
arm_add_memory函數,拿到由u-boot傳遞過來的哪個bank的start地址和長度,放到變量meminfo中。