向android中增加自定義的Linux核心啟動引數
前言,android裝置中常常需要新增自定義的核心配置,如imx51的primary_di定義 pmem定義等,這時需要使用__setup函式,下面的文章中詳述了該過程。
轉:如何增加自定義的Linux核心啟動引數
在驅動開發的過程中,有時為了除錯方便,需要給驅動傳入引數。下面就簡單說明,如何給驅動傳遞引數和驅動如何使用引數。
驅動可以編譯成模組,在需要時載入;也可以編譯進核心,和核心一起載入。
1.1驅動作為模組時的傳遞引數
可以在驅動中定義如下的巨集:(#include<linux/moduleparam.h>)
module_param(name, type, perm)
name是變數名;type是變數型別(bool,charp,int等);perm是訪問許可值,當perm=0時,不會在sysfs系統中生成相應的sysfs入口項;perm=S_IRUGO為對任何人只讀;S_IRUGO|S_IWUSR為允許root使用者修改引數。
例如:
static intmax_loop;
module_param(max_loop, int,0);
intloop(void)
{
inti=0;
for(i=0;i<max_loop;i++)
printk(“Inloop!/n”);
return0;
}
使用方法:
#insmod test.ko max_loop=10
1.2驅動不是模組,編譯進核心
這時,max_loop可以在核心啟動時傳入,驅動中實現時使用__setup巨集。
__setup(str, fn)
str為傳遞引數時使用的字串,fn是引數傳遞後對應的處理函式。
例如:
#ifndef MODULE
static int __initmax_loop_setup(char *str)
{
max_loop = simple_strtol(str, NULL,0);
return 1;
}
__setup(“max_loop=”,max_loop_setup);
#endif
在x86的grub(/boot/grub/menu.lst)中使用方法:
kernel /vmlinuz-2.6.30.5 ro root=/dev/sda1 max_loop=10
目前已有的核心啟動引數可以在此檔案查詢:documentation/kernel-parameters.txt。
1.3module_param和__setup實現概述
module_param巨集在標頭檔案include/linux/moduleparam.h中定義,呼叫順序如下:
module_paramàmodule_param_namedàmodule_param_callà__module_param_call(MODULE_PARAM_PREFIX,…)
最後,把用此巨集定義的引數放在__param段中:__section__ (“__param”)。
__param段引數的讀取,涉及到核心載入模組原理。在使用者空間執行insmod命令來載入模組時,會呼叫glibc(或uClibc)庫中的init_module系統呼叫,並把系統呼叫號傳遞給核心,核心根據此係統呼叫號,到硬體相關的一個系統呼叫表中找到此offset的函式並執行。
對於__setup巨集,在標頭檔案include/linux/init.h中定義,最後把用此巨集定義的引數放到.init.setup段中。
.init.setup段的讀取在do_early_param函式中,實現如下:
static int __initdo_early_param(char *param, char *val)
{
struct obs_kernel_param*p;
for (p = __setup_start; p<__setup_end; p++) {
//從.init.setup段開始處__setup_start讀取
if ((p->early&&strcmp(param, p->str) == 0) ||
(strcmp(param, “console”) == 0&&
strcmp(p->str, “earlycon”) ==0)
) {
if (p->setup_func(val)!= 0)
//呼叫__setup(str, fn)中指定的fn函式, val是從核心啟動傳入的引數值
printk(KERN_WARNING
“Malformed early option ‘%s’/n”,param);
}
}
return 0;
}
呼叫順序是:start_kernelàparse_early_paramàparse_early_optionsàdo_early_param
具體地說,首先,parse_early_param把傳遞給核心的命令列引數,複製到一個臨時變數tmp_cmdline中,然後傳遞給parse_early_options處理如下:
void __initparse_early_param(void)
{
strlcpy(tmp_cmdline, boot_command_line,COMMAND_LINE_SIZE);
parse_early_options(tmp_cmdline);
}
parse_early_options呼叫parse_args,parse_args把類似“max_loop=10”之類傳給核心的字串分解為字串”max_loop”和”10”,然後傳遞給parse_one,parse_one最後呼叫do_early_param。
do_early_param對param, val的處理上面已經說過了。