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

来源:互联网 发布:淘宝图片库 编辑:程序博客网 时间:2024/06/10 19:40

在 Android 下,
我们在命令行中敲入 reboot 后系统的重启首先是执行的 reboot 这个
应用程序。这是一个比较简单的小程序,其源码在
代码如下:
1 if
 if(poweroff)
2 ret
system/core/toolbox/reboot.c,主要的
=
__reboot(LINUX_REBOOT_MAGIC1,
LINUX_REBOOT_MAGIC2,
LINUX_REBOOT_CMD_POWER_OFF, NULL);
3
else if
if(argc > optind)
ret = __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART2,
4
argv[optind]);
5
else
ret = reboot(RB_AUTOBOOT);
6
这 边 都 是 通 过 系 统 调 用 进 入 内 核 的 , LINUX_REBOOT_MAGIC1 和
LINUX_REBOOT_MAGIC2 是两个幻数。进入 kernel/sys.c 中
7
/*
8 * Reboot system call: for obvious reasons only root may call it,
9 * and even root needs to set up some magic numbers in the registers
10 * so that some mistake won't make this reboot the whole machine.
11 * You can also set the meaning of the ctrl-alt-del-key here.
12 *
13 * reboot doesn't sync: do that yourself before calling this.
14 */
15 SYSCALL_DEFINE4(reboot, int magic1, int magic2, unsigned int cmd,
int,
int,
int,
16
void __user *, arg)
17 {
18 char buffer[256];
19 int ret = 0;
20
21
/* We only trust the superuser with rebooting the system. */
22
if (!capable(CAP_SYS_BOOT))
return -EPERM;
23
24
25 /* For safety, we require "magic" arguments. */
26 if (magic1 != LINUX_REBOOT_MAGIC1 ||
(magic2 != LINUX_REBOOT_MAGIC2 &&
27
magic2 != LINUX_REBOOT_MAGIC2A &&
28
magic2 != LINUX_REBOOT_MAGIC2B &&
29
magic2 != LINUX_REBOOT_MAGIC2C))
30
return -EINVAL;
31
32
33 /* Instead of trying to make the power_off code look like
34 * halt when pm_power_off is not set do it the easy way.
35 */
36
37
if ((cmd == LINUX_REBOOT_CMD_POWER_OFF) && !pm_power_off)
cmd = LINUX_REBOOT_CMD_HALT;
38
39 mutex_lock(&reboot_mutex);
40 switch (cmd) {
41 case LINUX_REBOOT_CMD_RESTART:
42 kernel_restart(NULL);
43 break
  break;
44
45
case LINUX_REBOOT_CMD_CAD_ON:
46 C_A_D = 1;
47 break
  break;
48
49
case LINUX_REBOOT_CMD_CAD_OFF:
50 C_A_D = 0;
51 break
  break;
52
53
case LINUX_REBOOT_CMD_HALT:
54 kernel_halt();
55 do_exit(0);
56 panic("cannot halt");
57
58
case LINUX_REBOOT_CMD_POWER_OFF:
59 kernel_power_off();
60 do_exit(0);
61 break
  break;
62
63
64
65
case LINUX_REBOOT_CMD_RESTART2:
if (strncpy_from_user(&buffer[0], arg, sizeof
sizeof(buffer) - 1) < 0) {
ret = -EFAULT;
break
break;
66
67 }
68 sizeof
  buffer[sizeof
 sizeof(buffer) - 1] = '\0';
69
70 kernel_restart(buffer);
71 break
  break;
72
73 #ifdef CONFIG_KEXEC
74 case LINUX_REBOOT_CMD_KEXEC:
75 ret = kernel_kexec();
76 break
  break;
77 #endif
78
79 #ifdef CONFIG_HIBERNATION
case LINUX_REBOOT_CMD_SW_SUSPEND:
80
81 ret = hibernate();
82 break
  break;
83 #endif
84
default
default:
85
86 ret = -EINVAL;
87 break
  break;
88 }
89 mutex_unlock(&reboot_mutex);
90 return ret;
91 }
我们通过命令行敲 reboot 的话进入的是 LINUX_REBOOT_CMD_RESTART 这个分支,可以
看到接下来会调用 kernel_restart(NULL);
92 /**
93 * kernel_restart - reboot the system
94 * @cmd: pointer to buffer containing command to execute for restart
95 *
96 *
97 * Shutdown everything and perform a clean reboot.
98 * This is not safe to call in interrupt context.
99 */
or %NULL
char
100 void kernel_restart(char *cmd)
101 {
102
103
104
kernel_restart_prepare(cmd);
if (!cmd)
printk(KERN_EMERG "Restarting system.\n");
105
else
printk(KERN_EMERG "Restarting system with command '%s'.\n", cmd);
106
107 kmsg_dump(KMSG_DUMP_RESTART);
108 machine_restart(cmd);
109 }
这个函数里面会打印出我们常看到的 log,Restarting system.
kernel_restart_prepare(cmd);里会去调用设备的 shutdown 接口,去 power off 设备,并且发送
SYS_RESTART 的广播,
char
110 void kernel_restart_prepare(char *cmd)
111 {
112 blocking_notifier_call_chain(&reboot_notifier_list, SYS_RESTART, cmd);
113 system_state = SYSTEM_RESTART;
114 device_shutdown();
115 sysdev_shutdown();
116 }
接着执行 machine_restart(cmd);我们会调到 arch/x86/kernel/reboot.c 中,
这里需要知道一个 ops
117 struct machine_ops machine_ops = {
118 .power_off = native_machine_power_off,
119 .shutdown = native_machine_shutdown,
120 .emergency_restart = native_machine_emergency_restart,
121 .restart = native_machine_restart,
122 .halt = native_machine_halt,
123 #ifdef CONFIG_KEXEC
124
.crash_shutdown = native_machine_crash_shutdown,
125 #endif
126 };
machine_restart 就是执行这行这里的 native_machine_restart
char
127 static void native_machine_restart(char *__unused)
128 {
129
130
printk("machine restart\n");
131
if (!reboot_force) {
132 printk("native_machine_restart reboot_force:%d\n", reboot_force);
133 machine_shutdown();
134 }
135 __machine_emergency_restart(0);
136 }
machine_shutdown(); 中 执 行 一 些
__machine_emergency_restart(0);
shutdown
工 作 , 重 启 的 工 作 在
int
137 static void __machine_emergency_restart(int emergency)
138 {
139 reboot_emergency = emergency;
140 machine_ops.emergency_restart();
141 }
调用 ops 中的 emergency_restart
void
142 static void native_machine_emergency_restart(void
void)
143 {
144
int i;
145
146
147
if (reboot_emergency)
emergency_vmx_disable_all();
148
149
tboot_shutdown(TB_SHUTDOWN_REBOOT);
150
151 /* Tell the BIOS if we want cold or warm reboot */
152 *((unsigned short *)__va(0x472)) = reboot_mode;
153
154
for (;;) {
155 /* Could also try the reset bit in the Hammer NB */
156 switch (reboot_type) {
157 case BOOT_KBD:
158
mach_reboot_fixups(); /* for board specific fixups */
159
160 for (i = 0; i < 10; i++) {
161 printk("%d\n", i);
162 kb_wait();
163 udelay(50);
164 outb(0xfe, 0x64); /* pulse reset low */
udelay(50);
165
166
}
167
168
case BOOT_TRIPLE:
169
170
load_idt(&no_idt);
171
172
__asm__ __volatile__("int3");
173
174 reboot_type = BOOT_KBD;
175 break
   break;
176
177 #ifdef CONFIG_X86_32
178
case BOOT_BIOS:
179 machine_real_restart(jump_to_bios, sizeof
   sizeof(jump_to_bios));
180 reboot_type = BOOT_KBD;
181
break
break;
182 #endif
183
184
case BOOT_ACPI:
185
186 acpi_reboot();
187 reboot_type = BOOT_KBD;
188 break
   break;
189
190
case BOOT_EFI:
191
192
193
if (efi_enabled)
efi.reset_system(reboot_mode ?
194 EFI_RESET_WARM :
195 EFI_RESET_COLD,
196 EFI_SUCCESS, 0, NULL);
197 reboot_type = BOOT_KBD;
198 break
   break;
199
200
case BOOT_CF9:
201
202 port_cf9_safe = true
   true;
203 /* fall through */
204
205
case BOOT_CF9_COND:
206
207
208
if (port_cf9_safe) {
u8 cf9 = inb(0xcf9) & ~6;
209
210 outb(cf9|2, 0xcf9); /* Request hard reset */
211 udelay(50);
212 outb(cf9|6, 0xcf9); /* Actually do the reset */
213 udelay(50);
214 }
215 reboot_type = BOOT_KBD;
216 break
   break;
}
217
}
218
219 }
这边就是重启的最后部分了,默认的是通过 BOOT_KBD 方式重启的,这种方式是
通过键盘控制器去模拟按下键盘上的 reset 键来重启的,往 0x64 端口中写 0xfe 即可,然后
系统会在__asm__ __volatile__("int3");中中断。
int3 是一个 breakpoint,
用来使程序停止在这,
等待重启。
这里再说下,通过 cf9来重启,用注释来解释 Use the so-called "PCI reset register",
CF9,通过这个寄存器可以使系统 hard reset。
对于上面的一些重启方式,
我将在下一篇文章里去介绍他们的用法,
以及我在调试
reboot 中遇到的一些问题,这篇文章主要就是分析一下 reboot 的流程。
同样,附一张流程图:
原创粉丝点击