全部博文(65)
分类: LINUX
2009-05-26 15:36:44
一、从reboot命令开始
reboot命令会执行系统调用来实现重启。我们在运行reboot时,会打印下面信息:
Restarting system.
这句话在kernel/sys.c的kernel_restart()函数中打印出来。
而调用kernel_restart函数的地方是,sys.c中的reboot系统调用宏定义中:
SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd,
void __user *, arg)
{
……
lock_kernel();
switch (cmd) {
case LINUX_REBOOT_CMD_RESTART:
kernel_restart(NULL);
break;
……
kernel_restart函数实现如下:
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);
machine_restart(cmd); //实际重启
}
EXPORT_SYMBOL_GPL(kernel_restart);
对于X86平台的machine_restart实现在arch/x86/kernel/reboot.c中:
void machine_restart(char *cmd)
{
machine_ops.restart(cmd);
}
其中,machine_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
};
可见,restart函数是native_machine_restart,其实现如下:
static void native_machine_restart(char *__unused)
{
printk("machine restart\n");
if (!reboot_force)
machine_shutdown();
machine_emergency_restart();
}
而native_machine_restart又调用了machine_emergency_restart函数,如下:
void machine_emergency_restart(void)
{
machine_ops.emergency_restart();
}
最终,实现X86重启的函数native_machine_emergency_restart如下:
static void (void)
{
int i;
*((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++) {
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;
}
}
}
一般情况下,运行reboot命令,进入的是BOOT_KBD这个case,然后,运行到BOOT_TRIPLE这个case,对于下面这句话,
__asm__ __volatile__("int3");
本人找了N+1本书,发现这句话的作用是产生一个breakpoint异常。
而实际重启的实现是在BOOT_KBD这个case中的:
for (i = 0; i < 10; i++) {
kb_wait();
udelay(50);
outb(0xfe, 0x64); /* pulse reset low */
udelay(50);
}
对于outb(0xfe,0x64)原理,我也不清楚,ICH8芯片手册找了没找到,Intel 965北桥芯片手册也没找到,网上说:
在不通过bios进行重启的情况下,系统向端口0xfe写入数字0x64,这种重启的具体原理我还不大清楚,似乎是模拟了一次reset键的按下。
知道的XDJM们在评论中告知一声,谢谢。
二、和ACPI
acpi模块的相关源代码在linux/drivers/acpi/中,以后有时间将对其进行具体分析。
注意:本文基于linux-2.6.28和X86平台进行分析。
/*