当前位置: 首页 > ds >正文

Linux sysvinit 系统启动

  1. Ramdisk 加载rootfs 分区数据
  1. 内核引导

  • 经没有ramdisk

  • 根文件系统挂载:内核调用 ext4 文件系统驱动,尝试将根设备挂载到 / 目录。具体挂载过程如下:

    • 内核定位根设备(如 /dev/sda1)。

    • 内核使用 ext4 文件系统驱动读取根设备的超级块(superblock),超级块包含文件系统的基本信息,如块大小、inode 数量等。

    • 内核根据超级块信息,验证文件系统的一致性,并进行必要的挂载操作,如初始化文件系统的缓存、设置挂载点等。

    • 若挂载成功,根文件系统就会被挂载到 / 目录。

  • 内核启动后,会进行一系列的初始化操作,包括硬件检测、设备驱动加载等。

  1. initramfs 阶段

  • 执行 init 脚本:内核会执行 initramfs 中的/init脚本。这个脚本负责在真正的 rootfs 挂载之前完成一些必要的初始化工作,如加载根文件系统所需的驱动模块。系统启动时,内核会依据 bootargs 中的 root 参数来挂载根文件系统。如果一切配置正确,系统会自动挂载指定 PARTUUID 的分区作为根文件系统。

检测 rootfs 设备:脚本会根据内核命令行参数(如root=/dev/sda1)来确定 rootfs 所在的设备。

获取内核命令行中的root参数 root_device=$(cat /proc/cmdline | sed -n 's/.*root=\([^ ]*\).*/\1/p')
linux dts 代码配置+ bootargs = "root=/dev/mmcblk0p15 rootfstype=ext4 rootwait ro highres=1 nr_cpus=4 initcall_debug=0 loglevel=4 earlycon console=ttyS0,115200n8 fb.lockless_register_fb=1 psplash=false init=/sbin/init logbuf.timestamp=rtc no_console_suspend";
命令参数获取cat /proc/cmdline rootfstype=ext4 rootwait ro highres=1 nr_cpus=4 initcall_debug=0 loglevel=4 earlycon console=ttyS0,115200n8 fb.lockless_register_fb=1 psplash=false init=/sbin/init logbuf.timestamp=rtc no_console_suspend root=PARTUUID=9b29ea53-affd-402a-a72a-6cfe11eb5fa7 slot_suffix=_a secure_updatemonitor=1 chipversion=X9SP domain=AP2 boot_image_emmc=normal bpt.version=0x42505402 img_ver.ap2_persist=DB_O4O8PA img_ver.safety_safety_os=DB_O4O8PA img_ver.safety_vbmeta_safety=DB_O4O8PA img_ver.boot_config_ap=DB_O4O8PA img_ver.ap2_cluster_rootfs=DB_O4O8PA img_ver.dil_safety=DB_O4O8PA img_ver.ssystem=DB_O4O8PA img_ver.ap2_cluster_preloader=DB_O4O8PA img_ver.ap1_atf=DB_O4O8PA img_ver.ap2_cluster_kernel=DB_O4O8PA img_ver.system_config=DB_O4O8PA img_ver.ap1_bootloader=DB_O4O8PA img_ver.slimfs_prop=DB_O4O8PA img_ver.ap2_cluster_tos=DB_O4O8PA img_ver.slimfs=DB_O4O8PA img_ver.ddr_init_seq=DB_O4O8PA img_ver.mpc_slimfs=DB_O4O8PA img_ver.spl=DB_O4O8PA img_ver.vbmeta_top=DB_O4O8PA img_ver.ap2_cluster_bootloader=DB_O4O8PA img_ver.ap2_cluster_dtb=DB_O4O8PA img_ver.ap1_tos=DB_O4O8PA img_ver.ap2_vbmeta_ap2=DB_O4O8PA img_ver.ap2_ap_share=DB_O4O8PA img_ver.ap2_cluster_log=DB_O4O8PA img_ver.ap1_preloader=DB_O4O8PA img_ver.ap2_userdata=DB_O4O8PA img_ver.ddr_fw=DB_O4O8PA img_ver.ap2_mcu=DB_O4O8PA img_ver.mpc_vbmeta_mpc=DB_O4O8PA img_ver.mpc_vdm=DB_O4O8PA img_ver.ap2_cluster_atf=DB_O4O8PA img_ver.ap1_vbmeta=DB_O4O8PA root@x9sp_ap2:/usr/bin#

等待设备就绪:如果 rootfs 所在的设备是块设备,可能需要等待设备完全初始化。

等待设备文件出现 while [ ! -e $root_device ]; dosleep 1done

挂载 rootfs:在 initramfs 中创建一个临时挂载点,然后将 rootfs 设备挂载到该点。

lk boot阶段修改

rtos/lk_boot/application/system/bootloader/bootlaoder.c的

remove_root_dev_fdt_bootargs 这个函数的上下文

static const uint8_t rootfs_type_guid[PARTITION_TYPE_GUID_SIZE] = {0xe1, 0xe6, 0x2c, 0xfc, 0xf4, 0x67, 0x00, 0x02, 0x25, 0xac, 0x3c, 0x65, 0x76, 0x12, 0xc9, 0x9b};

e1 e6 2c fc - f4 67- 00 02 - ac 25- 3c 65 76 12 c9 9b

memset(alias_rootfs_part, 0x0, sizeof(alias_rootfs_part)); 
memcpy(alias_rootfs_part, ptdev_active_name_by_type_guid(ptdev, (EFI_GUID *) rootfs_type_guid), MAX_GPT_NAME_SIZE);

[ 2.054691] dw-apb-uart 604d0000.serial: forbid DMA for kernel console [ 2.055122] Waiting for root device PARTUUID=d5fd7f80-4657-42a4-8174-5188a0f76d51...

[ 2.065619] mmc0: new HS400 MMC card at address 0001

[ 2.066094] mmcblk0: mmc0:0001 eMMC 9.30 GiB

[ 2.066288] mmcblk0boot0: mmc0:0001 eMMC partition 1 31.5 MiB [ 2.066463] mmcblk0boot1: mmc0:0001 eMMC partition 2 31.5 MiB

[ 2.069993] mmcblk0: p1 p2 p3 p4 p5 p6 p7 p8 p9 p10 p11 p12 p13 p14 p15 p16 p17 p18 p19 p20 p21

[ 2.073848] sdrv_ion: sdrv_heap num is zero, defer probe now

[ 2.087726] EXT4-fs (mmcblk0p19): mounted filesystem with ordered data mode. Opts: (null) [ 2.087774] VFS: Mounted root (ext4 filesystem) readonly on device 259:11. [ 2.088954] devtmpfs: mounted [ 2.089703] Freeing unused kernel memory: 1664K

[ 2.096138] Run /sbin/init as init process

[ 2.096145] with arguments:

[ 2.096149] /sbin/init

[ 2.096151] with environment:

[ 2.096155] HOME=/

[ 2.096157] TERM=linux

[ 2.096160] psplash=false

[ 2.096163] slot_suffix=_a

[ 2.096166] secure_updatemonitor=1 [ 2.096169] chipversion=X9SP [ 2.096172] domain=AP2 [ 2.096175] boot_image_emmc=normal [ 2.181623] mount (170) used greatest stack depth: 12688 bytes left

./init/do_mounts.c

tatic int __init do_mount_root(const char *name, const char *fs, const int flags, const void *data) { struct super_block *s; struct page *p = NULL; char *data_page = NULL; int ret; if (data) { /* init_mount() requires a full page as fifth argument */ p = alloc_page(GFP_KERNEL); if (!p) return -ENOMEM; data_page = page_address(p); /* zero-pad. init_mount() will make sure it's terminated */ strncpy(data_page, data, PAGE_SIZE); } ret = init_mount(name, "/root", fs, flags, data_page); if (ret) goto out; init_chdir("/root"); s = current->fs->pwd.dentry->d_sb; ROOT_DEV = s->s_dev; printk(KERN_INFO "VFS: Mounted root (%s filesystem)%s on device %u:%u.\n", s->s_type->name, sb_rdonly(s) ? " readonly" : "", MAJOR(ROOT_DEV), MINOR(ROOT_DEV)); out: if (p) put_page(p); return ret; }
  1. 切换到真正的 rootfs

  • 移动挂载点:将/proc/sys/dev等虚拟文件系统从 initramfs 移动到真正的 rootfs 中。

移动/procmount --move /proc /new_root/proc # 移动/sysmount --move /sys /new_root/sys # 移动/devmount --move /dev /new_root/dev

切换根目录:使用pivot_root命令将根目录从 initramfs 切换到真正的 rootfs。

切换根目录 pivot_root /new_root /new_root/initramfs # 切换到新的根目录cd /

卸载 initramfs:切换根目录后,卸载 initramfs。

卸载initramfsumount /initramfs
  1. SysVinit 启动

  • 执行 init:切换到真正的 rootfs 后,内核会执行/sbin/init程序,这是 SysVinit 系统的初始化进程。

  • 读取 inittab:init程序会读取/etc/inittab文件,根据其中的配置启动系统服务和进程。

总结

Yocto Linux 的 SysVinit 系统启动过程中,挂载 rootfs 分区主要通过 initramfs 阶段完成设备检测、驱动加载和挂载操作,然后切换到真正的 rootfs,最后由init程序继续完成系统初始化。

2. 使用 SysVinit 的启动流程

2.1 /sbin/init 进程启动

内核启动完成后,会调用 /sbin/init 程序,这是 SysVinit 系统的核心。

2.2 读取 /etc/inittab 文件

/sbin/init 进程会读取 /etc/inittab 文件,该文件定义了系统的运行级别和对应的初始化操作。运行级别是一组预定义的系统状态,例如单用户模式、多用户模式等。

2.3 执行 /etc/init.d 目录下的脚本

依据 /etc/inittab 文件指定的运行级别,init 进程会执行 /etc/init.d 目录下的脚本。这些脚本通常用于启动系统服务,如网络服务、日志服务等。/etc/init.d 目录本身存放的是各种服务的管理脚本,但这些脚本不会直接按顺序执行,而是通过 /etc/rc?.d 目录(? 代表运行级别,如 0 - 6)下的符号链接来间接执行,执行优先级与 /etc/rc?.d 目录下脚本文件名的命名规则相关

2.4 执行 /etc/rcS.d 目录下的脚本

/etc/rcS.d 目录下的脚本在系统启动早期执行,主要用于执行一些基本的初始化任务,比如挂载根文件系统、设置系统时钟、加载内核模块等。脚本文件名以 S 开头,后面跟着两位数字和脚本名,数字越小,执行优先级越高。

2.5 执行 /etc/rc?.d 目录下的脚本

这里的 ? 代表具体的运行级别,如 0 - 6/etc/rc?.d 目录下的脚本根据当前系统的运行级别来执行。以 S 开头的脚本在系统进入该运行级别时启动服务,以 K 开头的脚本在系统离开该运行级别时停止服务。同样,后面的两位数字表示执行顺序,数字越小,执行优先级越高。

2.6 启动登录进程

最后,系统会启动登录进程,如 gettymingetty,等待用户登录。

在系统启动时(除了紧急模式 -b),init 进程会执行 /etc/init.d/rcS 脚本。这个脚本一般用于执行系统启动初期的基本初始化任务,如挂载根文件系统、设置系统时钟、加载内核模块等

cat /proc/cmdline rootfstype=ext4 rootwait ro highres=1 nr_cpus=4 initcall_debug=0 loglevel=4 earlycon console=ttyS0,115200n8 fb.lockless_register_fb=1 psplash=false init=/sbin/init logbuf.timestamp=rtc no_console_suspend root=PARTUUID=9b29ea53-affd-402a-a72a-6cfe11eb5fa7 slot_suffix=_a secure_updatemonitor=1 chipversion=X9SP domain=AP2 boot_image_emmc=normal bpt.version=0x42505402 img_ver.ap2_persist=DB_O4O8PA img_ver.safety_safety_os=DB_O4O8PA img_ver.safety_vbmeta_safety=DB_O4O8PA img_ver.boot_config_ap=DB_O4O8PA img_ver.ap2_cluster_rootfs=DB_O4O8PA img_ver.dil_safety=DB_O4O8PA img_ver.ssystem=DB_O4O8PA img_ver.ap2_cluster_preloader=DB_O4O8PA img_ver.ap1_atf=DB_O4O8PA img_ver.ap2_cluster_kernel=DB_O4O8PA img_ver.system_config=DB_O4O8PA img_ver.ap1_bootloader=DB_O4O8PA img_ver.slimfs_prop=DB_O4O8PA img_ver.ap2_cluster_tos=DB_O4O8PA img_ver.slimfs=DB_O4O8PA img_ver.ddr_init_seq=DB_O4O8PA img_ver.mpc_slimfs=DB_O4O8PA img_ver.spl=DB_O4O8PA img_ver.vbmeta_top=DB_O4O8PA img_ver.ap2_cluster_bootloader=DB_O4O8PA img_ver.ap2_cluster_dtb=DB_O4O8PA img_ver.ap1_tos=DB_O4O8PA img_ver.ap2_vbmeta_ap2=DB_O4O8PA img_ver.ap2_ap_share=DB_O4O8PA img_ver.ap2_cluster_log=DB_O4O8PA img_ver.ap1_preloader=DB_O4O8PA img_ver.ap2_userdata=DB_O4O8PA img_ver.ddr_fw=DB_O4O8PA img_ver.ap2_mcu=DB_O4O8PA img_ver.mpc_vbmeta_mpc=DB_O4O8PA img_ver.mpc_vdm=DB_O4O8PA img_ver.ap2_cluster_atf=DB_O4O8PA img_ver.ap1_vbmeta=DB_O4O8PA root@x9sp_ap2:/usr/bin#

该文件中的每一行都代表一个初始化条目,格式通常为

<id>:<runlevels>:<action>:<process>

root@x9_ap2:/etc# cat inittab

# /etc/inittab: init(8) configuration.

# $Id: inittab,v 1.91 2002/01/25 13:35:21 miquels Exp $

# The default runlevel. id:5:initdefault: # Boot-time system configuration/initialization script. # This is run first except when booting in emergency (-b) mode. si::sysinit:/etc/init.d/rcS # What to do in single-user mode. ~~:S:wait:/sbin/sulogin # /etc/init.d executes the S and K scripts upon change # of runlevel. # # Runlevel 0 is halt. # Runlevel 1 is single-user. # Runlevels 2-5 are multi-user. # Runlevel 6 is reboot. l0:0:wait:/etc/init.d/rc 0 l1:1:wait:/etc/init.d/rc 1 l2:2:wait:/etc/init.d/rc 2 l3:3:wait:/etc/init.d/rc 3 l4:4:wait:/etc/init.d/rc 4 l5:5:wait:/etc/init.d/rc 5 l6:6:wait:/etc/init.d/rc 6 # Normally not reached, but fallthrough in case of emergency. z6:6:respawn:/sbin/sulogin S0:12345:respawn:/bin/start_getty 115200 ttyS0 vt102 # /sbin/getty invocations for the runlevels. # # The "id" field MUST be the same as the last # characters of the device (after "tty"). # # Format: # <id>:<runlevels>:<action>:<process> # 1:12345:respawn:/sbin/getty 38400 tty1

启动脚本

2.1 文件位置

  Linux启动脚本,即rcS文件。rcS文件位于系统根目录下的“/etc/init.d”下,可以查看到该文件的文件属主和文件属组都是root,只有root的权限可以修改和执行。

2.2 rcS文件格式

  rcS文件本质是一个bash shell脚本,因此遵循bash脚本的语法规则。bash shell也是一门复杂的语言,深入研究可以独立出来研究,但我们知道基本的规则即可满足我们应用。

[1] 文件首行必须为“#! /bin/sh”。

[2] 注释一行用“#”。

[3] 基本的赋值语句,如打印字符串。

[4] 打印特殊符号需加“\”。

[5] 逻辑语句、循环语句等。

2.3 实现功能

  启动脚本可以做很多事情,只要我们需要初始化时配置或者执行的功能,几乎都满足,总结几点下来及常用的有如下几种。

[1] 启动某个进程程序,最常用的,如启动串口收发进程。

[2] 加载驱动模块(.ko文件);如驱动编译成模块时,可以在这里增加加载(insmod/modprobe)驱动模块命令。

[3] 启动其他模块启动脚本,如网络服务。

[4] 配置功能,该项功能比较实用,实现期望系统起来后进行某些配置,如:配置环境变量、创建临时文件(夹)、挂在文件到指定文件夹、设置默认IP参数,以及配置系统主机名称等基础配置。

[5] 其他,如增加打印功能,方便在调试终端(串口)查看初始化过程,或者两者执行间进行延时(sleep)等。

https://www.cnblogs.com/acuity/p/12154122.html

https://www.cnblogs.com/aaronLinux/p/6860478.html

  1. Linux系统主要通过以下步骤启动
  1. 启动Boot Manager

  2. 加载系统内核,启动init进程, init进程是Linux的根进程,所有的系统进程都是它的子进程。

  3. init进程读取“/etc/inittab”文件中的信进入inittab中预设的运行级别,按顺序运行该运行级别对应文件夹(init*.d)下的脚本。脚本通常以“start”参数启动,并指向一个系统中的程序。通常情况下,“/etc/rcS.d/”目录下的启动脚本首先被执行,然后是“/etc/rcN.d/”目录。例如您设定的运行级别为3,那么它对应的启动目录为“/etc/rc3.d/”。

  4. 根据“/etc/rcS.d/”文件夹中对应的脚本启动Xwindow服务“xorg” Xwindow为Linux下的图形用户界面系统。

  5. 启动登录管理器,等待用户登录

1.1.系统服务

在运行级别对应的文件夹中,您可以看到许多文件名以“S##”和“K##”起始的启动脚本链接

init 进程将以“start”为参数,按文件名顺序执行所有以“S##”起始的脚本。脚本名称中的数字越小,它将被越早执行。例如在 “/etc/rc2.d/”文件夹中,“S13gdm”文件名中的数字小于“S23xinetd”,“S13gdm”将比“S23xinetd”先执行。如果一个脚本链接,以“K##”起始,表示它将以“stop”参数被执行。如果相应服务没有启动,则不执行该脚本。可以看到 rcS 脚本会依据文件名排序依次读取 /etc/init.d/ 目录下名字为 S??* 格式的脚本文件,并执行其中的 start 方法。同用的 rcK 脚本会依据文件名逆排序读取 /etc/init.d/ 目录下名字为 S??* 格式的脚本文件,并执行其中的 stop 方法。

1.2.手动控制服务

你可以手动运行带有以下参数的启动脚本,来控制系统服务。

start 启动

stop 停止

restart 重启

例如:

/etc/rc2.d/K20powernowd start

有 时您并不清楚当前运行级别,该运行级别下未必有相应脚本;而且此类脚本的前三位字符并不固定,不便于记忆。

这时,您可以直接使用 “/etc/init.d/”文件夹中的启动脚本(因为“/etc/rcX.d/”中的启动脚本都是链接到“/etc/init.d/”文件夹下相应脚本)

etc命令格式如下

"/etc"目录下,其中每一条配置信息定义一个初始化活动。格式如下:

<id>:<runlevels>:<action:<process>

inittab中的每个条目有4个字段,各字段间由冒号分开。

<id>: 表示该进程要使用的控制台(即标准输入、标准输出、标准错误设备)。如果省略,则使用与init进程一样的控制台。Id表示从哪个console启动,对busybox无意义

<runlevels>:对于busybox提供的init程序,这个字段没有意义,可以省略

<action>:表示init进程如何控制该子进程 8种行为

<process>:要执行的进程,它可以是可执行程序,也可以是脚本

一个简单的inittab示例:

::sysinit:/etc/init.d/rcS

::askfirst:-/bin/sh

::ctrllaltdel:/sbin/reboot

init进程的初始化任务被分解为一系列初始化活动来完成,busybox定义了8种action初始化活动,

  Sysinit:为init进程提供初始化命令脚本的路径。

  Wait:告诉init进程必须等到相应的进程执行完成之后,才能继续执行。

  Once:仅执行相应的进程一次,而且不会等待它执行完成。

  Respawn:当相应的进程终止执行时,重新启动该进程。

  Askfirst:与respawn类似,不过init进程先输出“please press enter to active this console”,等用户按回车键之后,才启动子进程。

  Shutdown:当系统关机时,执行相应的进程。

  Restart:当init进程重新启动时,执行相应的进程,通常此处执行的进程就是init本身。

  Ctrlatldel:当按下crtl+alt_delete组合键时,执行相应的进程

http://www.xdnf.cn/news/5860.html

相关文章:

  • 【三】 空域滤波的基础与空域中的低通滤波器(2)【830数字图像处理】
  • 解构赋值
  • RuoYi 中使用 PageUtils.startPage() 实现分页查询的完整解析
  • 数字ic后端设计从入门到精通4(含fusion compiler, tcl教学)CMOS VLSI Design
  • Baumer工业相机堡盟工业相机的工业视觉是否可以在室外可以做视觉检测项目
  • 【系统架构师】2025论文《基于架构的软件设计方法》【最新】
  • telnetlib源码深入解析
  • Java面试终极篇:Sentinel+Seata+Kafka Streams高并发架构实战
  • Adobe Acrobat pro在一份PDF中插入空白页
  • 【基于ALS模型的教育视频推荐系统(Java实现)】
  • java反序列化commons-collections链6
  • 邮件营销应对高退信率的策略
  • 一键解锁嵌入式UI开发——LVGL的“万能配方”
  • AI驱动网络范式革新:Smart Switch与智能路由的协同进化
  • 《飞飞重逢》手游:暴力治疗与团队赋能的战场艺术!
  • feign.RequestInterceptor 简介-笔记
  • 深入浅出:Java 中的动态类加载与编译技术
  • 2025.5.12 APIO 模拟赛总结
  • 小结: Port Security,DHCP Snooping,IPSG,DAI,
  • python opencv 将不同shape尺寸的图片制作video视频
  • 法国蒙彼利埃大学团队:运用元动力学模拟与马尔可夫状态模型解锁 G 蛋白偶联受体构象动态机制
  • Linux 服务器用 SSH 拉取多个 Git 工程
  • LeRobot 项目部署运行逻辑(七)—— ACT 在 Mobile ALOHA 训练与部署
  • 开发工具分享: Web前端编码常用的在线编译器
  • Matlab 基于滑模自抗扰的高速列车自动驾驶算法研究
  • Linux 软硬连接详解
  • linux下minio的进程管理脚本
  • LMFD格子多相流体力学仿真机:超级计算如何实现平民化?
  • Java高频面试之并发编程-16
  • Mysql的索引,慢查询和数据库表的设计以及乐观锁和悲观锁