操作系统实战 45 讲
彭东
网名 LMOS,Intel 傲腾项目关键开发者
65203 人已学习
新⼈⾸单¥68
登录后,你可以任选4讲全文学习
课程目录
已完结/共 60 讲
尝尝鲜:从一个Hello到另一个Hello (2讲)
特别放送 (1讲)
操作系统实战 45 讲
15
15
1.0x
00:00/00:00
登录|注册

15 | Linux初始化(下):从_start到第一个进程

建立第一个用户态进程
调用rest_init函数
初始化各个功能模块
调用Linux内核的第一个C函数
重新设置MMU页表
切换到长模式下解压vmlinux.bin.gz
建立新的全局段描述符表和MMU页表
跳转到vmlinux.bin文件中
调用16位main切换到保护模式
设置setup_header结构
清空bss
设置栈
kernel_init线程
x86_64_start_kernel函数
startup64函数
startup32函数
setup.bin的_start
第一个用户进程的建立
Linux内核的第一个C函数
vmlinux.bin解压和初始化
GRUB加载vmlinuz文件
Linux初始化流程
Linux初始化流程知识关系脑图

该思维导图由 AI 生成,仅供参考

你好,我是 LMOS。
今天我们继续来研究 Linux 的初始化流程,为你讲解如何解压内核,然后讲解 Linux 内核第一个 C 函数。最后,我们会用 Linux 的第一个用户进程的建立来收尾。
如果用你上手去玩一款新游戏做类比的话,那么上节课只是新手教程,而这节课就是更深入的实战了。后面你会看到很多熟悉的“面孔”,像是我们前面讲过的 CPU 工作模式、MMU 页表等等基础知识,这节课都会得到运用。

解压后内核初始化

下面,我们先从 setup.bin 文件的入口 _start 开始,了解启动信息结构,接着由 16 位 main 函数切换 CPU 到保护模式,然后跳入 vmlinux.bin 文件中的 startup_32 函数重新加载段描述符。
如果是 64 位的系统,就要进入 startup_64 函数,切换到 CPU 到长模式,最后调用 extract_kernel 函数解压 Linux 内核,并进入内核的 startup_64 函数,由此 Linux 内核开始运行。

为何要从 _start 开始

通过上节课对 vmlinuz 文件结构的研究,我们已经搞清楚了其中的 vmlinux.bin 是如何产生的,它是由 linux/arch/x86/boot/compressed 目录下的一些目标文件,以及 piggy.S 包含的一个 vmlinux.bin.gz 的压缩文件一起生成的。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

本文深入探讨了Linux初始化的流程,从内核解压到第一个用户进程的建立。文章首先介绍了从setup.bin文件的入口_start开始,解释了启动信息结构,以及在64位系统中切换到长模式的过程。接着详细解释了setup_header结构的重要性,以及16位的main函数在初始化过程中的作用。随后,文章介绍了go_to_protected_mode函数和protected_mode_jump函数的功能,以及在startup_32函数中重新加载段描述符、设置内核栈、检测CPU支持长模式等操作。最后,文章提到了进入长模式并跳转到startup_64函数的过程。整篇文章通过深入的技术细节,帮助读者全面了解了Linux初始化的流程,适合对Linux内核感兴趣的读者深入学习。文章还介绍了startup_64函数、extract_kernel函数以及Linux内核的startup_64和x86_64_start_kernel函数,展示了内核初始化的关键步骤和技术特点。文章内容丰富,涵盖了Linux内核初始化的各个重要环节,对于想深入了解Linux内核启动流程的读者具有很高的参考价值。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《操作系统实战 45 讲》
新⼈⾸单¥68
立即购买
登录 后留言

全部留言(16)

  • 最新
  • 精选
  • neohope
    大体上整理了一下,有问题欢迎帮忙指正【上】: Grub在/boot目录下找到的linux内核,是bzImage格式 1、bzImage格式生成: 1.1、head_64.S+其他源文件->编译-> vmlinux【A】 1.2、objcopy工具拷贝【 拷贝时,删除了文件中“.comment”段,符号表和重定位表】->vmlinux.bin【A】 1.3、gzib压缩->vmlinux.bin.gz 1.4、piggy打包,附加解压信息->piggy.o->其他.o文件一起链接->vmlinux【B】 1.5、objcopy工具拷贝【 拷贝时,删除了文件中“.comment”段,符号表和重定位表】->vmlinux【B】 1.6、head.S +main.c+其他->setup.bin 1.7、setup.bin+vmlinux.bin【B】->bzImage合并->bzImage 2、GRUB加载bzImage文件 2.1、会将bzImage的setup.bin加载到内存地址0x90000 处 2.2、把vmlinuz中的vmlinux.bin部分,加载到1MB 开始的内存地址 3、GRUB会继续执行setup.bin代码,入口在header.S【arch/x86/boot/header.S】 GRUB会填充linux内核的一个setup_header结构,将内核启动需要的信息,写入到内核中对应位置,而且GRUB自身也维护了一个相似的结构。 Header.S文件中从start_of_setup开始,其实就是这个setup_header的结构。 此外, bootparam.h有这个结构的C语言定义,会从Header.S中把数据拷贝到结构体中,方便后续使用。 4、GRUB然后会跳转到 0x90200开始执行【恰好跳过了最开始512 字节的 bootsector】,正好是head.S的_start这个位置; 5、在head.S最后,调用main函数继续执行 6、main函数【 arch/x86/boot/main.c】【16 位实模式】 6.1、拷贝header.S中setup_header结构,到boot_params【arch\x86\include\uapi\asm\bootparam.h】 6.2、调用BIOS中断,进行初始化设置,包括console、堆、CPU模式、内存、键盘、APM、显卡模式等 6.3、调用go_to_protected_mode进入保护模式 7、 go_to_protected_mode函数【 arch/x86/boot/pm.c】 7.1、安装实模式切换钩子 7.2、启用1M以上内存 7.3、设置中断描述符表IDT 7.4、设置全局描述符表GDT 7.4、protected_mode_jump,跳转到boot_params.hdr.code32_start【保护模式下,长跳转,地址为 0x100000】 8、恰好是vmlinux.bin在内存中的位置,通过这一跳转,正式进入vmlinux.bin 9、startup_32【 arch/x86/boot/compressed/head64.S】 全局描述符GDT 加载段描述符 设置栈 检查CPU是否支持长模式 开启PAE 建立MMU【4级,4G】 开启长模式 段描述符和startup_64地址入栈 开启分页和保护模式 弹出段描述符和startup_64地址到CS:RIP中,进入长模式 10、 startup_64【 arch/x86/boot/compressed/head64.S】 初始化寄存器 初始化栈 调准给MMU级别 压缩内核移动到Buffer最后 调用.Lrelocated 11、.Lrelocated 申请内存 被解压数据开始地址 被解压数据长度 解压数据开始地址 解压后数据长度 调用 extract_kernel解压内核 12、extract_kernel解压内核【 arch/x86/boot/compressed/misc.c】 保存boot_params 解压内核 解析ELF,处理重定向, 把 vmlinux 中的指令段、数据段、BSS 段,根据 elf 中信息和要求放入特定的内存空间 返回了解压后内核地址,保存到%rax 13、返回到.Lrelocated继续执行 跳转到%rax【解压后内核地址】,继续执行 解压后的内核文件,入口函数为【arch/x86/kernel/head_64.S】

    作者回复: 学习非常认真啊

    2021-06-12
    3
    33
  • neohope
    大体上整理了一下,有问题欢迎帮忙指正【下】: 14、SYM_CODE_START_NOALIGN(startup_64)【arch/x86/kernel/head_64.S】 SMP 系统加电之后,总线仲裁机制会选出多个 CPU 中的一个 CPU,称为 BSP,也叫第一个 CPU。它负责让 BSP CPU 先启动,其它 CPU 则等待 BSP CPU 的唤醒。 第一个启动的 CPU,会跳转 secondary_startup_64 函数中 1 标号处,对于其它被唤醒的 CPU 则会直接执行 secondary_startup_64 函数。 15、secondary_startup_64 函数【arch/x86/kernel/head_64.S】 各类初始化工作,gdt、描述符等 跳转到initial_code,也就是x86_64_start_kernel 16、 x86_64_start_kernel【 arch/x86/kernel/head64.c】 各类初始化工作,清理bss段,清理页目录,复制引导信息等 调用x86_64_start_reservations 17、x86_64_start_reservations【 arch/x86/kernel/head64.c】 调用start_kernel(); 18、start_kernel【 init/main.c】 各类初始化:ARCH、日志、陷阱门、内存、调度器、工作队列、RCU锁、Trace事件、IRQ中断、定时器、软中断、ACPI、fork、缓存、安全、pagecache、信号量、cpuset、cgroup等等 调用 arch_call_rest_init,调用到rest_init 19、rest_init【 init/main.c】 kernel_thread,调用_do_fork,创建了kernel_init进程,pid=1 . 是系统中所有其它用户进程的祖先 kernel_thread,调用_do_fork,创建了 kernel_thread进程,pid=2, 负责所有内核线程的调度和管理 【最后当前的进程, 会变成idle进程,pid=0】 20、kernel_init 根据内核启动参数,调用run_init_process,创建对应进程 调用try_to_run_init_process函数,尝试以 /sbin/init、/etc/init、/bin/init、/bin/sh 这些文件为可执行文件建立init进程,只要其中之一成功就可以 调用链如下: try_to_run_init_process run_init_process kernel_execve bprm_execve exec_binprm search_binary_handler-》依次尝试按各种可执行文件格式进行加载,而ELF的处理函数为 load_elf_binary load_elf_binary start_thread start_thread_common,会将寄存器地址,设置为ELF启动地址 当从系统调用返回用户态时,init进程【1号进程】,就从ELF执行了 到此为止,系统的启动过程结束。

    作者回复: 是的 大写6666

    2021-06-12
    2
    17
  • pedro
    _start在setup.bin的开头, x86_64_start_kernel在vmlinux.bin的开头,然后start_kernel初始化,然后rest_init初始化第一个用户进程和第一个内核进程,开始操作系统罪恶的一生。

    作者回复: 哈哈

    2021-06-11
    6
  • Geek_59a6f9
    老师,你这里说的grub是grub legacy还是grub2啊?grub2应该首先会进入保护模式,那grub2还会跳转到inux/arch/x86/boot/head.S 里的main函数 再去执行一次切换保护模式吗?这个时候应该早就是保护模式了吧

    作者回复: 是的 ,但是Linux并不用GRUB初始化的保护模式

    2021-06-24
    2
    2
  • 青玉白露
    课程已经快进入正题了,下一步就是内存了吧

    编辑回复: 是的,下个模块是内存管理,更加有挑战性,敬请期待!

    2021-07-06
    1
  • blentle
    收获盛大,终于看到了稍微能消化的一篇了

    作者回复: 你好,你平常接触Linux吧

    2021-06-11
    1
  • springXu
    这个问题是考对Linux熟悉程度了。哈

    作者回复: 这很难吗

    2021-06-11
    1
  • Qfeng
    内核启动最后创建了两个进程:kernel_init和kernel_thread,前面是第一个用户进程,后续用户进程都是从它fork而来,后面是内核进程,用来管理后续内核线程调度。这两个进程令我印象深刻。

    作者回复: 666666

    2022-06-19
  • 艾恩凝
    这节终于结束了,计划俩月完成,感觉进度有点慢了,到现在快20天了,应该去年来参与这门课的

    编辑回复: 相逢即有缘,现在跟进也不迟,有什么收获或疑问欢迎多多分享哦(ง •̀_•́)ง

    2022-04-10
  • ifelse
    果然厉害了

    作者回复: 什么厉害了

    2022-02-13
收起评论
显示
设置
留言
16
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部