x86平台下Android系统的Linux部分的重启分析

-----------------------------------------------------------------------
本文系本站原创,欢迎转载!
转载请注明出处:http://blog.csdn.net/android_huber
交流邮箱:dp.shao@gmail.com
-----------------------------------------------------------------------

        在Android下,我们在命令行中敲入reboot后系统的重启首先是执行的reboot这个应用程序。这是一个比较简单的小程序,其源码在   system/core/toolbox/reboot.c,主要的代码如下:

    if(poweroff)
        ret = __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_POWER_OFF, NULL);
    else if(argc > optind)
        ret = __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART2, argv[optind]);
    else
        ret = reboot(RB_AUTOBOOT);
这边都是通过系统调用进入内核的,LINUX_REBOOT_MAGIC1和LINUX_REBOOT_MAGIC2是两个幻数。进入kernel/sys.c中

/*
 * Reboot system call: for obvious reasons only root may call it,
 * and even root needs to set up some magic numbers in the registers
 * so that some mistake won't make this reboot the whole machine.
 * You can also set the meaning of the ctrl-alt-del-key here.
 *
 * reboot doesn't sync: do that yourself before calling this.
 */
SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd,
		void __user *, arg)
{
	char buffer[256];
	int ret = 0;

	/* We only trust the superuser with rebooting the system. */
	if (!capable(CAP_SYS_BOOT))
		return -EPERM;

	/* For safety, we require "magic" arguments. */
	if (magic1 != LINUX_REBOOT_MAGIC1 ||
	    (magic2 != LINUX_REBOOT_MAGIC2 &&
	                magic2 != LINUX_REBOOT_MAGIC2A &&
			magic2 != LINUX_REBOOT_MAGIC2B &&
	                magic2 != LINUX_REBOOT_MAGIC2C))
		return -EINVAL;

	/* Instead of trying to make the power_off code look like
	 * halt when pm_power_off is not set do it the easy way.
	 */
	if ((cmd == LINUX_REBOOT_CMD_POWER_OFF) && !pm_power_off)
		cmd = LINUX_REBOOT_CMD_HALT;

	mutex_lock(&reboot_mutex);
	switch (cmd) {
	case LINUX_REBOOT_CMD_RESTART:
		kernel_restart(NULL);
		break;

	case LINUX_REBOOT_CMD_CAD_ON:
		C_A_D = 1;
		break;

	case LINUX_REBOOT_CMD_CAD_OFF:
		C_A_D = 0;
		break;

	case LINUX_REBOOT_CMD_HALT:
		kernel_halt();
		do_exit(0);
		panic("cannot halt");

	case LINUX_REBOOT_CMD_POWER_OFF:
		kernel_power_off();
		do_exit(0);
		break;

	case LINUX_REBOOT_CMD_RESTART2:
		if (strncpy_from_user(&buffer[0], arg, sizeof(buffer) - 1) < 0) {
			ret = -EFAULT;
			break;
		}
		buffer[sizeof(buffer) - 1] = '\0';

		kernel_restart(buffer);
		break;

#ifdef CONFIG_KEXEC
	case LINUX_REBOOT_CMD_KEXEC:
		ret = kernel_kexec();
		break;
#endif

#ifdef CONFIG_HIBERNATION
	case LINUX_REBOOT_CMD_SW_SUSPEND:
		ret = hibernate();
		break;
#endif

	default:
		ret = -EINVAL;
		break;
	}
	mutex_unlock(&reboot_mutex);
	return ret;
}
我们通过命令行敲reboot的话进入的是LINUX_REBOOT_CMD_RESTART这个分支,可以看到接下来会调用kernel_restart(NULL);

/**
 *	kernel_restart - reboot the system
 *	@cmd: pointer to buffer containing command to execute for restart
 *		or %NULL
 *
 *	Shutdown everything and perform a clean reboot.
 *	This is not safe to call in interrupt context.
 */
void kernel_restart(char *cmd)
{
        kernel_restart_prepare(cmd);
	if (!cmd)
		printk(KERN_EMERG "Restarting system.\n");
	else
		printk(KERN_EMERG "Restarting system with command '%s'.\n", cmd);
	kmsg_dump(KMSG_DUMP_RESTART);
	machine_restart(cmd);
}
这个函数里面会打印出我们常看到的log,Restarting system.

kernel_restart_prepare(cmd);里会去调用设备的shutdown接口,去power off设备,并且发送SYS_RESTART的广播,

void kernel_restart_prepare(char *cmd)
{
	blocking_notifier_call_chain(&reboot_notifier_list, SYS_RESTART, cmd);
	system_state = SYSTEM_RESTART;
	device_shutdown();
	sysdev_shutdown();
}
接着执行machine_restart(cmd);我们会调到arch/x86/kernel/reboot.c中,这里需要知道一个ops

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
};
machine_restart就是执行这行这里的native_machine_restart

static void native_machine_restart(char *__unused)
{
	printk("machine restart\n");

	if (!reboot_force) {
		printk("native_machine_restart reboot_force:%d\n", reboot_force);
		machine_shutdown();
	}
	__machine_emergency_restart(0);
}
machine_shutdown();中执行一些shutdown工作,重启的工作在__machine_emergency_restart(0);
static void __machine_emergency_restart(int emergency)
{
	reboot_emergency = emergency;
	machine_ops.emergency_restart();
}
调用ops中的emergency_restart

static void native_machine_emergency_restart(void)
{
	int i;

	if (reboot_emergency)
		emergency_vmx_disable_all();

	tboot_shutdown(TB_SHUTDOWN_REBOOT);
	
	/* Tell the BIOS if we want cold or warm reboot */
	*((unsigned short *)__va(0x472)) = reboot_mode;

	for (;;) {
		/* Could also try the reset bit in the Hammer NB */
		switch (reboot_type) {
		case BOOT_KBD:			
			mach_reboot_fixups(); /* for board specific fixups */

			for (i = 0; i < 10; i++) {
				printk("%d\n", i);
				kb_wait();
				udelay(50);
				outb(0xfe, 0x64); /* pulse reset low */
				udelay(50);
			}

		case BOOT_TRIPLE:
			
			load_idt(&no_idt);
			
			__asm__ __volatile__("int3");
			
			reboot_type = BOOT_KBD;
			break;

#ifdef CONFIG_X86_32
		case BOOT_BIOS:
                        machine_real_restart(jump_to_bios, sizeof(jump_to_bios));
                        reboot_type = BOOT_KBD;
			break;
#endif

		case BOOT_ACPI:
			
			acpi_reboot();
			reboot_type = BOOT_KBD;
			break;

		case BOOT_EFI:
			
			if (efi_enabled)
				efi.reset_system(reboot_mode ?
						 EFI_RESET_WARM :
						 EFI_RESET_COLD,
						 EFI_SUCCESS, 0, NULL);
			reboot_type = BOOT_KBD;
			break;

		case BOOT_CF9:
			
			port_cf9_safe = true;
			/* fall through */

		case BOOT_CF9_COND:
			
			if (port_cf9_safe) {
				u8 cf9 = inb(0xcf9) & ~6;
                          
				outb(cf9|2, 0xcf9); /* Request hard reset */
				udelay(50);
				outb(cf9|6, 0xcf9); /* Actually do the reset */
				udelay(50);
			}
			reboot_type = BOOT_KBD;
			break;
		}
	}
}
        这边就是重启的最后部分了,默认的是通过BOOT_KBD方式重启的,这种方式是通过键盘控制器去模拟按下键盘上的reset键来重启的,往0x64端口中写0xfe即可,然后系统会在__asm__ __volatile__("int3");中中断。int3是一个breakpoint,用来使程序停止在这,等待重启。

        这里再说下,通过cf9来重启,用注释来解释Use the so-called "PCI reset register", CF9,通过这个寄存器可以使系统hard reset。

        对于上面的一些重启方式,我将在下一篇文章里去介绍他们的用法,以及我在调试reboot中遇到的一些问题,这篇文章主要就是分析一下reboot的流程。

同样,附一张流程图:




需要清晰大图的请留邮箱


  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值