猜你喜欢
UNIX xv6内核源码深入剖析(软件开发源码精讲系列)

UNIX xv6内核源码深入剖析(软件开发源码精讲系列)

书籍作者:高联雄 ISBN:9787302614630
书籍语言:简体中文 连载状态:全集
电子书格式:pdf,txt,epub,mobi,azw3 下载次数:8854
创建日期:2023-05-20 发布日期:2023-05-20
运行环境:PC/Windows/Linux/Mac/IOS/iPhone/iPad/Kindle/Android/安卓/平板
内容简介

本书对UNIX xv6的源码进行了深入剖析和详细注解,同时配合大量实例与图表,对每个模块先提炼关键数据结构和核心方法,再结合源码分析其工作机制,让读者明白其原理及具体实现,以求理论和实践能力同步提升,为深入理解操作系统原理乃至进一步研究学习Linux和Android等类UNIX系统内核打下坚实基础。

本书第1章对xv6进行概述;第2章介绍xv6操作系统结构;第3章介绍xv6开发、测试和运行的软件环境;第4章简要介绍x86计算机组成原理;第5章介绍x86的实模式与保护模式;第6章深入分析xv6的启动;第7~10章介绍xv6的虚拟空间管理、中断与系统调用、锁以及进程管理,第11、12章介绍xv6的文件系统;第13章介绍exec()函数、管道与字符串的实现;第14章介绍xv6的多处理器支持;第15章介绍字符设备驱动;第16章介绍用户进程的初始化、API和Shell的实现。

本书适合操作系统初、中级学习者,系统程序员,嵌入式系统开发者以及对UNIX和Linux等类UNIX内核感兴趣的读者。


作者简介

高联雄,北京邮电大学博士,昆明学院副教授、硕导,主要研究领域为信号与信息处理。先后主持和参与了华为鸿蒙操作系统实验等省部级以上教学和科研项目10余项,参与的研究工作还获得了省部级科技进步奖;潜心操作系统教学二十余年,从UNIX、MINIX、Linux到xv6,每一个重要的操作系统均深入内核研读源码并应用于教学之中;鉴于xv6的简洁优美,耗费两年游刃其间,写成《UNIX xv6内核源码深入剖析》一书。

前言

前言



操作系统在计算机系统中处于承上启下的重要地位,它对下管理计算机的硬件资源,对上服务应用程序和用户。阅读内核源码是学习操作系统原理及实现和理解计算机系统的重要途径,但实际的操作系统太过庞大,以致让人无法窥其全貌,例如2021年4月发布的Linux内核版本5.10稳定版已经达到了约3000万行源码的规模。

小巧的UNIX早期版本UNIX V6曾经是MIT等众多高校操作系统课程源码研读的首选,而且Linux、iOS和Android都基于UNIX V6,通过研读UNIX V6源码可以更深入理解UNIX、Linux等操作系统内核的基本概念及实现原理。

但UNIX V6基于的PDP-11硬件平台早已被淘汰,而UNIX V6部分汇编代码直接使用了PDP-11指令;UNIX V6所用的C语言也是最早期的版本;而且UNIX V6部分代码略显粗糙,这些因素给学习者造成了极大障碍。因此,2006年MIT基于Intel 的32位x86处理器用标准C语言重新实现了UNIX V6并命名为UNIX xv6,简称xv6。于2018年9月发布的xv6最终修订版rev11总共只有9300多行,xv6沿袭了UNIX V6的基本架构并对其粗糙的地方进行了改进。xv6及其变种目前被麻省理工学院(MIT)、耶鲁大学、清华大学、北京航空航天大学和哈尔滨工业大学等众多高校选为操作系统教学和实验平台。

《UNIX xv6内核源码深入剖析》结合源码深度剖析xv6如何在Intel的32位x86架构上实现UNIX V6操作系统,配套源码读者可以扫描下方二维码获取,《UNIX xv6内核源码深入剖析》涉及的思想和概念可以为Linux、iOS、Android乃至嵌入式系统的开发人员理解操作系统底层原理提供一条便捷之道。

源码

考虑到部分读者对如何学习操作系统及为何研究xv6源码存在疑问,因此《UNIX xv6内核源码深入剖析》先阐述操作系统的学习之道,然后再解释xv6为何适合作为打开操作系统内核的钥匙,最后给出《UNIX xv6内核源码深入剖析》的结构。

1. 操作系统的学习之道

操作系统的学习有以下4个循序渐进的途径和层次。

1)读原著

首先读一本经典的操作系统书籍,如Tanenbaum的《操作系统:设计与实现(第3版)》《现代操作系统》或者Silberschatz的《操作系统概念》,以对操作系统的基本概念(如进程管理、内存管理、文件系统和I/O管理)有基本的理解;此外还可动手编写一些程序来调用操作系统核心API,实现进程管理、内存分配和文件创建等功能。

如果对计算机系统基本原理不太熟悉,《深入理解计算机系统》可帮助读者对计算机系统有全面且深入的认识;学习操作系统需要理解CPU的6个重要机制:寄存器、多级缓存、分段、分页、中断以及多核同步,读者可参阅计算机组成原理方面的书籍,如David A. Patterson的《计算机组成与设计》;对于x86处理器的技术细节,Intel的开发手册Software Developer Manuals for Intel? 64 and IA-32 Architectures(简称Intel SDM)是权威的参考资料,但Intel SDM近5000页的体量过于庞大,所以更适合作为工具书查阅。

2)探源码

只了解操作系统的一些概念对于学习操作系统来说还只能算是纸上谈兵,如同医生要学习人体解剖学,计算机相关专业的从业者应该“解剖”一个操作系统。源码面前了无秘密,探究内核源码是剖析操作系统的最佳途径,研读内核源码会让读者对计算机系统从硬件到操作系统原理及实现有一个清晰完整的理解。另外,一些操作系统内核源码堪称大师杰作,是学习编程的典范;很多操作系统内核如UNIX、Linux等都是用C语言编写的,因此内核源码也是程序员学习C语言的优秀范本,C语言的指针、结构体和宏等高级特性在操作系统内核源码中体现得淋漓尽致。

研读源码经常涉及函数的调用与实现、变量和类型的定义,常常在源码之间来回跳转,而且对于一些很隐晦的部分如函数指针,只有具体分析上下文才能确定它关联到哪个函数,因此需要一个专业工具来阅读源码,Source Insight是阅读源码的利器,Visual Studio Code也是不错的选择。

3)改源码

对源码研习到一定阶段,读者可尝试修改操作系统内核源码。首先可以尝试在虚拟机上编译、运行并调试内核,让源码“活”起来;然后找到自己关注的模块动手修改,例如可以修改调度算法,实现内存映射、设备驱动、文件系统或者某个用户命令(如ls)等。

4)做原型

如果到第三个层次仍有余力,读者不妨尝试从零开始编写一个简单的操作系统内核。计算机界的大师如UNIX的作者Ken、Linux的作者Linus以及Minix的作者Andrew Stuart Tanenbaum就是这样做的。为实现操作系统原型,读者可参考于渊的《Orange’s 一个操作系统的实现》、川合秀实的《30天自制操作系统》以及田宇的《一个64位操作系统的设计与实现》。

2. 选择xv6源码的原因

研读操作系统源码可帮助读者真正理解操作系统的原理及实现技术,但实际的操作系统内核往往太过庞大。源码只有1万多行的UNIX V6是现代操作系统的鼻祖,UNIX V6曾经是众多高校操作系统课程研习内核源码的首选。

《UNIX xv6内核源码深入剖析》选择xv6的原因如下。

1)xv6基于UNIX V6

Linux、Minix、BSD、iOS和Android等众多现代操作系统都是在UNIX V6的基础上发展而来的,xv6也基于UNIX V6。xv6 基本沿袭UNIX V6的结构和风格,并对其粗糙的地方进行了改进,还增加了对多处理器的支持。

2)xv6基于Intel 的32位架构

UNIX V6基于古老的PDP-11系统, MIT将xv6移植到了Intel的32位x86架构,该架构支持多任务、虚拟内存和多核等现代处理器的基本特征。当代的计算机专业人员对x86架构更为熟悉,研读xv6源码时无须再去完成对PDP-11的“考古”工作。

3)xv6基于ANSI C

C语言经过多年的发展形成了标准化的ANSI C版本,ANSI C被众多编译器支持,ANSI C与UNIX V6使用的早期C语言版本已经有很大差别;xv6采用ANSI C来书写,为阅读、修改、编译和调试源码带来了极大方便。

4)xv6足够精干

xv6内核只有约8800行C语言代码、350行汇编语言代码、100行链接脚本和50行Perl脚本,但麻雀虽小五脏俱全,实现了包含进程管理、内存管理、完整的文件系统以及键盘、显示器和IDE硬盘等I/O设备管理、多核支持以及一个简单的Shell。此外还实现了mkfs、cat、grep和ls等命令。

5)xv6足够典型

读者进一步阅读Linux内核源码将会发现,xv6与现代操作系统如Linux无论是在设计思想上还是在启动、内存空间管理、中断、进程管理等功能实现上都已经足够相似。

6)xv6为学习而生

MIT开发xv6的初衷就是为了操作系统的学习,其设计简洁而优美,通过研读xv6,读者更容易进入Linux等操作系统的内核。

3. 《UNIX xv6内核源码深入剖析》的结构

《UNIX xv6内核源码深入剖析》共16章。

第1章是xv6 的整体概述,简要介绍xv6的前身UNIX、xv6的诞生及源码和文档。

第2章介绍xv6操作系统的整体结构,主要包括xv6的体系结构、进程管理、内存管理、设备驱动与文件系统,以及系统调用与API。

第3章介绍xv6操作系统使用的C语言高级特性和AT&T汇编语言与内联汇编、编译与链接工具,以及调试工具和运行环境。

第4章简要介绍x86体系32位计算机的组成原理,包括CPU、内存、外设、中断系统、I/O端口、I/O接口控制器与外设。

第5章介绍x86体系32位计算机的实模式与保护模式、分段管理与分页管理。

第6章介绍xv6的引导、内核进入与初始化过程。

第7章介绍xv6的虚拟空间管理,包括虚拟空间布局与映射、空间分配与释放以及进程内核空间与用户空间管理。

第8章介绍xv6的中断处理机制、系统调用和设备驱动,包括中断系统初始化、中断处理过程、系统调用与驱动程序以及中断过程的堆栈。

第9章介绍自旋锁、睡眠锁与内核死锁。

第10章介绍进程管理,包括进程的概念、进程调度与切换和进程生命周期的主要函数。

第11章介绍文件系统的I/O 处理、磁盘块缓冲与日志、块分配、i节点与目录管理。

第12章介绍文件描述符与文件系统调用。

第13章介绍exec()函数、管道以及基本的字符串处理函数。

第14章介绍多处理器的系统架构、数据结构和硬件。

第15章介绍键盘、串口和控制台等字符设备的驱动。

第16章介绍用户进程初始化、接口函数和Shell。

xv6的整体结构和《UNIX xv6内核源码深入剖析》各章之间的对应关系如图0.1所示。

图0.1 xv6的整体结构和《UNIX xv6内核源码深入剖析》各章之间的对应关系

由于编者水平有限,书中不当之处在所难免,欢迎广大同行和读者批评指正。


高联雄

2022年7月


目录

目录




第1章 xv6概述

1.1 xv6的前身UNIX

1.1.1 UNIX发展简史

1.1.2 UNIX家族

1.2 xv6的诞生

1.3 xv6的源码与文档

第2章 xv6操作系统结构

2.1 xv6体系结构

2.1.1 硬件与内核

2.1.2 界面

2.1.3 内核态与用户态

2.2 进程管理

2.3 虚拟内存、文件与I/O设备驱动

2.4 系统调用、API与内核函数

2.4.1 系统调用

2.4.2 API

2.4.3 内核函数

第3章 xv6的软件环境

3.1 xv6的C语言技巧

3.1.1 static

3.1.2 inline

3.1.3 函数指针

3.1.4 函数指针示例

3.1.5 双重指针

3.2 AT&T汇编与内联汇编

3.2.1 AT&T汇编

3.2.2 GCC内联汇编

3.3 函数调用与堆栈

3.3.1 栈帧、寄存器惯例与调用约定

3.3.2 栈帧示例1

3.3.3 栈帧示例2

3.3.4 汇编语言中调用C语言函数

3.3.5 C语言函数调用汇编语言函数

3.4 xv6编译、调试与链接

3.4.1 gcc命令

3.4.2 make命令

3.4.3 xv6的Makefile文件

3.4.4 gdb命令

3.4.5 ELF文件结构

3.4.6 使用ld命令链接xv6

3.5 Bochs与QEMU模拟器

3.5.1 Bochs模拟器

3.5.2 Bochs模拟器的配置

3.5.3 QEMU模拟器选项及内核调试

第4章 x86计算机组成原理

4.1 计算机系统

4.2 计算机硬件系统

4.2.1 硬件组成

4.2.2 总线

4.3 CPU

4.3.1 Cache与指令部件

4.3.2 MMU与BIU

4.3.3 寄存器组

4.4 内存

4.5 中断系统

4.5.1 中断

4.5.2 中断控制器与中断处理程序

4.6 I/O端口与外设

4.6.1 I/O端口与端口寻址

4.6.2 控制器与I/O设备

第5章 x86实模式与保护模式

5.1 x86的地址与工作模式

5.1.1 地址的概念

5.1.2 16位实模式

5.1.3 32位保护模式

5.2 A20地址线

5.3 保护模式与段寄存器

5.3.1 分段机制

5.3.2 逻辑地址转换为线性地址

5.3.3 段选择符

5.3.4 段寄存器

5.3.5 xv6的段选择符和段寄存器的设定

5.4 描述符

5.4.1 描述符格式

5.4.2 非系统描述符

5.4.3 系统描述符

5.4.4 xv6中的描述符

5.5 描述符表、TSS与特权等级保护

5.5.1 描述符表

5.5.2 TSS与任务切换

5.5.3 系统地址寄存器

5.5.4 段的特权等级保护

5.6 xv6的段管理

5.6.1 实模式下的段

5.6.2 保护模式引导阶段的GDT

5.6.3 内核的GDT

5.6.4 IDT

5.6.5 TSS与TR

5.7 保护模式分页机制

5.7.1 控制寄存器

5.7.2 分页机制

5.7.3 CR3、页目录项与页表项的格式

5.7.4 虚拟地址与物理地址的转换

5.8 xv6的地址空间

第6章 xv6的启动

6.1 概述

6.1.1 引导扇区与启动流程

6.1.2 启动过程的地址空间设置

6.1.3 启动过程的堆栈

6.2 BP的引导

6.2.1 BP从实模式进入保护模式

6.2.2 进入32位模式

6.2.3 调用bootmain()函数

6.2.4 BP加载内核映像文件

6.3 BP进入内核

6.3.1 内核入口地址

6.3.2 内核的进入

6.4 BP的初始化

6.4.1 运行主函数

6.4.2 启动AP

6.5 AP的进入与初始化

6.5.1 AP的进入

6.5.2 AP的初始化

第7章 虚拟空间管理

7.1 虚拟地址空间布局与映射

7.1.1 虚拟地址空间及布局

7.1.2 内核空间映射

7.1.3 内核的几个特殊地址

7.2 空间初始化、分配与释放

7.2.1 空闲帧管理

7.2.2 内核页面分配

7.2.3 内存初始化

7.2.4 空间释放

7.3 内核虚拟空间管理

7.3.1 内核虚拟空间分配、构建与切换

7.3.2 页面映射与页表查找

7.4 用户空间管理

7.4.1 初始进程的用户空间

7.4.2 用户空间加载

7.4.3 用户空间复制

7.4.4 用户空间切换

7.4.5 用户空间分配与释放

第8章 中断与系统调用

8.1 xv6中断处理

8.1.1 IDT初始化

8.1.2 xv6中断号

8.1.3 中断向量数组与中断向量

8.1.4 中断响应与中断返回

8.1.5 中断处理程序

8.2 系统调用

8.2.1 系统调用函数

8.2.2 系统调用函数的实现

8.2.3 系统调用分派

8.2.4 函数指针数组与系统函数

8.2.5 提取调用参数

8.2.6 系统调用示例

8.3 驱动程序

8.4 中断与系统调用及内核堆栈

8.4.1 中断与系统调用处理过程

8.4.2 中断的内核堆栈

第9章 锁

9.1 自旋锁

9.1.1 自旋锁的概念

9.1.2 自旋锁的实现

9.2 睡眠锁

9.2.1 睡眠锁的概念

9.2.2 睡眠锁的实现

9.3 内核的死锁

第10章 进程管理

10.1 进程的基本概念

10.1.1 进程的概念

10.1.2 进程的状态与生命周期

10.1.3 进程的上下文

10.1.4 处理器结构体、当前处理器与当前进程

10.2 进程的切换

10.2.1 上下文切换原理

10.2.2 切换函数的定义

10.2.3 切换函数的实现

10.2.4 切换函数的详细解释

10.2.5 上下文切换与陷阱帧

10.3 进程调度与进程表

10.3.1 进程的调度

10.3.2 进程表

10.4 进程的生成、退出与等待

10.4.1 进程的生成、退出与等待示例

10.4.2 创建子进程

10.4.3 进程退出与等待

10.5 进程的睡眠与唤醒

10.5.1 条件同步

10.5.2 空等问题

10.5.3 唤醒丢失问题

10.5.4 睡眠与唤醒函数的实现

10.6 进程让出与杀死进程

10.7 系统的初始进程

10.7.1 初始进程的建立

10.7.2 切换入初始进程

第11章 文件系统

11.1 概述

11.1.1 文件系统的功能

11.1.2 文件系统的分层

11.1.3 磁盘布局

11.2 磁盘层

11.2.1 磁盘初始化

11.2.2 磁盘中断处理

11.2.3 磁盘读写

11.3 块缓存层

11.3.1 缓冲块结构体

11.3.2 块缓存及其初始化

11.3.3 缓冲块读取

11.3.4 缓冲块写入与释放

11.3.5 缓冲块的使用

11.4 日志层

11.4.1 事务与日志

11.4.2 日志

11.4.3 日志的静态函数

11.4.4 日志的对外接口

11.4.5 事务的操作与实现

11.5 磁盘块管理

11.6 i节点

11.6.1 磁盘i节点

11.6.2 i节点及其锁

11.6.3 icache初始化与i节点更新

11.6.4 i节点的分配、获取、复制与释放

11.6.5 i节点的映射、截断、状态与读写

11.7 目录层

11.7.1 目录项

11.7.2 目录项查找

11.7.3 目录项链接

11.7.4 通过路径查找i节点

第12章 文件描述符与系统调用

12.1 文件描述符层

12.1.1 文件结构体

12.1.2 文件表及其初始化

12.1.3 文件分配、文件指针复制与关闭

12.1.4 文件状态与文件读写

12.2 系统调用层

12.2.1 文件系统调用

12.2.2 链接与删除链接

12.2.3 文件创建

12.2.4 文件打开

12.2.5 文件读写

12.2.6 管道

12.2.7 载入执行



第13章 exec()函数、管道与字符串

13.1 exec()函数

13.1.1 内核函数exec()

13.1.2 系统调用函数exec()

13.2 管道

13.2.1 管道结构体

13.2.2 管道的分配、关闭与读写

13.2.3 管道系统调用函数

13.3 字符串

第14章 多处理器

14.1 多处理器系统架构

14.2 多处理器配置的数据结构

14.2.1 多处理器环境与内存布局

14.2.2 mp结构体

14.2.3 MP配置表头

14.2.4 MP配置表表项

14.3 LAPIC

14.3.1 LAPIC的结构

14.3.2 LAPIC的寄存器

14.3.3 LAPIC ID与版本

14.3.4 ICR与AP启动

14.3.5 LAPIC计时器

14.3.6 伪中断

14.3.7 LVT与ICR

14.3.8 EOI与TPR

14.3.9 LAPIC可接收的中断源

14.4 I/O APIC

14.4.1 I/O APIC寄存器

14.4.2 I/O APIC寄存器访问

14.4.3 I/O APIC初始化与中断打开

第15章 字符设备驱动

15.1 键盘

15.1.1 键盘端口

15.1.2 扫描码

15.1.3 中断处理与驱动

15.2 控制台

15.2.1 控制台与文件读写

15.2.2 控制台输入

15.2.3 控制台输出

15.2.4 标准文件初始化

15.3 控制台输出示例

15.4 串口通信

15.4.1 UART硬件

15.4.2 UART端口

15.4.3 UART初始化

15.4.4 UART输入输出与中断处理

第16章 初始进程、API与Shell

16.1 初始进程

16.1.1 载入初始用户程序

16.1.2 初始用户程序init

16.2 API

16.2.1 API的定义和实现

16.2.2 接口函数使用示例

16.3 Shell

16.3.1 Shell概述

16.3.2 程序sh的主要功能

16.4 命令结构体及其构造与运行

16.4.1 命令

16.4.2 载入执行命令

16.4.3 重定向命令

16.4.4 管道命令

16.4.5 并列命令

16.4.6 后台命令

16.5 输入字符串的解析

16.5.1 命令解析

16.5.2 行解析

16.5.3 管道命令解析

16.5.4 重定向命令解析

16.5.5 块解析函数

16.5.6 载入执行命令解析

16.5.7 提取操作符

参考文献

附录A 缩略语与术语






产品特色