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预留内存的大小已经被确定了。