android reboot 过程

转载请标注原文地址:http://blog.csdn.net/uranus_wm/article/details/10542715

 

这里说的reboot是指software restart,常用场景有两种:

1.android应用层出现关键进程挂起,如system进程挂起引起的reboot

2.直接通过tty控制台输入reboot

 

以android4.0.4版本,samsung-exynos-4412+s5p8767(PMU)为例:

 

Android部分:

文件位置:/frameworks/base/core/java/com/android/internal/app/ShutdownThread.java

文件中有一个单例模式class ShutdownThread,包含reboot和shutdown两个静态方法。

 

public final class ShutdownThread extends Thread {

    /**
     * Request a clean shutdown, waiting for subsystems to clean up their
     * state etc.  Must be called from a Looper thread in which its UI
     * is shown.
     *
     * @param context Context used to display the shutdown progress dialog.
     * @param reason code to pass to the kernel (e.g. "recovery"), or null.
     * @param confirm true if user confirmation is needed before shutting down.
     */
    public static void reboot(final Context context, String reason, boolean confirm) {
        mReboot = true;
        mRebootReason = reason;
        shutdown(context, confirm);
    }
}


通过调用内部方法rebootOrShutdown会再调用到静态类Power.java的reboot方法

文件位置:/frameworks/base/core/java/android/os/power.java

    /**
     * Reboot the device.
     * @param reason code to pass to the kernel (e.g. "recovery"), or null.
     *
     * @throws IOException if reboot fails for some reason (eg, lack of
     *         permission)
     */
    public static void reboot(String reason) throws IOException
    {
        rebootNative(reason);
    }

    private static native void rebootNative(String reason) throws IOException ;

 

通过jni调用,一层层跟踪发现最终调用到

文件位置: /bionic/libc/unistd/reboot.c

int reboot (int  mode) 
{
    return __reboot( LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, mode, NULL );
}


进一步通过文件位置:/bionic/libc/arch-sh/syscalls/__reboot.S 调用系统调用__NR_reboot,其系统调用号是 88

转载请标注原文地址:http://blog.csdn.net/uranus_wm/article/details/10542715

 

文件位置:/bionic/libc/include/sys/linux-syscalls.h

#define __NR_umask                        (__NR_SYSCALL_BASE + 60)
#define __NR_reboot                       (__NR_SYSCALL_BASE + 88)
#define __NR_syslog                       (__NR_SYSCALL_BASE + 103)


到Kernel部分:

文件位置:/kernel/arch/arm/include/asm 有一个对应的系统调用号,reboot当然也是88

#define __NR_swapon			(__NR_SYSCALL_BASE+ 87)
#define __NR_reboot			(__NR_SYSCALL_BASE+ 88)
#define __NR_readdir			(__NR_SYSCALL_BASE+ 89)


文件位置:/kernel/kernel/sys.c 定义了reboot的函数实现

/*
 * 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)
{
	/* 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_HALT:
		kernel_halt();
		do_exit(0);
		panic("cannot halt");

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

	}
	mutex_unlock(&reboot_mutex);
}


然后我们就看到了kernel_restart(NULL);

文件位置:/kernel/kernel/sys.c

void kernel_restart_prepare(char *cmd)
{
	blocking_notifier_call_chain(&reboot_notifier_list, SYS_RESTART, cmd);
	system_state = SYSTEM_RESTART;
	usermodehelper_disable();
	device_shutdown();
	syscore_shutdown();
}

/**
 *	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);
}
EXPORT_SYMBOL_GPL(kernel_restart);


device_shutdown()通知devices_kset上的设备调用shutdown注册函数

syscore_shutdown()通知syscore_ops_list上的设备调用shutdown注册函数

跟踪下来这个list上只有一个设备注册了shutdown函数:

文件位置:/kernel/kernel/irq/generic-chip.c

static struct syscore_ops irq_gc_syscore_ops = {
	.suspend = irq_gc_suspend,
	.resume = irq_gc_resume,
	.shutdown = irq_gc_shutdown,
};


回到kernel_restart(),下面调用的就是machine_restart();

这个函数和cpu平台有关,exynos4412平台的函数位置在

文件位置:/kernel/arch/arm/kernel/process.c

void machine_shutdown(void)
{
#ifdef CONFIG_SMP
	smp_send_stop();
#endif
}

void machine_restart(char *cmd)
{
	machine_shutdown();
	arm_pm_restart(reboot_mode, cmd);
}

 

exynos4412是个四核cpu0~cpu3,smp_send_stop()就是通知cpu1,cpu2,cpu3停止运行

最后调用的是同文件的arm_machine_restart

void arm_machine_restart(char mode, const char *cmd)
{
	/* Flush the console to make sure all the relevant messages make it
	 * out to the console drivers */
	arm_machine_flush_console();

	/* Disable interrupts first */
	local_irq_disable();
	local_fiq_disable();

	/*
	 * Tell the mm system that we are going to reboot -
	 * we may need it to insert some 1:1 mappings so that
	 * soft boot works.
	 */
	setup_mm_for_reboot(mode);

	/* Clean and invalidate caches */
	flush_cache_all();

	/* Turn off caching */
	cpu_proc_fin();

	/* Push out any further dirty data, and ensure cache is empty */
	flush_cache_all();

	/*
	 * Now call the architecture specific reboot code.
	 */
	arch_reset(mode, cmd);

	/*
	 * Whoops - the architecture was unable to reboot.
	 * Tell the user!
	 */
	mdelay(1000);
	printk("Reboot failed -- System halted\n");
	while (1);
}

 

幸运的是在arch_reset之前,printk都是有效的,如果调试中碰到log不能输出的问题,可以参考文章:使用printascii与printhex输出log到串口

原文地址:http://blog.csdn.net/uranus_wm/article/details/11176877 

实际使用reboot命令reset时,发现cpu_proc_fin()这个函数执行不过去,不知道是不是我们开发板的问题,我注释掉才可以通过

 

最后面的arch_reset(mode, cmd)是最终的reset函数

文件位置:/kernel/arch/plat-s5p/reset.c

void arch_reset(char mode, const char *cmd)
{
	/* SWRESET support in s5p_reset_hook() */

	if (s5p_reset_hook)
		s5p_reset_hook();

	/* Perform reset using Watchdog reset
	 * if there is no s5p_reset_hook()
	 */

	arch_wdt_reset();
}

这里调用s5p_reset_hook()是通过设置cpu的专有寄存器SWRESET复位,

而后面的arch_wdt_reset()是通过设置watch_dog是手机复位,这一句实际上保险措施,实际不一定执行的到


文件位置:/kernel/arch/mach-exynos/cpu-exynos4.c

 /* set sw_reset function */ 
s5p_reset_hook = exynos4_sw_reset;

static void exynos4_sw_reset(void)
{
 int count = 3;

 while (count--) {
  __raw_writel(0x1, S5P_SWRESET);
  mdelay(500);
 }
}

S5P_SWRESET是exynos4412提供的专有寄存器,当该寄存器被设置后,系统会软件重启,重启之后可以通过查询RST_STAT寄存器获取cpu reset信息

 

启动过程: 

1. reset之后cpu会和正常开机一样,从irom开始执行;和正常开机不同的是他没有power_key的上电过程,通过外部cmu启动给cpu上电。

2. irom内置一段小程序用于初始化soc,这段程序就是在irom上直接执行

3. load BL1,BL1包含一些芯片相关的配置,BL1存储在外部存储器,如EMMC上

4. load BL2,BL2包含一些平台相关的配置,BL2也存储在外部存储器上,如EMMC上

5. 前四点由于没有源码,仅能通过文档介绍了解,最后跳转到u-boot

文件位置:/arch/arm/cpu/armv7/start.S 

.globl _start
_start: b	reset
reset:
 bl cpu_init_crit


 

文件位置:/board/samsung/smdk4212/lowlevel_init.S

	.globl lowlevel_init
lowlevel_init:

	/* use iROM stack in bl2 */
	ldr	sp, =0x02060000
	push {lr}

	/* check reset status  */
	ldr     r0, =(INF_REG_BASE + INF_REG1_OFFSET)
	ldr     r1, [r0]

	/* Sleep wakeup reset */
	ldr	r2, =S5P_CHECK_SLEEP
	cmp	r1, r2
	beq	wakeup_reset

	/* During sleep/wakeup or AFTR mode, pmic_init function is not available 
	 * and it causes delays. So except for sleep/wakeup and AFTR mode, 
	 * the below function is needed 
	 */
	bl pmic_init
	
	bl uart_asm_init
	
	bl read_om

这里会通过专有寄存器INF_REG1_OFFSET判断是wakeup还是reset,关于系统sleep和wakeup我会专门有一篇文章介绍android suspend and resume过程:

原文链接:http://blog.csdn.net/uranus_wm/article/details/11569913

 

uart_asm_init初始化串口,可以打印单个字符

read_om是通过om pin判断cpu是sdcard启动还是emmc启动等等

 

关于系统正常开机流程,以前写过一篇文章专门介绍android2.2 boot process details,比较简单,以后再补充吧!

原文链接:http://blog.csdn.net/uranus_wm/article/details/7864585

你可能感兴趣的:(android reboot 过程)