免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1483 | 回复: 0
打印 上一主题 下一主题

Linux设备驱动简析—PC重启源码分析 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-05-26 15:36 |只看该作者 |倒序浏览
    Linux在PC上的关机和重启可能由两种行为引发,一是通过用户编程,一是系统自己产生的消息。用户和系统进行交互的方式也有两个,一个是系统调用:sys_reboot,另一个就是apm或acpi的设备文件,通过对其操作也可以使系统关机或者重启。

一、从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 native_machine_emergency_restart(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
                            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
                            kb_wait();
                            udelay(50);
                            outb(0xfe, 0x64); /* pulse reset low */
                            udelay(50);
                     }
      
       对于outb(0xfe,0x64)原理,我也不清楚,ICH8芯片手册找了没找到,Intel 965北桥芯片手册也没找到,网上说:
在不通过bios进行重启的情况下,系统向端口0xfe写入数字0x64,这种重启的具体原理我还不大清楚,似乎是模拟了一次reset键的按下。
       知道的XDJM们在评论中告知一声,谢谢。

二、APM和ACPI
acpi模块的相关源代码在linux/drivers/acpi/中,以后有时间将对其进行具体分析。


注意:本文基于linux-2.6.28和X86平台进行分析。

/*
*By Neil Chiao (
neilchiao at gmail.com
)
*转载请注明出处:
neilengineer.cublog.cn

*欢迎访问:新星湾(
www.xinxingwan.com
)
*/





本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u3/91522/showart_1945383.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP