您的位置:首页 > 运维架构 > Linux

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

2012-11-26 14:55 441 查看
在 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 的流程。

同样,附一张流程图:
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: