linux kernel下输入输出console如何实现.docx
《linux kernel下输入输出console如何实现.docx》由会员分享,可在线阅读,更多相关《linux kernel下输入输出console如何实现.docx(6页珍藏版)》请在冰豆网上搜索。
linuxkernel下输入输出console如何实现
linuxkernel下输入输出console如何实现
,kernel下printkconsole的选择,kernel下console的注册,user空间console的选择。
一指定kernel调试console首先看kernel启动时如何获取和处理指定的console参数。
kernel的启动参数cmdline可以指定调试console,如指定‘console=ttyS0,115200’,kernel如何解析cmdline,我之前写了一篇博文如下:
根据之前的分析,cmdline中有console=xxx,start_kernel中parse_args遍历.init.setup段所有obs_kernel_param。
kernel/printk.c中注册了‘console=’的解析函数console_setup(注册了obs_kernel_param),所以匹配成功,会调用console_setup来解析,如下:
[cpp]viewplaincopystaticint__initconsole_setup(char*str){charbuf[sizeof(console_cmdline[0].name)+4];/*4forindex*/char*s,*options,*brl_options=NULL;intidx;#ifdefCONFIG_A11Y_BRAILLE_CONSOLEif(!
memcmp(str,"brl,",4)){brl_options="";str+=4;}elseif(!
memcmp(str,"brl=",4)){brl_options=str+4;str=strchr(brl_options,',');if(!
str){printk(KERN_ERR"needportnameafterbrl=\n");return1;}*(str++)=0;}#endif/**Decodestrintoname,index,options.*/if(str[0]>='0'&&str[0]<='9'){strcpy(buf,"ttyS");strncpy(buf+4,str,sizeof(buf)-5);}else{strncpy(buf,str,sizeof(buf)-1);}buf[sizeof(buf)-1]=0;if((options=strchr(str,','))!
=NULL)*(options++)=0;#ifdef__sparc__if(!
strcmp(str,"ttya"))strcpy(buf,"ttyS0");if(!
strcmp(str,"ttyb"))strcpy(buf,"ttyS1");#endiffor(s=buf;*s;s++)if((*s>='0'&&*s<='9')||*s==',')break;idx=simple_strtoul(s,NULL,10);*s=0;__add_preferred_console(buf,idx,options,brl_options);console_set_on_cmdline=1;return1;}__setup("console=",console_setup);参数是console=的值字符串,如“ttyS0,115200”,console_setup对console=参数值做解析,以ttyS0,115200为例,最后buf=“ttyS”,idx=0,options="115200",brl_options=NULL。
调用__add_preferred_console如下:
[cpp]viewplaincopy/**Ifexclusive_consoleisnon-NULLthenonlythisconsoleistobeprintedto.*/staticstructconsole*exclusive_console;/**Arrayofconsolesbuiltfromcommandlineoptions(console=)*/structconsole_cmdline{charname[8];/*Nameofthedriver*/intindex;/*Minordev.touse*/char*options;/*Optionsforthedriver*/#ifdefCONFIG_A11Y_BRAILLE_CONSOLEchar*brl_options;/*Optionsforbrailledriver*/#endif};#defineMAX_CMDLINECONSOLES8staticstructconsole_cmdlineconsole_cmdline[MAX_CMDLINECONSOLES];staticintselected_console=-1;staticintpreferred_console=-1;intconsole_set_on_cmdline;EXPORT_SYMBOL(console_set_on_cmdline);staticint__add_preferred_console(char*name,intidx,char*options,char*brl_options){structconsole_cmdline*c;inti;/**Seeifthisttyisnotyetregistered,and*ifwehaveaslotfree.*/for(i=0;i<MAX_CMDLINECONSOLES&&console_cmdline[i].name[0];i++)if(strcmp(console_cmdline[i].name,name)==0&&console_cmdline[i].index==idx){if(!
brl_options)selected_console=i;return0;}if(i==MAX_CMDLINECONSOLES)return-E2BIG;if(!
brl_options)selected_console=i;c=&console_cmdline[i];strlcpy(c->name,name,sizeof(c->name));c->options=options;#ifdefCONFIG_A11Y_BRAILLE_CONSOLEc->brl_options=brl_options;#endifc->index=idx;return0;}
kernel利用结构体数组console_cmdline[8],最多可支持8个cmdline传入的console参数。
__add_preferred_console将nameidxoptions保存到数组下一个成员console_cmdline结构体中,如果数组中已有重名,则不添加,并置selected_console为最新添加的console_cmdline的下标号。
比如cmdline中有“console=ttyS0,115200console=ttyS1,9600”则在console_cmdline[8]数组中console_cmdline[0]代表ttyS0,console_cmdline[1]代表ttyS1,而selected_console=1.二kernel下printkconsole的选择kernel下调试信息是通过printk输出,如果要kernel正常打印,则需要搞明白printk怎么选择输出的设备。
关于printk的实现原理,我在刚工作的时候写过一篇博文,kernel版本是2.6.21的,但是原理还是一致的,可供参考:
viewplaincopy#defineMAX_CMDLINECONSOLES8staticstructconsole_cmdlineconsole_cmdline[MAX_CMDLINECONSOLES];staticintselected_console=-1;staticintpreferred_console=-1;intconsole_set_on_cmdline;EXPORT_SYMBOL(console_set_on_cmdline);/*Flag:
consolecodemaycallschedule()*/staticintconsole_may_schedule;#ifdefCONFIG_PRINTKstaticchar__log_buf[__LOG_BUF_LEN];staticchar*log_buf=__log_buf;staticintlog_buf_len=__LOG_BUF_LEN;staticunsignedlogged_chars;/*Numberofcharsproducedsincelastread+clearoperation*/staticintsaved_console_loglevel=-1;log_buf的大小由kernelmenuconfig配置,我配置的CONFIG_LOG_BUF_SHIFT为17,则log_buf为128k。
printk内容会一直存在log_buf中,log_buf满了之后则会从头在开始存,覆盖掉原来的数据。
根据printk的实现原理,printk最后调用console_unlock实现log_buf数据刷出到指定设备。
这里先不关心printk如何处理logbuf数据(比如添加内容级别),只关心printk如何一步步找到指定的输出设备,根据printk.c代码,可以找到如下线索。
printk->vprintk->console_unlock->call_console_drivers->_call_console_driv