linux驱动——cmdline原理及利用
最近安卓項目中想要獲取內核cmdline特定的啟動參數,因為我們在他的U-BOOT中定制了啟動參數,需要在驅動中處理,這個手段其實很常見,今天mark個腳印。
內核中如果你用cat /proc/cmdline,你會看見大致如下的打印:
console=ttyHSL0,115200,n8 androidboot.console=ttyHSL0...。當然如果我也可以在我們的項目比如掃描頭的型號加個字段scanner=se955,等號賦值,name和value跟前后字段以空格分割。
那么如何從中獲取呢?!
方法一:直接獲取原始的cmdline的,就是獲取/proc/cmdline屬性值,在代碼中就是讀取全局變量saved_command_line這個字符串,然后自行處理,缺點是這個處理的時機比較晚,在設備驅動中處理,優點開發者自由度比較大。
方法二:利用內核的__setup或者early_param。這個兩個函數宏實質上是一樣的,就是early_param比__setup先處理,優點他們在內核啟動階段運行,都在設備驅動前預先運行。上定義代碼,
#define __setup_param(str, unique_id, fn, early) ? ? ? ? ? ?/
? ? static char __setup_str_##unique_id[] __initdata = str; ? ?/
? ? static struct obs_kernel_param __setup_##unique_id ? ?/
? ? ? ? __attribute_used__ ? ? ? ? ? ? ? ?/
? ? ? ? __attribute__((__section__(".init.setup"))) ? ?/
? ? ? ? __attribute__((aligned((sizeof(long))))) ? ?/
? ? ? ? = { __setup_str_##unique_id, fn, early }
? ? ? ??
#define __setup(str, fn) ? ? ? ? ? ? ? ? ? ?/
? ? __setup_param(str, fn, fn, 0)
? ??
#define early_param(str, fn) ? ? ? ? ? ? ? ? ? ?/
? ? __setup_param(str, fn, fn, 1)
其中結構體定義如下:
struct obs_kernel_param {
const char *str;
int (*setup_func)(char *);
int early;
};
鏈接時以這個結構體保存在.init.setup段,實際在存儲上就是個結構體數組。仔細看鏈接文件vmlinux.lds時,你會發現.init.setup實際上就是大致有這樣的描述
__setup_start = .;?
*(.init.setup)?
__setup_end = .;
它的意思就是你所有定義的struct obs_kernel_param結構體變量連續序排在__setup_start 和__setup_end 存儲之間,到時候就可以在這2個標記之間搜索。而__setup_start這個標記只被do_early_param和obsolete_checksetup。而這2個函數都是在kernel/init/main.c下的函數start_kernel中運行,并且do_early_param先運行,接著obsolete_checksetup后運行。調用大致流程如下start_kernel->parse_early_param->parse_early_options->parse_args->parse_one->do_early_param,而start_kernel->parse_args->parse_one->unknown_bootoption->obsolete_checksetup。翻代碼代碼中可見先調用__early_param定義的解析參數函數及__setup定義的(console及earlycon)的參數解析函數
接著再調用__setup定義的其他解析參數函數。
使用例子:
static int __init scanner_setup(char *str)
{
?? ?if (!str)
?? ??? ?return 0;
?? ?if(!strcmp("se955",str)){
?? ??? ?scanner_id = SCANNER_SE955;
?? ?}else if(!strcmp("ue966",str)){
?? ??? ?scanner_id = SCANNER_UE966;
?? ?}else if(!strcmp("n4313",str)){
?? ??? ?scanner_id = SCANNER_N4313;
?? ?}else if(!strcmp("n5600",str)){
?? ??? ?scanner_id = SCANNER_N5600;
?? ?}else if(!strcmp("se655",str)){
?? ??? ?scanner_id = SCANNER_SE655;
?? ?}else if(!strcmp("se4710",str)){
?? ??? ?scanner_id = SCANNER_SE4710;
?? ?}else{
?? ??? ?scanner_id = SCANNER_SE4500;
?? ?}
?? ?printk("%s %d\n",__func__,scanner_id);
?? ?return 1;
}
__setup("scanner=", scanner_setup);
該段代碼對應于cmdline中的...?scanner=se955 ...,這樣的話,kernel已啟動會先搜索scanner=字符串,如果找到的話就把=號后面的字符串值傳遞給給回調函數scanner_setup,這樣的話str參數就是se955,并且這些代碼是在設備驅動運行之前。
NOTE:我碰到的問題,如果同一個字段被比如scanner字段,__setup使用兩次,__setup(“scanner=”,fun_1)和__setup(“scanner=”,fun_2)在2個文件中,那么只會有1個被使用,誰先被鏈接,誰運行,另一個失效,因為運行不到他,代碼決定,只匹配第一個。
---------------------?
作者:sgmenghuo?
來源:CSDN?
原文:https://blog.csdn.net/sgmenghuo/article/details/41251739?
版權聲明:本文為博主原創文章,轉載請附上博文鏈接!
總結
以上是生活随笔為你收集整理的linux驱动——cmdline原理及利用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 发卡机项目开发总结
- 下一篇: git学习:关于origin和maste