标题:
x86平台linux系统重启流程跟踪更新
[打印本页]
作者:
look_w
时间:
2017-10-24 23:11
标题:
x86平台linux系统重启流程跟踪更新
从函数实现上看,使用死循环,根据不同的重启类型做转变:
BOOT_ACPI->BOOT_KBD->BOOT_ACPI->BOOT_EFI->BOOT_BIOS->BOOT_CF9_SAFE->BOOT_TRIPLE...首先是ACPI复位,调用acpi_reboot函数(driver/acpi/reboot.c),在该函数中通过写PCI寄存器方式复位。这涉及ACPI相关知识,笔者未做深入研究。笔者在一台安装BIOS的机器上测试发现是使用ACPI复位的。
如果ACPI被禁止(即无法复位成功),则使用keyboad复位,主要是写0xfe到端口0x64,关于它的作用,直接引述网络资料:
“0x64端口是i8042键盘控制器的控制端口,0xfe命令字的意思是将P32-P21三个针脚拉为低电平,持续6usec。这段代码的实际效果就相当于你按下机箱上的 RESET键。”
值得一提的是BOOT_CF9_SAFE分支,当port_cf9_safe为true时,会通过写0xcf9寄存器的方式复位。
其余的暂略过不提。
(注:上面分析顺序根据笔者测试结果来描述,理论上并不严谨)
下面看看系统重启过程的调试信息(注:此时机器无法使用reset重启):
* Will now restart
[ 716.203870] reboot: Restarting system
[ 716.208485] reboot: reboot_type: 97(a)
[ 716.212675] reboot: 11111reboot_type: 97(a)
[ 716.217350] acpi_reboot() acpi is disable...
[ 716.222121] reboot: 11111reboot_type: 107(k)
[ 716.226900] reboot: native_machine_emergency_restart() in KBD reboot...
[ 718.637262] reboot: 11111reboot_type: 97(a)
[ 718.641936] acpi_reboot() acpi is disable...
[ 718.646707] reboot: 11111reboot_type: 107(k)
[ 718.651484] reboot: native_machine_emergency_restart() in KBD reboot...
[ 721.061846] reboot: 11111reboot_type: 101(e)
[ 721.066616] reboot: 11111reboot_type: 98(b)
四、u-boot环境reset作为扩展,本文顺便也看看u-boot源码下重启的流程。reset命令位于cmd/boot.c文件:
U_BOOT_CMD(
reset, 1, 0, do_reset,
"Perform RESET of the CPU",
""
);
do_reset函数实现在arch/x86/cpu/cpu.c文件:
int do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
printf("resetting ...\n");
/* wait 50 ms */
udelay(50000);
disable_interrupts();
reset_cpu(0);
/*NOTREACHED*/
return 0;
}
__weak void reset_cpu(ulong addr)
{
/* Do a hard reset through the chipset's reset control register */
outb(SYS_RST | RST_CPU, IO_PORT_RESET);
for (;;)
cpu_hlt();
}
void x86_full_reset(void)
{
outb(FULL_RST | SYS_RST | RST_CPU, IO_PORT_RESET);
}
上面列出2个复位的函数:reset_cpu、x86_full_reset。它们只有细微区别,但都是往IO_PORT_RESET这个端口上写数值。接着看看这些宏定义是什么。它们的定义位于文件arch/x86/include/asm/processor.h:
/*
* This register is documented in (for example) the Intel Atom Processor E3800
* Product Family Datasheet in "PCU - Power Management Controller (PMC)".
*
* RST_CNT: Reset Control Register (RST_CNT) Offset cf9.
*
* The naming follows Intel's naming.
*/
#define IO_PORT_RESET 0xcf9
enum {
SYS_RST = 1 << 1, /* 0 for soft reset, 1 for hard reset */
RST_CPU = 1 << 2, /* initiate reset */
FULL_RST = 1 << 3, /* full power cycle */
};
从注释上看,0xcf9是Intel Atom的E3800系列SOC的RST_CNT寄存器(在内核中亦出现此寄存器)。复位类型有3种:SYS_RST、RST_CPU、FULL_RST。
本着打破沙锅问到底的钻研精神,找到E3800的datasheet,查看关于复位的说明章节(7.4章节),截图如下:
三种复位类型组合即为0x0e,亦即表格第一行所述操作。而RST_CNT寄存器的说明位于30.7章节,其寄存器地址正是CF9h。
这样,终于和u-boot源码对应起来了,对源码的复位函数也能解释得通了。网络上有资料表明可以在ICH手册中找到CF9寄存器,有兴趣的可以自行查阅。
五、所遇问题及解决细心的读者可能会发现在native_machine_emergency_restart函数中,笔者在BOOT_KBD分支中写0xcf9寄存器,而不是使用BOOT_CF9_SAFE分支。因为笔者在使用u-boot引导启动(非BIOS)的x86机器上遇到无法复位的问题,当执行到BOOT_BIOS时机器死了,但没有复位——应该是板子上并没有BIOS,无法执行对应的指令吧,这方面没有深入研究。选择在BOOT_KBD中实现是因为同一份内核镜像文件需要在有BIOS的机器和有u-boot的机器上运行。——无论是设计还是维护角度,笔者希望能尽量兼容。
六、小结要使系统重启,直接调用reboot即可,但由于系统重启还需要进行其它清理操作,一般不建议直接使用。在内核空间中实现的重启机制,首先使用ACPI,其次使用keyboad,再次使用BIOS,最后使用CF9。从u-boot源码分析看到,x86机器的重启是通过将0x0e写到0xcf9寄存器来实现的,在内核内核也有此方式,但差不多是在最后才执行,优先级较低。另外关于ACPI的研究,待日后有空闲再议。
欢迎光临 电子技术论坛_中国专业的电子工程师学习交流社区-中电网技术论坛 (http://bbs.eccn.com/)
Powered by Discuz! 7.0.0