Linux cmdline 解析(CMA 预留内存)

Linux Version:3.14
Android : L

cmdline在kernel启动的时候被解析.
cmdline启动的log中可以看到,比如我的是

command_line = androidboot.bootloader=1537.100_M1S1 androidboot.serialno=004999010640000 bl_shared_ram=4k@0xfff4f000 console=ttyS0,115200n8 idle=halt debug androidboot.hardware=sofia_lte cma=170M nolapic_pm firmware_class.path=/system/vendor/firmware androidboot.selinux=permissive androidboot.selinux=permissive

以CMA为例

cma=170M

drivers/base/dma-contiguous.c定义了

static int __init early_cma(char *p)
{
    pr_debug("%s(%s)\n", __func__, p);
    size_cmdline = memparse(p, &p);
    return 0;
}
early_param("cma", early_cma);

early_param是一个宏:

/* NOTE: fn is as per module_param, not __setup!  Emits warning if fn
* returns non-zero. */
#define early_param(str, fn)                                    \
        __setup_param(str, fn, fn, 1)
/*
* Only for really core code.  See moduleparam.h for the normal way.
*
* Force the alignment so the compiler doesn't space elements of the
* obs_kernel_param "array" too far apart in .init.setup.
*/
#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 }

展开后:

struct obs_kernel_param  __setup_early_cma
          __used __section(.init.setup)  
          __attribute__((aligned((sizeof(long))))) 
          = { "cma", early_cma, 1}

include/asm-generic/vmlinux.lds.h +628 定义了


#define INIT_SETUP(initsetup_align)                                     \
                . = ALIGN(initsetup_align);                             \
                VMLINUX_SYMBOL(__setup_start) = .;                      \
                *(.init.setup)                                          \
                VMLINUX_SYMBOL(__setup_end) = .;

.init.setup段的开始和结束分别用__setup_start和__setup_end表示。
Kernel中有很多类似的声明,这些结构体变量被保存在 .init.setup段中。
Kernel初始化时
Start_kernel—-> parse_early_param—->parse_early_options—-> do_early_param

该函数会遍历 __setup_start和 __setup_end之间的所有结构体,然后将 cmdline中的各个参数与字符串 ”cma”比较,如果匹配,那么调用 early_cma函数。

kernel启动过程中
Start_kernel—->setup_arch—->early_init_fdt_scan_reserved_mem—->fdt_init_reserved_mem—->__reserved_mem_alloc_size

—->of_get_flat_dt_probe ,从 dts获取 cma-default节点

—->__reserved_mem_alloc_size 设置cma reserved area大小

/**
* dma_contiguous_reserve() - reserve area(s) for contiguous memory handling
* @limit: End address of the reserved memory (optional, 0 for any).
*
* This function reserves memory from early allocator. It should be
* called by arch specific code once the early allocator (memblock or bootmem)
* has been activated and all other subsystems have already allocated/reserved
* memory.
*/
void __init dma_contiguous_reserve(phys_addr_t limit, phys_addr_t size)
{
     phys_addr_t selected_size = 0;

     pr_debug("%s(limit %08lx)\n", __func__, (unsigned long)limit);

     if (size != 0)
          selected_size = size;
     else if (size_cmdline != -1) {
          selected_size = size_cmdline;
     } else {
#ifdef CONFIG_CMA_SIZE_SEL_MBYTES
          selected_size = size_bytes;
#elif defined(CONFIG_CMA_SIZE_SEL_PERCENTAGE)
          selected_size = cma_early_percent_memory();
#elif defined(CONFIG_CMA_SIZE_SEL_MIN)
          selected_size = min(size_bytes, cma_early_percent_memory());
#elif defined(CONFIG_CMA_SIZE_SEL_MAX)
          selected_size = max(size_bytes, cma_early_percent_memory());
#endif
     }

     if (selected_size && !dma_contiguous_default_area) {
          pr_debug("%s: reserving %ld MiB for global area\n", __func__,
               (unsigned long)selected_size / SZ_1M);

          dma_contiguous_reserve_area(selected_size, 0, limit,
                             &dma_contiguous_default_area);
     }
};

优先处理DTS中获取的cma reserved area size。

Note:setup_arch比parse_early_param先执行,所以还没来得及解析cmline中的cma parameter,CMA预留内存的大小已经被确定了。

你可能感兴趣的:(kernel)