一:busyobx层的分析
这段时间,在忙到一个项目时,需要在busybox中用到reboot命令,开始在busybox中的shell中输入reboot命令,始终如下的信息,然后就停止在那里了,无法重启...为了彻底的弄明白这个问题,我在网络上找了很久,终于有个人写的一个reboot流程分析,我就借花献佛.在这里重新分析下busybox是如何运行这个命令,同时又是如何调用到linux内核中的mach_reset中的arch_reset,当针对不同的arm芯片时,作为linux内核开发和驱动开发的朋友,对于这个流程还是一定要了解的。要不,出现问题,又如何找出问题呢。忘记了reboot的打印信息了,如下:
[plain]view plaincopy
print?
thesystemisgoingdownnow!!
sendingsigtermtoallprocesses.
sendingsigkilltoallprocesses.
pleasestandbywhilerebootingthesystem.
restartingsystem.
.
通过分析busybox1.20.0的代码可以看出在init.c中有这样一行的代码,如下:
[cpp]view plaincopy
print?
intinit_main(intargc,char**argv)main_externally_visible;
intinit_main(intargcunused_param,char**argv)
{
staticconstintmagic[]={
rb_halt_system,
rb_power_off,
rb_autoboot
};
staticconstsmallintsignals[]={sigusr1,sigusr2,sigterm};
......
/*structsysinfoislinux-specific*/
#ifdef__linux__
/*makesurethereisenoughmemorytodosomethinguseful.*/
if(enable_swaponoff){//是否配置了swapoff命令
structsysinfoinfo;
if(sysinfo(&info)==0
&&(info.mem_unit?info.mem_unit:1)*(longlong)info.totalram<1024*1024
){
message(l_console,lowmemory,forcingswapon);
/*swapon-arequires/proctypically*/
new_init_action(sysinit,mount-tprocproc/proc,);
/*trytoturnonswap*/
new_init_action(sysinit,swapon-a,);
run_actions(sysinit);/*waitandremoving*/
}
}
#endif
......
/*makethecommandlinejustsayinit-thatsall,nothingelse*/
strncpy(argv[0],init,strlen(argv[0]));
/*wipeargv[1]-argv[n]sotheydon'tclutterthepslisting*/
while(*++argv)
memset(*argv,0,strlen(*argv));
/*setupsignalhandlers*/
/*setupsignalhandlers*/
if(!debug_init){
structsigactionsa;
bb_signals(0
+(1<
+(1<
+(1<
,halt_reboot_pwoff);//看到这个halt_reboot_pwoff
signal(sigquit,restart_handler);/*re-execanotherinit*///看到这个restart_handler函数,这是我们需要分析的
/*stophandlermustallowonlysigcontinsideitself*/
memset(&sa,0,sizeof(sa));
sigfillset(&sa.sa_mask);
sigdelset(&sa.sa_mask,sigcont);
sa.sa_handler=stop_handler;
/*nb:sa_flagsdoesn'thavesa_restart.
*itmustbeabletointerruptwait().
*/
sigaction_set(sigtstp,&sa);/*pause*/
/*doesnotworkasintended,atleastin2.6.20.
*sigstopissimplyignoredbyinit:
*/
sigaction_set(sigstop,&sa);/*pause*/
/*sigint(ctrl-alt-del)mustinterruptwait(),
*settinghandlerwithoutsa_restartflag.
*/
bb_signals_recursive_norestart((1
if(!(a->action_type&restart))
continue;
/*startingfromhere,wewon'treturn.
*thusdon'tneedtoworryaboutpreservingerrno
*andsuch.
*/
reset_sighandlers_and_unblock_sigs();
run_shutdown_and_kill_processes();
#ifdefrb_enable_cad
/*allowctrl-alt-deltorebootthesystem.
*thisishowkernelsetsitupforinit,wefollowsuit.
*/
reboot(rb_enable_cad);/*misnomer*/
#endif
if(open_stdio_to_tty(a->terminal)){
dbg_message(l_console,tryingtore-exec%s,a->command);
/*theoreticallyshouldbesafe.
*butinpractice,kernelbugsmayleave
*unkillableprocesses,andwait()mayblockforever.
*ohwell.hopingnewinitwon'tbetoosurprised
*byhavingchildrenitdidn'tcreate.
*/
//while(wait(null)>0)
//continue;
init_exec(a->command);
}
/*openorexecfailed*/
pause_and_low_level_reboot(rb_halt_system);
/*notreached*/
}
}
通过分析,我们看到他们都会有调用这两个函数:reset_sighandlers_and_unblock_sigs();以及run_shutdown_and_kill_processes();,我们重点关注如下这个函数:
[cpp]view plaincopy
print?
staticvoidrun_shutdown_and_kill_processes(void)
{
/*runeverythingtoberunatshutdown.thisisdone_prior_
*tokillingeverything,incasepeoplewishtousescriptsto
*shutthingsdowngracefully...*/
run_actions(shutdown);
message(l_console|l_log,thesystemisgoingdownnow!);
/*sendsignalstoeveryprocess_except_pid1*/
kill(-1,sigterm);
message(l_console|l_log,sentsig%stoallprocesses,term);
sync();
sleep(1);
kill(-1,sigkill);
message(l_console,sentsig%stoallprocesses,kill);
sync();
/*sleep(1);-callerstakecareaboutmakingapause*/
}
嘿嘿,终于看到了上面的打印信息:the system is going down now !! 以及sending sigterm to all processes. 同时在上面的halt_reboot_pwoff和restart_handler中都会调用这样一个函数,如下:
[cpp]view plaincopy
print?
staticvoidpause_and_low_level_reboot(unsignedmagic)noreturn;
staticvoidpause_and_low_level_reboot(unsignedmagic)
{
pid_tpid;
/*allowtimeforlastmessagetoreachserialconsole,etc*/
sleep(1);
/*wehavetoforkhere,sincethekernelcallsdo_exit(exit_success)
*inlinux/kernel/sys.c,whichcancausethemachinetopanicwhen
*theinitprocessexits...*/
pid=vfork();
if(pid==0){/*child*/
reboot(magic);
_exit(exit_success);
}
while(1)
sleep(1);
}
看到了吗?有一个reboot(magic)函数,对于vfork函数,请参考fork函数。这里不多说了.... 我们现在来看看reboot.h文件,如下:
[cpp]view plaincopy
print?
/*
*definitionsrelatedtothereboot()systemcall,
*sharedbetweeninit.candhalt.c.
*/
#include
#ifndefrb_halt_system
#ifdefined(__linux__)
#definerb_halt_system0xcdef0123
#definerb_enable_cad0x89abcdef
#definerb_disable_cad0
#definerb_power_off0x4321fedc
#definerb_autoboot0x01234567
#elifdefined(rb_halt)
#definerb_halt_systemrb_halt
#endif
#endif
/*stopsystemandswitchpoweroffifpossible.*/
#ifndefrb_power_off
#ifdefined(rb_powerdown)
#definerb_power_offrb_powerdown
#elifdefined(__linux__)
#definerb_power_off0x4321fedc
#else
#warningpoweroffunsupported,usinghaltasfallback
#definerb_power_offrb_halt_system
#endif
#endif
而在linux的内核中的定义如下:
busybox和linux内核中的reboot的定义值是一样的。看到了没有了。这个很重要的哦,否则busybox是无法调用linux内核的reboot函数。
二:linux内核层的分析
linux内核是如何衔接busybox的reboot函数的呢,如下代码:
[cpp]view plaincopy
print?
/*
*rebootsystemcall:forobviousreasonsonlyrootmaycallit,
*andevenrootneedstosetupsomemagicnumbersintheregisters
*sothatsomemistakewon'tmakethisrebootthewholemachine.
*youcanalsosetthemeaningofthectrl-alt-del-keyhere.
*
*rebootdoesn'tsync:dothatyourselfbeforecallingthis.
*/
syscall_define4(reboot,int,magic1,int,magic2,unsignedint,cmd,
void__user*,arg)
{
charbuffer[256];
intret=0;
/*weonlytrustthesuperuserwithrebootingthesystem.*/
if(!capable(cap_sys_boot))
return-eperm;
/*forsafety,werequiremagicarguments.*/
if(magic1!=linux_reboot_magic1||
(magic2!=linux_reboot_magic2&&
magic2!=linux_reboot_magic2a&&
magic2!=linux_reboot_magic2b&&
magic2!=linux_reboot_magic2c))
return-einval;
/*insteadoftryingtomakethepower_offcodelooklike
*haltwhenpm_power_offisnotsetdoittheeasyway.
*/
if((cmd==linux_reboot_cmd_power_off)&&!pm_power_off)
cmd=linux_reboot_cmd_halt;
lock_kernel();
switch(cmd){
caselinux_reboot_cmd_restart:
kernel_restart(null);//这个就是重新启动linx的命令
break;
caselinux_reboot_cmd_cad_on:
c_a_d=1;
break;
caselinux_reboot_cmd_cad_off:
c_a_d=0;
break;
caselinux_reboot_cmd_halt:
kernel_halt();
unlock_kernel();
do_exit(0);
panic(cannothalt);
caselinux_reboot_cmd_power_off:
kernel_power_off();
unlock_kernel();
do_exit(0);
break;
caselinux_reboot_cmd_restart2:
if(strncpy_from_user(&buffer[0],arg,sizeof(buffer)-1)<0){
unlock_kernel();
return-efault;
}
buffer[sizeof(buffer)-1]='\0';
kernel_restart(buffer);
break;
#ifdefconfig_kexec
caselinux_reboot_cmd_kexec:
ret=kernel_kexec();
break;
#endif
#ifdefconfig_hibernation
caselinux_reboot_cmd_sw_suspend:
ret=hibernate();
break;
#endif
default:
ret=-einval;
break;
}
unlock_kernel();
returnret;
}
继续跟踪kernel_restart()函数,如下:
最终会调用一个machine_restart(cmd)函数,这个是跟具体的芯片有很大的关系的,我们进一步的分析如下:
看到了吗,最终是调用arch_reset来复位整个系统的。同时我们也看到了s3c2440的reset的函数如下:
在arm_pm_restart = s3c24xx_pm_restart()函数,最终也是调用arm_machine_restart(mod, cmd)来实现的。而在arm_machine_restart()函数中,最终也是调用arch_reset()函数来实现,而这个函数是在哪里呢。在s3c2440没有看到arch_reset函数的实现,因此从s3c2410中找到了如下的代码,请继续看下面的代码:
终于看到了arch_reset函数,最终是采用s3c2410或者s3c2440的watchdog来实现reboot的命令的。大家可以想想,busybox的poweroff命令,是如何实现通过linux系统关闭整个系统的电源呢,其实很简单,只需要实现下面的函数中的pm_power_off的回调函数即可。
我们可以通过一个gpio来控制整个系统的电源,而通过上面的pm_power_off的回调函数来实现,只需要在pm_power_off函数对gpio进行操作就可以了。你看不是很简单吗?
宝骏310W将于7月11日上市,预售价4.48万起!!!
优化信号链的电源系统 — 第2部分:高速数据转换器
电子管胆味校声电路的改进
华为MATE系列命名确定,从MATE20延续到MATE90
VR沉浸式娱乐助力合肥VR小镇产业生态
基于Linux与Busybox的Reboot命令流程分析
当前CBB电容的发展分析
芯海科技CS32G020Q助力手机与车机的智慧互联
iphone8发布会倒计时:iphone8颜色汇总:黑色、银色和腮红金,新配色腮红金很惊艳但是估计买不到
iPhone8黑白版设计图,看了卖肾也要买
基于51单片机的蜂鸣器设计
罗德与施瓦茨的ATC语音质量保证系统增强安全性、可靠性和效率
ICT在线测试机
一位电气工程师的十大忠告
2016年可穿戴行业年终盘点 未来走向何方
这个国产手机品牌成立不到四年却获奖无数一加3t依旧强悍
【嵌入式学习】4412开发板学习笔记之超级终端工具设置问题
增程式油电混动系统 中大型SUV理想ONE正式亮相
2021年Q1全球HEV节能乘用车销量约为71.6万辆
KING 耳机放大电路图