reboot 流程

article/2025/11/3 23:02:10

前言

        对于生在智能时代的我们,对关机和重启这两个概念肯定不会陌生,尤其经历早期Android智能机的人们,印象最深恐怕就是重启,当然现在不会了,还没有改过来的都被淘汰了。在Linux系统中我们使用reboot完成这个动作,下面以rk px30 linux4.4.194为例,分析这个过程。

应用层

        重启reboot基本上都是通过一条命令实现,之所以聊一下应用层,主要是新的系统中reboot shutdown halt 等,这些操作被systemd统一管理了,也就是说reboot,shutdown,halt等命令是指向systemctl的软链接,执行reboot相当于执行 systemctl reboot,systemctl reboot 会切换到 reboot.target.

 下面使用systemd进行系统关闭/重启的依赖关系图:

                                  (conflicts with  (conflicts withall system     all file systemservices)     mounts, swaps,|           cryptsetup|          devices, ...)|                |v                vshutdown.target    umount.target|                |\_______   ______/\ /v(various low-levelservices)|vfinal.target|_____________________________________/ \_________________________________/                         |                        |                      \|                         |                        |                      |v                         v                        v                      v
systemd-reboot.service   systemd-poweroff.service   systemd-halt.service   systemd-kexec.service|                         |                        |                      |v                         v                        v                      vreboot.target             poweroff.target            halt.target           kexec.target

下面是reboot的service 

#  SPDX-License-Identifier: LGPL-2.1+
#
#  This file is part of systemd.
#
#  systemd is free software; you can redistribute it and/or modify it
#  under the terms of the GNU Lesser General Public License as published by
#  the Free Software Foundation; either version 2.1 of the License, or
#  (at your option) any later version.[Unit]
Description=Reboot
Documentation=man:systemd-halt.service(8)
DefaultDependencies=no
Requires=shutdown.target umount.target final.target
After=shutdown.target umount.target final.target
SuccessAction=reboot-force

conflicts with all system services:指那些定义了Conflicts=shutdown.target 和 Before=shutdown.target 依赖关系(除非明确设置了 DefaultDependencies=no ,否则 service 单元将会自动添加这些依赖)的服务,这些服务在shutdown.target运行之前会停止。

实际执行过程从上到下,以reboot为例:

1.停止和shutdown.target、umount.target冲突的服务。

2.shutdown.target、umount.target

3.various low-level services

4.final.target

5.systemd-reboot.service
该服务执行的命令行:ExecStart=/bin/systemctl --force reboot,这条命令会调用systemd-shutdown,它将以简单而强大的方式卸载任何剩余的文件系统,杀死任何剩余的进程并释放任何其他剩余的资源,而不再考虑任何服务或单元概念。一般这是最后执行的服务。

6.reboot.target

目标单元的功能仅仅是通过依赖关系将一组单元汇聚在一起, 形成一个同步点,并给这个同步点取一个众所周知的名称, 以便用作启动目标或其他单元的依赖。对于shutdown.target、umount.target、final.target、reboot.target这些目标单元,其组内的单元(.wants/、.requires/)实际的启动顺序取决于单元自身的依赖关系。
最后通过系统调用,通过内核完成相关操作。

kernel

如下为reboot的系统调用代码kernel/reboot.c:

/** Reboot system call: for obvious reasons only root may call it,* and even root needs to set up some magic numbers in the registers* so that some mistake won't make this reboot the whole machine.* You can also set the meaning of the ctrl-alt-del-key here.** reboot doesn't sync: do that yourself before calling this.*/
SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd,void __user *, arg)
{struct pid_namespace *pid_ns = task_active_pid_ns(current);char buffer[256];int ret = 0;#检测权限/* We only trust the superuser with rebooting the system. */if (!ns_capable(pid_ns->user_ns, CAP_SYS_BOOT))return -EPERM;//加入一些验证,防止误操作/* For safety, we require "magic" arguments. */if (magic1 != LINUX_REBOOT_MAGIC1 ||(magic2 != LINUX_REBOOT_MAGIC2 &&magic2 != LINUX_REBOOT_MAGIC2A &&magic2 != LINUX_REBOOT_MAGIC2B &&magic2 != LINUX_REBOOT_MAGIC2C))return -EINVAL;//调用reboot_pid_ns接口,检查是否需要由该接口处理reboot请求。这是一个有关pid namespaces的新特性,也是Linux内核重要的知识点/** If pid namespaces are enabled and the current task is in a child* pid_namespace, the command is handled by reboot_pid_ns() which will* call do_exit().*/ret = reboot_pid_ns(pid_ns, cmd);if (ret)return ret;//如果是POWER_OFF命令,且没有注册power off的machine处理函数(pm_power_off),把该命令转换为HALT命令;/* Instead of trying to make the power_off code look like* halt when pm_power_off is not set do it the easy way.*/if ((cmd == LINUX_REBOOT_CMD_POWER_OFF) && !pm_power_off)cmd = LINUX_REBOOT_CMD_HALT;mutex_lock(&reboot_mutex);switch (cmd) {case LINUX_REBOOT_CMD_RESTART:kernel_restart(NULL);break;/*省略不相干代码*/default:ret = -EINVAL;break;}mutex_unlock(&reboot_mutex);return ret;
}

1、内核根据不同的表现形式把重启分为下面几类:

/** Commands accepted by the _reboot() system call.** RESTART     Restart system using default command and mode.* HALT        Stop OS and give system control to ROM monitor, if any.* CAD_ON      Ctrl-Alt-Del sequence causes RESTART command.* CAD_OFF     Ctrl-Alt-Del sequence sends SIGINT to init task.* POWER_OFF   Stop OS and remove all power from system, if possible.* RESTART2    Restart system using given command string.* SW_SUSPEND  Suspend system using software suspend if compiled in.* KEXEC       Restart system using a previously loaded Linux kernel*/#define LINUX_REBOOT_CMD_RESTART        0x01234567
#define LINUX_REBOOT_CMD_HALT           0xCDEF0123
#define LINUX_REBOOT_CMD_CAD_ON         0x89ABCDEF
#define LINUX_REBOOT_CMD_CAD_OFF        0x00000000
#define LINUX_REBOOT_CMD_POWER_OFF      0x4321FEDC
#define LINUX_REBOOT_CMD_RESTART2       0xA1B2C3D4
#define LINUX_REBOOT_CMD_SW_SUSPEND     0xD000FCE2
#define LINUX_REBOOT_CMD_KEXEC          0x45584543

RESTART,正常的重启,也是我们平时使用的重启。执行该动作后,系统会重新启动。

HALT,停止操作系统,然后把控制权交给其它代码(如果有的话)。具体的表现形式,依赖于系统的具体实现。

CAD_ON/CAD_OFF,允许/禁止通过Ctrl-Alt-Del组合按键触发重启(RESTART)动作。
注1:Ctrl-Alt-Del组合按键的响应是由具体的Driver(如Keypad)实现的。

POWER_OFF,正常的关机。执行该动作后,系统会停止操作系统,并去除所有的供电。

RESTART2,重启的另一种方式。可以在重启时,携带一个字符串类型的cmd,该cmd会在重启前,发送给任意一个关心重启事件的进程,同时会传递给最终执行重启动作的machine相关的代码。内核并没有规定该cmd的形式,完全由具体的machine自行定义。

SW_SUSPEND,即前一篇文章中描述的Hibernate操作。

KEXEC,重启并执行已经加载好的其它Kernel Image(需要CONFIG_KEXEC的支持),暂不涉及。


上面已经注释过一些,下面我们重点看一下 LINUX_REBOOT_CMD_RESTART 命令的处理函数kernel_restart

/***	kernel_restart - reboot the system*	@cmd: pointer to buffer containing command to execute for restart*		or %NULL**	Shutdown everything and perform a clean reboot.*	This is not safe to call in interrupt context.*/
void kernel_restart(char *cmd)
{kernel_restart_prepare(cmd);migrate_to_reboot_cpu();syscore_shutdown();if (!cmd)pr_emerg("Restarting system\n");elsepr_emerg("Restarting system with command '%s'\n", cmd);kmsg_dump(KMSG_DUMP_RESTART);machine_restart(cmd);
}

kernel_restart_prepare

void kernel_restart_prepare(char *cmd)
{blocking_notifier_call_chain(&reboot_notifier_list, SYS_RESTART, cmd);system_state = SYSTEM_RESTART;usermodehelper_disable();device_shutdown();
}

    进行restart/halt/power_off前的准备工作,包括,
      调用blocking_notifier_call_chain接口,向关心reboot事件的进程,发送SYS_RESTART将cmd参数一并发送出去。驱动需要关注该事件需要调用register_reboot_notifier注册,
      将系统状态设置为相应的状态(SYS_RESTART)。
      调用usermodehelper_disable接口,禁止User mode helper。
      调用device_shutdown,关闭所有的设备

migrate_to_reboot_cpu

void migrate_to_reboot_cpu(void)
{/* The boot cpu is always logical cpu 0 */int cpu = reboot_cpu;cpu_hotplug_disable();/* Make certain the cpu I'm about to reboot on is online */if (!cpu_online(cpu))cpu = cpumask_first(cpu_online_mask);/* Prevent races with other tasks migrating this task */current->flags |= PF_NO_SETAFFINITY;/* Make certain I only run on the appropriate processor */set_cpus_allowed_ptr(current, cpumask_of(cpu));
}

 该函数主要是把当前调用重启接口的任务,绑定到固定的一个CPU上,通常为当前online的序号排第一的CPU。此处不用纠结为什么绑定到第一个online的而不是第二个第三个,主要原因一是为了简单,二是防止在重启时再有什么任务迁移。

syscore_shutdown

/*** syscore_shutdown - Execute all the registered system core shutdown callbacks.*/
void syscore_shutdown(void)
{struct syscore_ops *ops;mutex_lock(&syscore_ops_lock);list_for_each_entry_reverse(ops, &syscore_ops_list, node)if (ops->shutdown) {if (initcall_debug)pr_info("PM: Calling %pF\n", ops->shutdown);ops->shutdown();}mutex_unlock(&syscore_ops_lock);
}

回调所有注册syscore shutdown回调的回调函数,通常注册syscore的回调有3个:suspend\resume\shutdown,其中suspend和resume在低功耗流程中调用,shutdown则在此处调用。

machine_restart

/** Restart requires that the secondary CPUs stop performing any activity* while the primary CPU resets the system. Systems with multiple CPUs must* provide a HW restart implementation, to ensure that all CPUs reset at once.* This is required so that any code running after reset on the primary CPU* doesn't have to co-ordinate with other CPUs to ensure they aren't still* executing pre-reset code, and using RAM that the primary CPU's code wishes* to use. Implementing such co-ordination would be essentially impossible.*/
void machine_restart(char *cmd)
{/* Disable interrupts first */local_irq_disable();smp_send_stop();do_kernel_i2c_restart(cmd);/** UpdateCapsule() depends on the system being reset via* ResetSystem().*/if (efi_enabled(EFI_RUNTIME_SERVICES))efi_reboot(reboot_mode, NULL);/* Now call the architecture specific reboot code. */if (arm_pm_restart)arm_pm_restart(reboot_mode, cmd);elsedo_kernel_restart(cmd);/** Whoops - the architecture was unable to reboot.*/printk("Reboot failed -- System halted\n");while (1);
}

复位cpu会通过smp_send_stop接口把其他cpu停下来,接着调用复位命令,看一下这个do_kernel_restart,也是回调函数列表,主要处理通过register_restart_handler注册到register_restart_handler的设备,其中比较关键的clk函数下面贴出来看一下

static int rockchip_restart_notify(struct notifier_block *this,unsigned long mode, void *cmd)
{if (cb_restart)cb_restart();writel(0xfdb9, rst_base + reg_restart);return NOTIFY_DONE;
}

参考一下px30的datasheet《2.3 System Reset Solution》

到此ARM 会执行复位。 


硬件时序


http://chatgpt.dhexx.cn/article/q04tsxQn.shtml

相关文章

Vue路由和路由器简介

前言 路由(route)是vue中非常重要的技术,几乎每一个用vue所写的项目都会用到路由,它是一个vue的插件库,专门实现SPA应用 路由(route)的简介 说到路由,大多数人会想到路由器(router),可以这么说,路由器上的每一个口都…

路由传递数据

1.路由可以传递query和params参数。路由组件可以通过$route获取query和params参数。 2.路由传递params参数 (1)当to为字符串形式时。直接在路径后边添加数据 但是在路由中,path属性必须给数据占位。 (2)当to为对象形…

vue-router 路由传参方式/缓存路由/路由跳转

基础 前端路由 用来开发 SPA(单页面应用) 单页面应用 整个应用只有一个完整页面,页面变化都是在这一个页面更新的点击链接不会刷新整个页面,会局部更新,也会更新浏览历史(地址)点击链接也不…

Vue路由的$router.back(-1)回退时如何判断有没有上一个路由

每个页面的左上角有一个返回按钮< 点击时的代码是this.$router.back(-1)&#xff0c;返回上一个路由 但是用户点开其中一页&#xff0c;用户打开时并没有上一条路由的历史记录&#xff0c;所以点击<按钮时没有反应。 所以应该怎么判断有没有上一条路由的历史记录。 1.在页…

回程静态路由及trunk简单链路

六、trunk链路 可以实现连个交换机间不同vlan相同网段间的互访 [one]vlan 2 [one-vlan2]vlan 3 [one-vlan3]quit [one]port-group 1 [one-port-group-1]group-memberGigabitEthernet 0/0/1 Gigab&#xff09;itEthernet 0/0/3 [one-port-group-1]port link-type access …

Vue路由(vue-router)

一、Vue路由的相关概念 1、路由&#xff08;routing&#xff09;&#xff1a;是指从源到目的地时&#xff0c;决定端到端路径的决策过程。 2、前端路由&#xff1a;即由前端来维护一个路由规则。实现模式有两种。 (1)利用URL的Hash模式&#xff1a;就是常说的锚点&#xff0c;J…

Vue Router路由详解

文章目录 1. 介绍2. Vue Router 和 Vue 项目集成3. 声明式导航4. 编程式导航5. 重定向和4046. 嵌套路由7. 动态路由匹配 1. 介绍 Vue Router 是 Vue.js 官方的路由管理器。它和 Vue.js 的核心深度集成&#xff0c;让构建单页面应用变得易如反掌。包含的功能有&#xff1a; 嵌…

Vue 路由(Router)详细介绍(切换,传参,通信)

目录 前言 准备工作 基本使用 router-link router-view 基本流程 扩展内容 动态路由匹配 ​编辑 编程式导航 重定向 路由组件传参 HTML5 History模式 前言 在一个vue项目中&#xff0c;免不了对组件&#xff08;页面&#xff09;进行切换与跳转。而用 Vue.js Vu…

使用Best Trace工具查看VPS的去程和回程线路的路由

​ 去程线路查询操作比较简单&#xff0c;这里主要先说回在Linux VPS上安装Best Trace工具查询回程线路的方法 ​ Best Trace官网 回程线路路由查询 Linux版本Best Trace Ubuntu/Debian准备工作 apt install -y wget zip CentOS准备工作 yum -y install wget zip 下载 …

Vue路由(vue-router)详细讲解指南

中文文档&#xff1a;https://router.vuejs.org/zh/ Vue Router 是 Vue.js 官方的路由管理器。它和 Vue.js 的核心深度集成&#xff0c;让构建单页面应用变得易如反掌。路由实际上就是可以理解为指向&#xff0c;就是我在页面上点击一个按钮需要跳转到对应的页面&#xff0c;这…

静态路由配置

静态路由配置 一、静态路由简单配置方法 一、静态路由简单配置方法 设置静态路由步骤&#xff1a; 1.设置每个设备&#xff08;PC、路由器&#xff09;接口IP&#xff1a; 如图所示配置好各个接口的IP地址: 配置路由器AR1 0/0/0接口IP&#xff1a; [Huawei]interface Gigabi…

【接口篇 / Lan】(5.4) ❀ 02. 与交换机连接 (回程路由) ❀ FortiGate 防火墙

【简介】大多数企业都会配备三层交换机&#xff0c;通过划分VLAN更好的管理内部网络&#xff0c;三层交换机功能强大&#xff0c;本身带路由功能&#xff0c;可以控制VLAN之间的互相访问&#xff0c;这里要介绍的是三层交换机与防火墙连接上网。 回程路由 在没有等动态路由的情…

静态路由的配置以及简单分析

我们先把每个pc、路由器端口的ip配置好 然后在配置静态路由 在配置静态路由的时候&#xff0c;我们先配去程路由 在路由器R1 的命令行输入ip route-static 192.168.6.0 30 192.168.2.2 再去路由器R2 的命令行输入 ip route-static 192.168.1.0 30 192.168.2.1 配置回程路由 配置…

路由回环配置

一、拓扑模型 二、要求及分析 要求 配置pc等设备&#xff0c;要求互通 分析 1、配置IP地址 2、路由配置 三、配置IP r1配置 [r1]interface GigabitEthernet 0/0/0 [r1-GigabitEthernet0/0/0]ip address 192.168.1.100 24 [r1]interface GigabitEthernet 0/0/1 [r1-Gigab…

路由-回指路由

回指路由&#xff0c;是一个相对的概念。顾名思义&#xff0c;是指“回去的路由”。 当原路由是A区域-->B区域时&#xff0c;A向B发送访问请求&#xff0c;以A为源B为目标&#xff0c;此时B需要以A为目标地址&#xff0c;B为源配置一个静态路由&#xff0c;作为回指路由。 …

【计算机网络】Linux下路由配置总结

文章目录 路由的基础知识Linux内核路由表使用route -n命令查看Linux内核路由表三种路由类型说明(Flags)配置路由route的命令设置包转发静态路由配置 参考 路由的基础知识 1&#xff09;路由概念 路由&#xff1a; 跨越从源主机到目标主机的一个互联网络来转发数据包的过程路由…

Message消息框

//示例1.默认右下角 $.messager.show({title:我的消息,//可以用span标签拼接改变字体样式msg:data.msg,timeout:2000,showType:slide });//示例2.消息将显示在顶部中间 自定义消息框位置 $.messager.show({title:我的消息,msg:消息将在4秒后关闭。,showType:show,style:{right:…

简单的message提示框插件

下载&#xff1a;https://download.csdn.net/download/billhepeng/11929586

弹出Message

开发过程中&#xff0c;经常需要弹出各种信息提示框&#xff0c;很多框架都自定义了提示框&#xff0c;有的框架或许没有&#xff0c;我们也可以使用alert &#xff0c;confirm等IE自带的信息提示框&#xff0c;缺点就是太死板&#xff0c;无法修改其样式&#xff0c;所以很多时…

Handler,Message,Looper MessageQueue

##1 Handler简介 Handler&#xff0c;Looper&#xff0c;Message&#xff0c;MessageQueue是Android开发中经常遇到的知识点&#xff0c;也是Android面试题中常遇到的问题。 先来看一下Message在Android中传递的概览图 上面这张图基本反映了Handler发送和处理Message的流程。H…