meminfo初始化

1. u-boot中设置启动参数
     1)启动命令
          u-boot-env.txt
          bootcmd 
               if ${recovery}; then 
                    run nandrecovery; 
               else 
                    if mmc init; then 
                         if run loadbootscript; then 
                              run bootscript; 
                         else 
                              if run loaduImage; then 
                                   run mmcboot; 
                              else 
                                   run nandboot; 
                              fi; 
                         fi;
                    else 
                         run nandboot; 
                    fi; 
               fi
          nandboot 
               echo Booting from nand ...; 
               run nandargs; 
               nand read ${loadaddr} boot; 
               booti 0x82000008
          nandargs
                              setenv bootargs console=${console} init=${init} mem=${mem} ip=${ip} mpurate=${mpurate} omap_vout.vid1_static_vrfb_alloc=y vram=${vram} omapfb.vram=0:8M androidboot.console=${tty} root=${root_nand} rootfstype=${rootfstype_nand} ubi.mtd=${ubi_mtd}

     这一部分属于commandline,会在setup_commandline_tag中插入params数组,并标上ATAG_CMDLINE,会在parse_args的时候,用对应的处理函数来处理,具体如下
     
     2)环境变量
          include/configs/d7800.h
     #define CONFIG_EXTRA_ENV_SETTINGS \
    "init=/init\0" \
    "mem=256M\0" \
    "mpurate=800\0" \
   ……

2.kernel中用parse_args解析此bootarg,具体可参考另一份笔记Linux启动参数“init=xxx”分析
     parse_args -> parse_one -> unknown_bootoption -> obsolete_checksetup -> obs_kernel_param.setup_func = early_mem

3.kernel中设置对应bootarg的处理函数
     early_param("mem", early_mem); -> __setup_param(str, fn, fn, 1) -> 
     #define __setup_param(str, unique_id, fn, early)            \
     static const char __setup_str_##unique_id[] __initconst \
        __aligned(1) = str; \
     static struct obs_kernel_param __setup_##unique_id  \
        __used __section(.init.setup)           \
        __attribute__((aligned((sizeof(long)))))    \
        = { __setup_str_##unique_id, fn, early }   

4.early_mem函数
          static int __init early_mem(char *p)
{
    static int usermem __initdata = 0;
    unsigned long size, start;
    char *endp;
    /*
     * If the user specifies memory size, we
     * blow away any automatically generated
     * size.
     */

    if (usermem == 0) {
        usermem = 1;
        meminfo.nr_banks = 0;
    }
        /*
     defined in arch/arm/plat-omap/include/plat/memory.h
     * PHYS_OFFSET  = UL(0x80000000)

     */
    start = PHYS_OFFSET;
    size  = memparse(p, &endp);
    if (*endp == '@')
        start = memparse(endp + 1, NULL);
    arm_add_memory(start, size);
    return 0;
}

最后遗留一个问题,假如有几块内存需要处理怎么办?
     没关系,Linux提供了对应的机制。就是__tagtable(ATAG_MEM, parse_tag_mem32);这是一张表格,代表了一组ATAG_MEM param,用parse_tag_mem32来处理。这一组param同样也是在u-boot阶段就加入了。即:
     do_bootm_linux -> setup_memory_tags (u-boot)
static void setup_memory_tags (bd_t *bd)
{
    int i;

    for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
        params->hdr.tag = ATAG_MEM;
        params->hdr.size = tag_size (tag_mem32);

        params->u.mem.start = bd->bi_dram[i].start;
        params->u.mem.size = bd->bi_dram[i].size;

        params = tag_next (params);
    }
}

     只不过在D7800中CONFIG_NR_DRAM_BANKS=1(configs/d7800.h)。

     meminfo中的内存地址全部是真正的物理地址。