linux重启驱动程序,Linux设备驱动简析―PC重启源码分析

一、从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如下:

{

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平台进行分析。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
CANopen协议是一种应用于控制系统中的开放式网络通讯协议,CANopen协议栈是一种实现CANopen协议的软件库,而CanFestival是其中的一种开源实现。CanFestival协议栈提供了一套用于实现CANopen从站设备的软件工具,用户可以利用CanFestival来开发符合CANopen协议的从站设备。 CanFestival协议栈的实现主要由以下几个步骤构成:首先,用户需要配置CanFestival协议栈,包括设置从站设备的节点ID、通信速率等参数;然后,用户需要定义从站设备的对象字典,包括输入对象、输出对象、PDO对象等;接着,用户需要编写应用程序,根据需求实现从站设备的控制逻辑;最后,用户需要编译链接代码,并将生成的可执行文件下载到从站设备中运行。 CanFestival协议栈的源码主要包括以下几个模块:CO_Data模块负责管理CANopen通信过程中的数据;对于CAN总线的操作交由CO_CAN模块处理;NMT模块实现CANopen网络管理功能,负责从站设备的初始化和启动过程;SDO模块用于实现从站设备上的服务数据对象传输;PDO模块处理实时数据的传输;EMCY模块处理紧急事件报告;SYNC模块管理同步传输数据;TIME模块提供时间基准。 值得注意的是,CanFestival协议栈的实现需要根据具体的硬件平台和应用场景进行调整和修改,用户在使用时需要充分理解CANopen协议的原理和特点,结合具体需求进行定制和优化。 CanFestival协议栈的开源性质意味着用户可以根据需要对其进行二次开发和定制。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值