刘盼盼
有十多年项目工作经验,涉及手机、汽车、芯片行业,目前就职于芯片大厂任谷歌开发者社区优秀讲师,腾讯技术训练营导师,某科技公司合伙人,善于挖掘技术背后的本质。
本书共13章,操作系统部分涉及内存管理、进程管理、文件系统、同步管理,以及系统调用。SoC部分涉及SoC启动的过程、设备模型、设备树原理、电源模块、时钟模块、引脚模块、时间模块以及中断模块,这些模块都是芯片运行的基本要求。作者站在一线开发者的角度先剖析了Kernel 6.6的实现原理,然后结合恩智浦i.MX9芯片的SoC硬件原理,由浅入深地讲解了操作系统和SoC的不解之谜。
刘盼盼
有十多年项目工作经验,涉及手机、汽车、芯片行业,目前就职于芯片大厂任谷歌开发者社区优秀讲师,腾讯技术训练营导师,某科技公司合伙人,善于挖掘技术背后的本质。
芯片与操作系统成为业界当下的热点。然而,业界少有从打通操作系统和芯片开发角度讲解的技术书籍。本书的特色在于挖掘Linux核心技术,剖析难点痛点,打通Linux操作系统与芯片开发链路,为嵌入式系统工程师、芯片设计工程师等从业者拓宽技术视野,助力我国在芯片与操作系统关键领域技术人才的培养。
操作系统与SoC(System on a Chip,系统级芯片)之间存在着紧密的联系。SoC是一种高度集成的芯片,它将多个功能模块(如CPU、GPU、NPU、存储器等)集成在一个芯片上,以实现更高效的性能和更低的功耗。操作系统则负责管理这些硬件资源,确保它们得到合理的分配和使用。如果把芯片比作一个人的心脏的话,操作系统无疑是一个人的灵魂。
势是未来发展的大势。人工智能、机器人、芯片自主、智能驾驶等新一代信息技术是当代智能科技的主要体现。在这个百年未有之大变局的历史机遇中,计算机底层教育的作用不言而喻,它是现代智能科技发展的核心支柱。计算机底层的技术包含芯片设计、操作系统、编译器、数学库等内容。目前,中美竞争的加剧使高端芯片和操作系统设计成为众所周知的“卡脖子”技术,国家开始重视底层技术,越来越多的企业投入芯片和操作系统的研发,比如华为的海思芯片和面向万物互联的鸿蒙操作系统。但对开发者而言,一直以来,芯片和操作系统是两个不同的领域。芯片从业者更多的是硬件工程师,操作系统从业者更多的是软件工程师,在这之间还有嵌入式工程师,彼此合作,又各自安好。可是操作系统和芯片开发彼此是紧密相连、相互依存的,芯片提供数据处理等核心能力,操作系统适配芯片架构来驱动硬件工作。芯片的性能影响操作系统运行的流畅度,操作系统合理地调配资源也能挖掘芯片的潜在性能。
道是事物背后的规律。回顾历史,每一次智能终端的发展,都会带来翻天覆地的变化。从PC时代的个人计算机,开启了数字化办公与学习的先河;到互联网时代的万维网,将全球信息紧密相连,彻底改变了信息传播的方式;再到移动互联网时代的智能手机,让信息获取与服务享受变得无处不在,极大提升了生活与工作的便捷性;直至现在的人工智能时代,以智能语音助手、自动驾驶汽车等为代表的产品,正逐步重塑生产方式、服务模式乃至社会结构,引领世界迈向一个更加智能化、自动化的未来。我们正在进入万物智能互联的新世界,万物智能互联的世界对传统的芯片和操作系统提出了新的需求。顺应时代发展,芯片和操作系统都出现了相应的革命,比如OpenAI的ChatGPT、恩智浦新研究的跨界处理器、谷歌新研究的TPU和Fuchsia、华为新研究的鸿蒙等,它们都是为万物智能互联新时代而生的新架构。
术是操作层面的方法。那么,如何学习底层技术?操作系统涉及的模块很多,包含内存管理、进程管理、文件系统、同步机制等内容,芯片开发的基本内容包括电源模块、时钟模块、时间模块、中断模块、引脚模块等,不同模块之间又是彼此关联的。想要精通这些模块,没有好的学习方法,基本无从下手。虽然“Talk is cheap. Show me the code.”,但除非你本身就是做操作系统或者芯片开发相关工作的,否则我不推荐大家把相关源码通读一遍,因为首先大部分人在工作时间已经够辛苦,工作之余并没有大量的时间去通读,其次即使你啃完了代码,但手头的工作和底层关系不大,没有工作的实践,过段时间还是会忘掉。
打通操作系统和芯片开发的过程,实际上是一个跨学科、跨领域的合作过程,需要操作系统开发人员和芯片设计工程师的紧密合作。尽管他们的工作背景和专长不同,但他们的目标是一致的,那就是提供高效、稳定、功能丰富的硬件和软件解决方案。市场上有很多芯片开发和操作系统的书籍,但似乎都是针对纯硬件或者纯软件的内容,鲜有将二者兼容,以至于操作系统和芯片开发从业者很难再次提升自己的内功。本书重点在于打通操作系统和芯片开发,让硬件工作者有机会走进软件的大门,让软件工作者有机会理解底层的本质。总之,如果你有志于修炼底层内功,那么这本《打通Linux操作系统和芯片开发》将是好的选择。
为什么写本书?
毕业后我一直从事底层技术开发,从起初的驱动开发、内核开发、安卓Framework开发,再到芯片级的系统开发,一直对底层的本质原理有着浓厚的兴趣,十多年的工作沉淀让我对操作系统和芯片级的软件开发有着一定的理解。我希望通过某种方式把自己的一些总结记录下来,另外,我一直觉得如果把人比作计算机,人的大脑更像是CPU,并不适合用来存储记忆,特别是随着时间的推移,经验也会化作遗忘,所以需要有像硬盘一样的东西把内容记录下来,这也是我选择写书的原因之一。
那为什么选择写打通操作系统和芯片开发的内容呢?我们知道,计算机行业是个变化极快的行业,特别是从事互联网行业的朋友,经常面对技术的更新,开发语言的迭代,每天过的都很焦虑,随着新人的入职,技术的变化,老人的技术经验似乎无法得到发挥,这也是为什么都说程序员有35岁失业风险的根本原因。那么技术更新不那么快的行业是不是就好点了呢?答案的确如此,比如更加接近底层的嵌入式行业、操作系统行业、芯片行业等都会比互联网行业好很多,特别是同时懂软件和硬件的工程师,甚至随着时间的推移,越老越吃香,而且国家越来越重视底层技术的开发。即便是在互联网行业,如果你对底层技术有着深厚的积累,依然可以很有竞争力,相当于有了武侠小说中所说的内功。一旦有了雄厚的内功,其他武功你一看就明白,一学就会,任何招式你和别人打出去的威力就不是一个级别。这种帮助无论对嵌入式开发者,还是对互联网程序员都是非常明显的。
学习非常重要的是什么?其实很简单,好的资料,好的老师,然后花时间投入进去。
现在人工智能发展得很快,特别是大模型的出现,几乎每个人都可以拥有自己的智能助手,完全可以利用人工智能充当好的老师。好的老师有了,那学习资料呢?我刚毕业那会儿,学习资料很少,更不用说偏向底层的计算机书籍,更是少之又少,只能通过阅读代码的方式一边理解,一边猜测背后的逻辑,很痛苦。很羡慕现在的学生,无论是视频、图文,还是自媒体、纸质书,市面上的学习资料很多,大大降低了学习的门槛。但这也是大的问题,资料太多带来的筛选成本和学习成本也很高,而且我发现,市场上虽然有很多操作系统、Linux内核、芯片开发的书籍,但彼此内容都是隔离的。芯片、硬件开发者中想了解软件开发的人很多,但无法找到合适的书籍。软件开发者想了解底层硬件技术原理,也无法找到合适的内容,这一度让有志于挖掘底层技术原理的从业者无从下手。这也是我选择写本书的原因之一,希望这本《打通Linux操作系统和芯片开发》能帮助一些人找到提升内功的抓手,借此机会在技术的道路上更上一层。
学习本书的好处
1. 有助于顺利通过大厂面试。大厂面试通常非常注重技术深度。对于底层技术的考查,能够有效筛选出真正有实力的候选人。在面试中,很多应聘者可能对应用层技术有一定的了解,但深入到操作系统原理、芯片架构等底层知识时,掌握这些知识的人相对较少。例如,在操作系统方面,能够深入讲解进程调度算法(如CFS,完全公平调度算法)、内存管理机制(如分页和分段机制)的应聘者会给面试官留下深刻印象。在芯片开发领域,如果了解芯片常用驱动等底层知识,那么能够在面试相关岗位时展现出自己的专业度。这是因为大厂往往有自己的底层技术研发需求,大厂在实际项目中会遇到很多与底层技术相关的问题。例如,软件在运行时出现性能瓶颈,可能与操作系统的内存分配不合理或者CPU调度策略不够优化有关。掌握底层技术的人能够从根源上分析和解决这些问题,这在面试中通过案例分析等环节可以很好地体现出来。
2. 拓宽技术职业方向。操作系统和芯片开发等底层技术的变化相对缓慢。与应用层技术频繁更新换代不同,底层技术的核心原理和架构在较长时间内保持稳定。例如,Linux操作系统的内核架构虽然在不断发展,但基本的进程管理、内存管理等核心机制变化不大。学习这些底层技术可以让从业者在较长的职业生涯中保持技术的有效性和竞争力。而且掌握底层技术能够使从业者更容易实现技术迁移。
无论是从不同行业领域之间的择业,还是从一种操作系统平台转向另一种,底层技术知识都能提供坚实的基础。例如,一个熟悉操作系统底层的开发者,在从传统PC操作系统开发转向移动操作系统开发时,能够更快地理解和适应新的开发环境,因为移动操作系统的很多底层原理(如进程管理、资源调度)与传统操作系统是相通的。在人工智能时代亦是如此。
3. 缓解35岁失业焦虑。在技术行业,35岁左右往往面临年轻从业者的竞争压力。学习操作系统和芯片开发等底层技术可以建立起较高的技术壁垒。这些底层技术需要长时间的学习和实践才能掌握,相比年轻从业者普遍掌握的应用层技术,底层技术更能体现资深从业者的价值。例如,在企业裁员时,能够对操作系统内核进行优化或者对芯片设计进行改进的技术人员,因其不可替代的技术能力,被裁掉的风险相对较低。
第1章内存管理
1.1内存管理的机制
1.1.1分段机制
1.1.2分页机制
1.2CPU访问内存的过程
1.2.1PN/PFN/PT/PTE
1.2.2MMU中的TLB和TTW
1.2.3一级页表映射过程
1.2.4为什么使用多级页表
1.3内存架构和内存模型
1.3.1Linux内存模型
1.3.2Linux内存映射
1.4memblock物理内存的初始化
1.4.1early boot memory
1.4.2memblock的数据结构
1.4.3memblock的初始化
1.5memblock物理内存的映射
1.5.1paging_init函数
1.5.2__create_pgd_mapping函数
1.6物理内存的软件划分
1.6.1划分的数据结构
1.6.2划分的初始化
1.7页帧分配器的实现
1.8页帧分配器的快速分配之水位控制
1.8.1水位的初始化
1.8.2水位的判断
1.9页帧分配器的快速分配之伙伴系统
1.9.1相关的数据结构
1.9.2伙伴算法申请页面
1.9.3伙伴算法释放页面
1.10页帧分配器的慢速分配之内存回收
1.10.1数据结构
1.10.2代码流程
1.11页帧分配器的慢速分配之内存碎片规整
1.11.1什么是内存碎片化
1.11.2规整碎片化页面的算法
1.11.3数据结构
1.11.4规整的三种方式
第2章进程管理
2.1内核对进程的描述
2.1.1通过task_struct描述进程
2.1.2如何获取当前进程
2.2用户态进程/线程的创建
2.2.1fork函数
2.2.2vfork函数
2.2.3pthread_create函数
2.2.4三者之间的关系
2.3do_fork函数的实现
2.3.1copy_process函数
2.3.2wake_up_new_task函数
2.4进程的调度
2.4.1进程的分类
2.4.2调度相关的数据结构
2.4.3调度时刻
2.4.4调度算法
2.4.5CFS调度器
2.4.6选择下一个进程
2.4.7进程上下文切换
2.5多核系统的负载均衡
2.5.1多核架构
2.5.2CPU拓扑
2.5.3调度域和调度组
2.5.4何时做负载均衡
2.5.5负载均衡的基本过程
第3章同步管理
3.1原子操作
3.2自旋锁
3.3信号量
3.4互斥锁
3.5RCU
第4章文件系统
4.1磁盘
4.1.1磁盘类型
4.1.2磁盘读写数据所花费的时间
4.2磁盘的分区
4.3磁盘上数据的分布
4.4查看文件系统的文件
4.4.1文件系统对象结构
4.4.2查看分区信息
4.4.3查看超级块
4.4.4查看块组描述符
4.5ext4文件系统
4.5.1磁盘布局
4.5.2ext3布局
4.5.3ext4中的inode
4.5.4ext4文件寻址
4.6查找文件test的过程
4.7虚拟文件系统
4.7.1文件系统类型(file_system_type)
4.7.2超级块(super_block)
4.7.3目录项(dentry)
4.7.4索引节点(inode)
4.7.5文件对象(file)
第5章系统调用
5.1系统调用的定义
5.2系统调用的处理流程
5.2.1用户态的处理
5.2.2内核态的处理
第6章SoC启动
6.1Uboot启动前的工作
6.1.1链接脚本和程序入口
6.1.2镜像容器
6.1.3SPL的启动
6.1.4ATF的启动
6.2Uboot的初始化过程
6.2.1Uboot的启动
6.2.2Uboot驱动的初始化
6.2.3Uboot的交互原理
6.3kernel的初始化过程
6.3.1内核运行的第一行代码
6.3.2head.S的执行过程
6.3.3内核子系统启动的全过程
第7章设备模型
7.1设备模型的基石
7.1.1设备模型是什么
7.1.2设备模型的实现
7.2设备模型的探究
7.2.1总线、设备和驱动模型
7.2.2设备树的出现
7.2.3各级设备的展开
第8章设备树原理
8.1设备树的基本用法
8.1.1设备树的结构
8.1.2设备树的语法
8.2设备树的解析过程
8.3设备树常用of操作函数
8.3.1查找节点的of函数
8.3.2查找父/子节点的of函数
8.3.3提取属性值的of函数
8.3.4其他常用的of函数
第9章电源模块
9.1电源子系统的power domain
9.1.1power domain的硬件实现
目录XVII
9.1.2power domain的软件实现
9.2电源子系统的runtime pm
9.2.1runtime pm在内核中的作用
9.2.2runtime pm的软件流程
9.2.3suspend/resume的过程
第10章时钟模块
10.1时钟控制器的硬件实现
10.1.1Clock Source
10.1.2Clock Root
10.1.3Clock Gate
10.2时钟控制器的驱动实现
10.3时钟子系统的实现
10.3.1时钟子系统之Clock Provider
10.3.2时钟子系统之Clock Consumer
第11章引脚模块
11.1IOMUX控制器的工作原理
11.1.1IOMUX控制器的硬件实现
11.1.2引脚的使用
11.2pinctrl驱动和client device使用过程
11.2.1pinctrl_desc结构体
11.2.2IOMUX控制器驱动初始化
11.2.3client device使用过程
第12章时间模块
12.1定时器和计时器的初始化
12.1.1local timer的初始化
12.1.2system counter的初始化
12.2定时器的应用
12.2.1高分辨率定时器
12.2.2低分辨率定时器
12.2.3sched_timer
第13章中断模块
13.1中断控制器(GIC)硬件原理
13.1.1GIC v3中断类别
13.1.2GIC v3组成
13.1.3中断路由
13.1.4中断处理状态机
13.1.5中断处理流程
13.2中断控制器的驱动实现
13.3中断的映射
13.3.1数据结构
13.3.2中断控制器注册irq_domain
13.3.3外设硬中断和虚拟中断号的映射关系
13.4中断的注册
13.5中断的处理
13.5.1保护现场
13.5.2中断处理
13.5.3恢复现场