700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > Linux设备驱动简析—PC重启源码分析

Linux设备驱动简析—PC重启源码分析

时间:2024-02-09 21:40:59

相关推荐

Linux设备驱动简析—PC重启源码分析

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 voidnative_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 < 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们在评论中告知一声,谢谢。

二、APM和ACPI

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

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

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。