Chinaunix首页 | 论坛 | 博客
  • 博客访问: 9412694
  • 博文数量: 1748
  • 博客积分: 12961
  • 博客等级: 上将
  • 技术积分: 20070
  • 用 户 组: 普通用户
  • 注册时间: 2009-01-09 11:25
个人简介

偷得浮生半桶水(半日闲), 好记性不如抄下来(烂笔头). 信息爆炸的时代, 学习是一项持续的工作.

文章分类

全部博文(1748)

文章存档

2024年(24)

2023年(26)

2022年(112)

2021年(217)

2020年(157)

2019年(192)

2018年(81)

2017年(78)

2016年(70)

2015年(52)

2014年(40)

2013年(51)

2012年(85)

2011年(45)

2010年(231)

2009年(287)

分类: LINUX

2011-12-02 09:23:38

BusyBox 版本1.10-2

用户在console下输入reboot命令,

busybox会调用到halt_main

int halt_main(int argc ATTRIBUTE_UNUSED, char **argv)

{

.....

/* Perform action. */
if (ENABLE_INIT && !(flags & 4)) {
if (ENABLE_FEATURE_INITRD) {
pid_t *pidlist = find_pid_by_name("linuxrc");
if (pidlist[0] > 0)
rc = kill(pidlist[0], signals[which]);
if (ENABLE_FEATURE_CLEAN_UP)
free(pidlist);
}
if (rc)
rc = kill(1, signals[which]); //
如果INIT 进程有,就发信号给它
} else
rc = reboot(magic[which]); //
否则直接调用kernelreboot

if (rc)
bb_error_msg("no");
return rc;

}

init.c/init_main中(这是INITconfig 以后才会使用的函数,也就是busybox默认的init)

int init_main(int argc ATTRIBUTE_UNUSED, char **argv)
{
struct init_action *a;
pid_t wpid;

......

bb_signals(0
+ (1 << SIGUSR1) /* halt */
+ (1 << SIGUSR2) /* poweroff */
+ (1 << SIGTERM) /* reboot */
, halt_reboot_pwoff); //
挂载reboot,halt,poweroff 信号处理的handler

.....

}

所以此时当halt_main中发信号要reboot以后,系统进入halt_reboot_pwoff

static void halt_reboot_pwoff(int sig)

{

const char *m;

int rb;

kill_all_processes(); //杀死所有进程,也就是发消息

m = "halt";

rb = RB_HALT_SYSTEM;

if (sig == SIGTERM) {

m = "reboot";

rb = RB_AUTOBOOT;

} else if (sig == SIGUSR2) {

m = "poweroff";

rb = RB_POWER_OFF;

}

message(L_CONSOLE | L_LOG, "Requesting system %s", m);

/* allow time for last message to reach serial console */

sleep(2);

init_reboot(rb); //真正调用kernel的重启动

loop_forever();

}

static void kill_all_processes(void)

{

/* run everything to be run at "shutdown". This is done _prior_

* to killing everything, in case people wish to use scripts to

* shut things down gracefully... */

run_actions(SHUTDOWN); //调用run_action ,它会parse inittab中的action去做一些事情

/* first disable all our signals */

sigprocmask_allsigs(SIG_BLOCK);

message(L_CONSOLE | L_LOG, "The system is going down NOW!");

/* Allow Ctrl-Alt-Del to reboot system. */

init_reboot(RB_ENABLE_CAD); //告诉系统可以用CAD来重启

/* Send signals to every process _except_ pid 1 */

message(L_CONSOLE | L_LOG, "Sending SIG%s to all processes", "TERM");

kill(-1, SIGTERM); //发送终止信号

sync(); //刷cache回设备

sleep(1);

message(L_CONSOLE | L_LOG, "Sending SIG%s to all processes", "KILL");

kill(-1, SIGKILL); //杀死进程

sync();

sleep(1);

}

/* Run all commands of a particular type */

static void run_actions(int action_type)

{

struct init_action *a, *tmp;

for (a = init_action_list; a; a = tmp) {

tmp = a->next;

if (a->action_type & action_type) {

// Pointless: run() will error out if open of device fails.

///* a->terminal of "" means "init's console" */

//if (a->terminal[0] && access(a->terminal, R_OK | W_OK)) {

// //message(L_LOG | L_CONSOLE, "Device %s cannot be opened in RW mode", a->terminal /*, strerror(errno)*/);

// delete_init_action(a);

//} else

if (a->action_type & (SYSINIT | WAIT | CTRLALTDEL | SHUTDOWN | RESTART)) {

waitfor(run(a)); //做事的是run函数

delete_init_action(a);

} else if (a->action_type & ONCE) {

run(a);

delete_init_action(a);

} else if (a->action_type & (RESPAWN | ASKFIRST)) {

/* Only run stuff with pid==0. If they have

* a pid, that means it is still running */

if (a->pid == 0) {

a->pid = run(a);

}

}

}

}

}

static pid_t run(const struct init_action *a)

{

init_exec(a->command); //真正执行命令, 这个函数应该会使用之前parse inittab 中产生的shutddown action

}

回头来看 init_reboot

先看下magic 定义

RB_HALT_SYSTEM = 0xcdef0123, /* FIXME: this overflows enum */

RB_ENABLE_CAD = 0x89abcdef,

RB_DISABLE_CAD = 0,

RB_POWER_OFF = 0x4321fedc,

RB_AUTOBOOT = 0x01234567,

对比linux kernel的看看,一致

#define LINUX_REBOOT_CMD_RESTART 0x01234567

#define LINUX_REBOOT_CMD_HALT 0xCDEF0123

#define LINUX_REBOOT_CMD_CAD_ON 0x89ABCDEF

#define LINUX_REBOOT_CMD_CAD_OFF 0x00000000

#define LINUX_REBOOT_CMD_POWER_OFF 0x4321FEDC

#define LINUX_REBOOT_CMD_RESTART2 0xA1B2C3D4

#define LINUX_REBOOT_CMD_SW_SUSPEND 0xD000FCE2

#define LINUX_REBOOT_CMD_KEXEC 0x45584543

static void init_reboot(unsigned long magic)

{

pid_t pid;

/* We have to fork here, since the kernel calls do_exit(0) in

* linux/kernel/sys.c, which can cause the machine to panic when

* the init process is killed.... */

pid = vfork();

if (pid == 0) { /* child */

reboot(magic); //最重要的事情,调用reboot

_exit(0);

}

waitfor(pid);

}

Busybox的调用顺序看完了,我们来看看linux reboot做了哪些事情

Linux2.6.28 kernel(是不是有点老,手边就这个最方便) sys.c/sys_reboot

Sys_reboot reboot的系统调用,自然我们看这个

asmlinkage long sys_reboot(int magic1, int magic2, unsigned int cmd, void __user * arg)

{

case LINUX_REBOOT_CMD_RESTART:

kernel_restart(NULL); //系统重启

break;

case LINUX_REBOOT_CMD_CAD_ON:

C_A_D = 1; //允许用户ctrl_alt_del重启

break;

case LINUX_REBOOT_CMD_CAD_OFF:

C_A_D = 0;

break;

case LINUX_REBOOT_CMD_HALT:

kernel_halt();

unlock_kernel();

do_exit(0);

break;

case LINUX_REBOOT_CMD_POWER_OFF:

kernel_power_off();

unlock_kernel();

do_exit(0);

break;

….

}

系统重启:

void kernel_restart(char *cmd)

{

kernel_restart_prepare(cmd); //这个函数中kernel/和设备驱动等需要做重启前的准备工作

if (!cmd) {

printk(KERN_EMERG "Restarting system./n");

} else {

printk(KERN_EMERG "Restarting system with command '%s'./n", cmd);

}

printk("./n");

machine_restart(cmd);

}

kernel 的重启准备

void kernel_restart_prepare(char *cmd)
{
blocking_notifier_call_chain(&reboot_notifier_list, SYS_RESTART, cmd); //调用reboot 的notifier 链表,很多必要的设备,驱动都会注册一个reboot_notifier,这样在内核准备重启时还有机会把设备最后需要做的事情完成
system_state = SYSTEM_RESTART;
device_shutdown();
sysdev_shutdown();
}

设备驱动会调用这个函数来注册reboot notifier:

/**
* register_reboot_notifier - Register function to be called at reboot time
* @nb: Info about notifier function to be called
*
* Registers a function with the list of functions
* to be called at reboot time.
*
* Currently always returns zero, as blocking_notifier_chain_register()
* always returns zero.
*/
int register_reboot_notifier(struct notifier_block *nb)
{
return blocking_notifier_chain_register(&reboot_notifier_list, nb);
}

看看MTD 设备挂的接口:

struct mtd_info *cfi_cmdset_0001(struct map_info *map, int primary)
{
.....

mtd->priv = map;
mtd->type = MTD_NORFLASH;

/* Fill in the default mtd operations */
mtd->erase = cfi_intelext_erase_varsize;
mtd->read = cfi_intelext_read;
mtd->write = cfi_intelext_write_words;
mtd->sync = cfi_intelext_sync;
mtd->lock = cfi_intelext_lock;
mtd->unlock = cfi_intelext_unlock;
mtd->suspend = cfi_intelext_suspend;
mtd->resume = cfi_intelext_resume;
mtd->flags = MTD_CAP_NORFLASH;
mtd->name = map->name;
mtd->writesize = 1;

mtd->reboot_notifier.notifier_call = cfi_intelext_reboot;

....

}

static struct mtd_info *cfi_intelext_setup(struct mtd_info *mtd)
{
...
register_reboot_notifier(&mtd->reboot_notifier);

....
return NULL;
}

再看看这个函数,如果是bus就调用bus的shutdown,如果设备就调用设备的。

/**
* device_shutdown - call ->shutdown() on each device to shutdown.
*/
void device_shutdown(void)
{
struct device *dev, *devn;

list_for_each_entry_safe_reverse(dev, devn, &devices_kset->list,
kobj.entry) {
if (dev->bus && dev->bus->shutdown) {
dev_dbg(dev, "shutdown/n");
dev->bus->shutdown(dev);
} else if (dev->driver && dev->driver->shutdown) {
dev_dbg(dev, "shutdown/n");
dev->driver->shutdown(dev);
}
}
kobject_put(sysfs_dev_char_kobj);
kobject_put(sysfs_dev_block_kobj);
kobject_put(dev_kobj);
}

其他看看吧

void machine_restart(char *cmd)

{

machine_ops.restart(cmd);

}

struct machine_ops machine_ops = {

.power_off = native_machine_power_off,

.shutdown = native_machine_shutdown,

.emergency_restart = native_machine_emergency_restart,

.restart = native_machine_restart,

.halt = native_machine_halt,

#ifdef CONFIG_KEXEC

.crash_shutdown = native_machine_crash_shutdown,

#endif

};

static void native_machine_restart(char *__unused)

{

printk("machine restart/n");

if (!reboot_force)

machine_shutdown(); //à最后指向native_machine_shutdown

machine_emergency_restart(); //->最后指向native_machine_emergency_restart

}

native_machine_emergency_restart 中定义了集中reboot的的方式

方式如下,它们由reboot_setup设置,用户也可以传入,default by KBD

/* reboot=b[ios] | s[mp] | t[riple] | k[bd] | e[fi] [, [w]arm | [c]old]

warm Don't set the cold reboot flag

cold Set the cold reboot flag

bios Reboot by jumping through the BIOS (only for X86_32)

smp Reboot by executing reset on BSP or other CPU (only for X86_32)

triple Force a triple fault (init)

kbd Use the keyboard controller. cold reset (default)

acpi Use the RESET_REG in the FADT

efi Use efi reset_system runtime service

force Avoid anything that could hang.

*/

Reboot_setupSetup.c/setup_arch调用,

顺便分析下native_machine_emergency_restart

native_machine_emergency_restart

{

For (;;){

..

switch (reboot_type) {

case BOOT_KBD:

... //使用keyboard 8042reboot硬件

case BOOT_TRIPLE:

case BOOT_BIOS://bios boot

case BOOT_ACPI://使用ACPI table提供的方法来boot

case BOOT_EFI://使用EFI runtime service reset reset 系统

}

}

阅读(5415) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~