重庆网站域名备案地址,php成品网站,西红门网站建设公司,开一个公司需要多少钱原文#xff1a;Linux电源管理#xff08;3#xff09;_Generic PM之重新启动过程
1.前言
在使用计算机的过程中#xff0c;关机和重启是最先学会的两个操作。同样#xff0c;这两个操作在Linux中也存在#xff0c;可以关机和重启。这就是这里要描述的对象。在Linux Ke…原文Linux电源管理3_Generic PM之重新启动过程
1.前言
在使用计算机的过程中关机和重启是最先学会的两个操作。同样这两个操作在Linux中也存在可以关机和重启。这就是这里要描述的对象。在Linux Kernel中主流的关机和重新启动都是通过“ reboot”系统调用具体可参考kernel / sys.c来实现的。另外除了我们常用的shutdown和restart两类操作之外该系统调用也提供了其他的reboot方式也会在这里一一说明。 2.内核支持的reboot方式
也许你会奇怪reboot是重启的意思所以用它实现Restart是合理的但怎么用它实现关机操作呢答案是这样的关机之后早晚也会开机啊所以关机是一种特殊的重新启动过程只不过持续的时间有点长而已。所以内核根据不同的表现方式将重新启动分成如下的几种方式
1 / * 2 * _reboot系统调用接受的命令。 3 * 4 *重新启动使用默认命令和模式重新启动系统。 5 * HALT停止OS并将系统控制权交给ROM监视器如果有。 6 * CAD_ON Ctrl-Alt-Del序列导致RESTART命令。 7 * CAD_OFF Ctrl-Alt-Del序列将SIGINT发送到初始化任务。 8 * POWER_OFF如果可能请停止OS并从系统中断开所有电源。 9 * RESTART2使用给定的命令字符串重新启动系统。 10 * SW_SUSPEND使用软件挂起的挂起系统如果已编译。 11 * KEXEC使用先前加载的Linux内核重新启动系统 12 * / 13 14 #define LINUX_REBOOT_CMD_RESTART 0x01234567 15 #define LINUX_REBOOT_CMD_HALT 0xCDEF0123 16 #define LINUX_REBOOT_CMD_CAD_ON 0x89ABCDEF 17 #define LINUX_REBOOT_CMD_CAD_OFF 0x00000000 18 #define LINUX_REBOOT_CMD_POWER_OFF 0x4321FEDC 19 #define LINUX_REBOOT_CMD_RESTART2 0xA1B2C3D4 20 #define LINUX_REBOOT_CMD_SW_SUSPEND 0xD000FCE2 21 #define LINUX_REBOOT_CMD_KEXEC 0x4558454 操作类型 英文全称/别名 功能描述 备注 RESTART Restart 正常重启系统重新加载内核和用户空间。 用户最常用的重启方式等同于 reboot 命令。 HALT Halt 停止操作系统将控制权交给其他代码如 BIOS/UEFI 或监控程序。 表现形式依赖具体硬件实现可能完全断电或进入低功耗状态。 CAD_ON/CAD_OFF CtrlAltDel On/Off 允许/禁止通过 CtrlAltDel 组合键触发重启RESTART。 需键盘驱动支持默认行为由内核配置决定。 POWER_OFF Power Off 正常关机停止操作系统并切断电源ACPI 状态 S5 。 等同于 poweroff 命令需硬件支持完全断电。 RESTART2 Restart with Command 重启时携带自定义字符串 cmd 传递给关注重启事件的进程或机器相关代码。 用途由设备厂商自定义如安卓的恢复模式。 SW_SUSPEND Software Suspend 挂起到内存Suspend-to-RAM或磁盘Hibernate进入低功耗状态。 依赖 CONFIG_SUSPEND 内核选项详见后续休眠专题。 KEXEC Kernel Execute 跳过 BIOS/UEFI直接重启到预加载的其他内核镜像需 CONFIG_KEXEC 支持。 用于快速内核热替换或崩溃恢复如 kexec -l 加载新内核。 3.重新启动相关的操作流程
在Linux操作系统中可以通过重新启动停止关闭电源等命令启动重新启动具体的操作流程如下 一般的Linux操作系统在用户空间都提供了一些工具集合如常在嵌入式系统使用的Busybox这些工具集合包含了重新引导停止和关机三个和重新引导相关的命令。
用户空间程序通过reboot系统调用进入内核空间内核空间根据执行路径的不同提供了kernel_restartkernel_halt和kernel_power_off三个处理函数响应用空间的reboot请求这三个处理函数的处理流程大致相同主要包括向有关重新引导过程的进程发送通知事件调用驱动程序核心模块提供的接口关闭所有的外部设备调用驱动程序syscore模块提供的接口关闭系统核心调用架构相关的处理函数进行后续的处理最后调用计算机相关的接口实现真正意义上的重新启动另外采用TTY模块提供的Sysreq机制内核提供了其他途径的关机方法如某些按键组合向/ proc文件写入命令等 4.重新启动过程的内部动作和代码分析
4.1重启系统调用
重新启动系统调用的实现位于“ kernel / sys.c”其函数原型如下 1 SYSCALL_DEFINE4rebootintmagic1intmagic2unsigned intcmd 2 void __user *argreboot该系统调用的名称。magic1magic2两个int类型的“魔力数”用于防止误操作。具体在“ include / uapi / linux / reboot.h”中定义感兴趣的同学可以去看看话说这些数字还是蛮有意思的例如Linus同学及其家人的生日就在里面猜出来的可以在文章下面留言。cmd第2章所描绘的reboot方式。arg其他的额外参数。 reboot系统调用的内部动作比较简单
1确定调用者的用户权限如果不是超级用户superuser则直接返回错误这也是我们再用户空间执行reboothaltpoweroff等命令时必须是root用户的原因
2判断预测的魔术数是否匹配如果不匹配直接返回错误。这样就可以进行的防止误动作发生
3调用reboot_pid_ns接口检查是否需要由该接口处理reboot请求。
4如果是POWER_OFF命令且没有注册电源关闭的机器处理函数pm_power_off把该命令转换为HALT命令
5根据特定的cmd命令执行具体的处理包括 如果是RESTART或RESTART2命令调用kernel_restart。 如果是CAD_ON或CAD_OFF命令更新C_A_D的值则表示允许通过Ctrl Alt Del组合键重新启动系统。 如果是HALT命令调用kernel_halt。 如果是POWER_OFF命令调用kernel_power_off。 如果是KEXEC命令调用kernel_kexec接口 如果是SW_SUSPEND则调用hibernate接口
6返回上述的处理结果系统调用结束。 4.2 kernel_restartkernel_halt和kernel_power_off
1调用kernel_xxx_prepare函数进行重新启动/停止/ power_off前的准备工作包括 调用blocking_notifier_call_chain接口向关心reboot事件的进程发送SYS_RESTARTSYS_HALT或SYS_POWER_OFF事件。并发送出去。 将系统状态设置为相应的状态SYS_RESTARTSYS_HALT或SYS_POWER_OFF。 调用usermodehelper_disable接口禁止用户模式辅助 调用device_shutdown关闭所有的设备
2如果是power_off并且存在PM相关的power off prepare函数pm_power_off_prepare则调用该调用函数
3调用migrate_to_reboot_cpu接口将当前的进程任务移到一个CPU上
注2对于多CPU的机器无论由哪个CPU触发了当前的系统调用代码都可以运行在任意的CPU上。这个接口将代码分派到一个特定的CPU上并禁止调度器分派代码到其他CPU上。首先这个接口被执行后只有一个CPU在运行用于完成后续的重新启动动作。
4调用syscore_shutdown接口将系统核心器件关闭例如中断等
5调用printk以及kmsg_dump向这个世界发出最后的声音打印日志
6最后由machine-core的代码接管后续的处理。 4.3 device_shutdown
设备模型中和device_shutdown有关的逻辑包括
1.每个设备结构设备都会保存该设备的驱动结构设备驱动程序指针以及该设备所在的总线结构总线类型的指针
2.设备驱动中有一个名称为“ shutdown”的某种函数用于在device_shutdown时关闭该设备
3.总线中也有一个名称为“ shutdown”的某种函数用于在device_shutdown时关闭该设备
4.系统的所有设备都存在于“ / sys / devices /”目录下而该目录由名称为“ devices_kset”的kset表示。kset中会使用一个链表保存其下所有的kobject也即“ / sys / devices /”目录下的所有设备。”的最终结果就是以“ devices_kset”为根目录将内核中所有的设备以相应的kobject为代表组织成一个树状结构
device_shutdown的实现该接口位于“ drivers / base / core.c”中执行逻辑如下。 1 / ** 2 * device_shutdown-在每个设备上调用- shutdown以关闭。 3 * / 4 无效device_shutdownvoid 5 { 6 结构设备* dev* parent; 7 8 spin_lockdevices_kset- list_lock; 9 / * 10 *向后移动设备列表依次关闭每个设备。 11 *请注意设备拔出事件也可能会开始拉 12 *设备离线即使系统正在关闭。 13 * / 14: while (!list_empty(devices_kset-list)) { 15: dev list_entry(devices_kset-list.prev, struct device, 16: kobj.entry); 17: 18: /* 19: * hold reference count of devices parent to 20: * prevent it from being freed because parents 21: * lock is to be held 22: */ 23: parent get_device(dev-parent); 24: get_device(dev); 25: /* 26: * Make sure the device is off the kset list, in the 27: * event that dev-*-shutdown() doesnt remove it. 28: */ 29: list_del_init(dev-kobj.entry); 30: spin_unlock(devices_kset-list_lock); 31: 32: /* hold lock to avoid race with probe/release */ 33: if (parent) 34: device_lock(parent); 35: device_lock(dev); 36: 37: /* Dont allow any more runtime suspends */ 38: pm_runtime_get_noresume(dev); 39: pm_runtime_barrier(dev); 40: 41: if (dev-bus dev-bus-shutdown) { 42: if (initcall_debug) 43: dev_info(dev, shutdown\n); 44: dev-bus-shutdown(dev); 45: } else if (dev-driver dev-driver-shutdown) { 46: if (initcall_debug) 47: dev_info(dev, shutdown\n); 48: dev-driver-shutdown(dev); 49 } 50 51 device_unlockdev; 52 如果父母 53 device_unlockparent; 54 55 put_devicedev 56 put_device父 57 58 spin_lockdevices_kset- list_lock; 59 } 60 spin_unlockdevices_kset- list_lock; 61 async_synchronize_full; 62 } 4.4 system_core_shutdown
系统核心的关机和设备的关机类似也是从一个链表中遍历所有的系统核心并调用它的关机接口。 4.5 machine_restartmachine_halt和machine_power_off
虽然以machine_为预先命名这三个接口却是属于架构相关的处理函数如ARM。以ARM为例它们在“ arch / arm / kernel / process.c”中实现具体如下。
4.5.1机器重启 1 / * 2 *重新启动要求辅助CPU停止执行任何活动 3 *同时主CPU重置系统。具有单个CPU的系统可以 4 *使用soft_restart作为其机器描述符的.restart钩子因为 5 *将导致唯一可用的CPU复位。具有多个CPU的系统必须 6 *提供硬件重新启动实施以确保所有CPU立即复位。 7 *这是必需的以便在主CPU上复位后运行的任何代码 8 *不必与其他CPU协调以确保它们仍然不处于运行状态 9 *执行预重置代码并使用主CPU的代码希望的RAM 10 *使用。实施这种协调基本上是不可能的。 11 * / 12 void machine_restartchar * cmd 13 { 14 smp_send_stop 15 16 arm_pm_restartreboot_modecmd; 17 18 / *给失败的宽限期1s * / 19 mdelay1000; 20 21 / *糟糕-平台无法重新启动。告诉用户* / 22 printk“重新启动失败-系统停止\ n”; 23 local_irq_disable; 24 而1; 25 } 0先转述一下该接口的注释
对于多CPU的机器而言重新启动之前必须保证其他的CPU位于非活动状态由其中一个主CPU负责重新启动动作。并且必须实现一个基于硬件的重新启动操作以保证所有CPU同步重启这是设计的重点
对于单CPU机器而言就相对简单了可以直接用软件reset的方式实现重启。
1调用smp_send_stop接口确保其他CPU位于非活动状态
2调用机器相关的重启接口实现真正的重启。该接口是一个变量函数由“ arch / arm / kernel / process.c”声明由具体的机器代码实现。格式如下 void* arm_pm_restart char strconst char * cmd null_restart; EXPORT_SYMBOL_GPLarm_pm_restart;
3等待1s
4如果没有返回则重启成功否则失败打印错误信息。 4.5.2 machine_halt
ARM的halt很简单就是将其他CPU停下来并禁止当前CPU的中断后死循环确实中断被禁止了又死循环了不halt才怪。代码如下 1 / * 2 *停止仅要求辅助CPU停止执行任何操作 3 *活动执行任务处理中断。smp_send_stop 4 *实现此目标。 5 * / 6 void machine_haltvoid 7 { 8 smp_send_stop 9 10 local_irq_disable; 11 而1 12 } 4.5.3 machine_power_off
power off动作和restart类似即停止其他CPU调用其他函数。power off的某些函数和restart类似就不再说明了。 5.总结与思考
5.1建筑和机器的概念
本文是我们在分析Linux内核时第一次遇到架构和机器的概念顺便解释一下。内核代码中最常见的目录结构就是arch / xxx / mach-xxx /例如arch / arm / mach-bcm /。由该目录结构可知架构简称arch是指具体的体系结构如ARMX86等。机器呢是指具体体系结构下的一个或多个的SOC如bcm等。
5.2电源管理驱动和reboot有关的部分需要实现的内容
由上面的分析可知在Reboot的过程中大部分的逻辑是否内核处理的具体的驱动程序需要关注2点即可
1实现各自的关机接口以正确关闭对应的设备
2实现机器相关的接口以确保足够的机器可以正确重启或关闭电源
看来还是很简单的