本文基于reboot命令的具体实现,具体的硬件是mips架构的CAVIUM的CN63XX的CPU,内核版本为2.6.32.27
1,系统下面的命令
linux下面的一切都是文件,所以我们对应的命令也对应着文件,而命令如何链接到文件,这就是系统的配置问题了,主要是环境变量的PATH的配置,shell解析会自动去PATH环境变量下面的路径去寻找对应的处理。
如果是单个的命令,可能对应着一个单独的可执行程序,也可能是一个可执行程序对应着一批的命令,例如reboot,poweroff等命令都连接到了busybox文件系统里面,里面对命令再进行解析
A ,单个命令对应单个的可执行程序,例如:
-rwxr-xr-x 1 root root 174391 May 24 12:25 sed
-rwxr-xr-x 1 root root 312892 Jul 13 11:45 sup :我们自己开发的命令也可以放在该目录下面
B,多个命令对应一个可执行程序,然后该可执行程序再对不同的命令进行解析,例如:
rwxrwxrwx 1 root root 14 Jul 13 11:46 reboot -> ../bin/busybox
lrwxrwxrwx 1 root root 14 Jul 13 11:46 rfkill -> ../bin/busybox
lrwxrwxrwx 1 root root 14 Jul 13 11:46 rmmod -> ../bin/busybox
lrwxrwxrwx 1 root root 14 Jul 13 11:46 route -> ../bin/busybox
BusyBox就好像是个大工具箱,它集成压缩了 Linux 的许多工具和命令。
busybox的流程分析参见
附六。
reboot是系统调用:
2,系统处理接口的调用入口:
SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd,
void __user *, arg)
{
case LINUX_REBOOT_CMD_RESTART: //0x01234567
kernel_restart(NULL);
break;
}
3,具体实现接口流程
kernel_restart(/kernel/sys.c)
{
kernel_restart_prepare(cmd);
{
device_shutdown();
sysdev_shutdown();
}
machine_restart(cmd);
{
if (_machine_restart) //相关的调用流程参照附四说明
_machine_restart(command); --->octeon_restart(arch/mips/cavium-octeon/setup.c )
cvmx_write_csr(CVMX_CIU_SOFT_RST, 1);//主要就是写了一个CPU的重启寄存器
}
}
4,预重启的准备接口操作
kernel/sys.c文件:
void kernel_restart_prepare(char *cmd)
{
//调用所有的设备的reboot的通知器的接口,一般的设备驱动接口初始化都会赋值有此通知接口,在mtd_info结构体有这个元素。比如附二。
blocking_notifier_call_chain(&reboot_notifier_list, SYS_RESTART, cmd);
//这是一个menu,在文件init/main.c里面EXPORT_SYMBOL(system_state);
//在include/linux/kernel.h中定义 ,如附一
system_state = SYSTEM_RESTART;
//调用所有的设备驱动的dev->driver->shutdown(dev)接口dev->bus->shutdown(dev); ,device--》device_driver--》shutdown
//主要用于在内核注册驱动结构的设备 , 主链表:struct kset *devices_kset;
//从打印来看只有dev->bus->shutdown(dev);有设备,dev下面没有
device_shutdown();printk(KERN_EMERG "*** Shutdown device_shutdown .\n");
//关闭一些cpu相关的资源,包括clocksource,timekeeping,cpu
sysdev_shutdown();printk(KERN_EMERG "*** Shutdown sysdev_shutdown .\n");
}
5,实际重启的实现:
主要就是写了一个CPU的reset寄存器操作,CVMX_CIU_SOFT_RST手动写该寄存器也会导致CPU重启
machine_restart(cmd);
{
if (_machine_restart) //相关的调用流程参照附四说明
_machine_restart(command); --->octeon_restart(arch/mips/cavium-octeon/setup.c )
cvmx_write_csr(CVMX_CIU_SOFT_RST, 1);//主要就是写了一个CPU的重启寄存器
}
附一:
/* Values used for system_state */
extern enum system_states {
SYSTEM_BOOTING,
SYSTEM_RUNNING,
SYSTEM_HALT,
SYSTEM_POWER_OFF,
SYSTEM_RESTART,
SYSTEM_SUSPEND_DISK,
} system_state;
附二:
文件cfi_cmdset_0001.c中注册一些nor的mtd接口时: mtd->reboot_notifier.notifier_call = cfi_intelext_reboot;
附三:
内核device的初始化和注册以及添加的一些接口:
int device_add(struct device *dev)
int device_register(struct device *dev)
void device_initialize(struct device *dev)
void device_del(struct device *dev)
附四:
一些CPU相关的接口的调用流程:
start_kernel(init/main.c)
----》setup_arch(arch/mips/kernel/setup.c)
---->prom_init(arch/mips/cavium-octeon/setup.c)----
在这个接口里面初始化了一批的接口:
重启 : _machine_restart = octeon_restart;
挂起: _machine_halt = octeon_halt;
附五:
命令的调用流程
大量的系统命令都放置在了/sbin/目录下面,例如:
CPC depmod getty loadfont ntpd svlogd
acpid devmem halt loadkmap oct_linux_csr swapoff
add-shell dhcprelay hdparm logcheck pivot_root swapon
addgroup dnsd hotplug-call logread popmaildir switch_root
adduser dtweak hotplug2 losetup
poweroff sysctl
adjtimex e2fsck httpd lpd powertop syslogd
appdaemon ether-wake hwclock lsmod raidautorun sysupgrade
appmain fakeidentd ifconfig makedevs rdate telnetd
arp fbset ifdown mdev rdev tftpd
arping fbsplash ifenslave mkdosfs readprofile tunctl
bds_main fdformat ifplugd mke2fs
reboot ubiattach
blkid fdisk ifup mkfs.ext2 remove-shell ubidetach
blockdev firstboot inetd mkfs.ext3 rfkill ubimkvol
bootchartd flash_eraseall info-collect mkfs.minix rmmod ubirmvol
brctl flash_lock init mkfs.vfat route ubirsvol
bup flash_unlock insmod mkswap rtcwake ubiupdatevol
chat flashcp ip modinfo runlevel uci
chpasswd freeramdisk ipaddr modprobe sed udevtrigger
chroot fsck iplink mount_root sendmail udhcpc
cli fsck.ext2 iproute mtd setconsole udhcpd
config_set fsck.ext3 iprule myfsck setfont upgrade
core_zip.sh fsck.minix iptunnel nameif setlogcons vconfig
crond fstrim killall5 nanddump slattach watchdog
datasize fsuptime klogd nandwrite start-stop-daemon who_am_i
delgroup ftpd ldconfig nbd-client sulogin wifi
deluser getppid led.sh net-proxy sup zcip
而且大半部分都是软链接,链接到了文件系统:例如:
lrwxrwxrwx 1 root root 14 Jul 13 11:46 reboot -> ../bin/busybox
lrwxrwxrwx 1 root root 14 Jul 13 11:46 rfkill -> ../bin/busybox
lrwxrwxrwx 1 root root 14 Jul 13 11:46 rmmod -> ../bin/busybox
lrwxrwxrwx 1 root root 14 Jul 13 11:46 route -> ../bin/busybox
或者说直接就是单个的运行程序,例如:
-rwxr-xr-x 1 root root 174391 May 24 12:25 sed
-rwxr-xr-x 1 root root 312892 Jul 13 11:45 sup :我们自己开发的命令也可以放在该目录下面
附六:
busybox的流程简单分析。基于源码1.22.1
命令注册接口:
注册命令:include/applets.src.h文件
# define APPLET(name,l,s) int name##_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
# define APPLET_ODDNAME(name,main,l,s,name2) int main##_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
# define APPLET_NOEXEC(name,main,l,s,name2) int main##_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
# define APPLET_NOFORK(name,main,l,s,name2) int main##_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
IF_ACPID(APPLET(acpid, BB_DIR_SBIN, BB_SUID_DROP))
IF_ADDGROUP(APPLET(addgroup, BB_DIR_USR_SBIN, BB_SUID_DROP))
IF_IPROUTE(APPLET(iproute, BB_DIR_SBIN, BB_SUID_DROP))
IF_IPRULE(APPLET(iprule, BB_DIR_SBIN, BB_SUID_DROP))
IF_MOUNT(APPLET(mount, BB_DIR_BIN, IF_DESKTOP(BB_SUID_MAYBE) IF_NOT_DESKTOP(BB_SUID_DROP)))
IF_PKILL(APPLET_ODDNAME(pkill, pgrep, BB_DIR_USR_BIN, BB_SUID_DROP, pkill))
IF_PRINTF(APPLET_NOFORK(printf, printf, BB_DIR_USR_BIN, BB_SUID_DROP, printf))
IF_PWD(APPLET_NOFORK(pwd, pwd, BB_DIR_BIN, BB_SUID_DROP, pwd))
从上述两个宏可知,每个命令都有对应的处理函数,比如acpid_main ,mount_main 等等。
busybox的详细介绍参照:
http://blog.csdn.net/linuxarmsummary/article/details/12612269
busybox与内核的交互通过init 进程来进行。