OS 的基本原理与简单实现
1 操作系统简介
1.1 应具备的背景知识和学习环境
设计实现操作系统其实就是设计实现一个可以管理CPU、内存和各种外设,并管理和服务应用软件的系统软件
- 计算机原理课程
- 程序设计课程
- 掌握C语言
1.2 外设
-
计算机系统中的硬件设备(外设),一般连接在计算接系统中 I/O 总线上,通过 I/O 控制器与 CPU 进行交互。
-
I/O 控制器在物理上包含三个层次:
- I/O 地址空间(即 I/O 端口):是 CPU 可以直接访问的地址
- CPU 一般支持 I/O 地址空间访问,即通过特定的I/O 访问指令访问
- 也支持基于内存的 I/O 地址空间,即通过一般的访存指令访问
- 这些 I/O 访问请求通过 I/O 总线传递给 I/O 接口
- I/O 接口:是处于一组 I/O 端口和对应的设备控制器之间的一种硬件电路
- 将I/O访问请求中的特定值转换成设备所需要的命令和数据
- 检测设备的状态变化,及时将各种状态信息写回到特定I/O地址空间,供操作系统通过I/O访问指令来访问
- I/O接口包括键盘接口、图形接口、磁盘接口、总线鼠标、网络接口、括并口、串口、通用串行总线、PCMCIA接口和SCSI接口等
- 设备控制器:只有少数复杂的设备才需要
- 负责解释从I/O接口接收到的高级命令,并将其以适当的方式发送到I/O设备
- 并且对I/O设备发送的消息进行解释并修改I/O端口的状态寄存器
- I/O 地址空间(即 I/O 端口):是 CPU 可以直接访问的地址
-
操作系统对硬件设备的控制方式
- 程序循环检测方式(Programmed I/O,简称PIO)
- 中断驱动方式**(Interrupt-driven I/O**)
- 直接内存访问方式(DMA, Direct Memory Access)
1.3 内存
-
用于存放代码和数据地址的硬件,访问速度快,空间大
-
访问内存空间的索引:内存地址
- 物理地址
- CPU 通过总线访问物理内存用到的物理内存
- 逻辑地址
- 编写应用程序所用到
- C 语言中的指针
- 物理地址
-
对于一般的32位CPU而言,以寻址的物理内存地址空间为2^32= 4 G 字节,支持以页(页大小一般为 4 KB )为单位对内物理内存空间进行重新编排内存地址,形成虚拟内存地址,而编排虚拟内存地址的策略由操作系统完成。这样操作系统就可以指定不同的物理内存空间给应用程序,而应用程序“看到”的是操作系统在CPU的支持下虚拟化后的地址空间。最终,让操作系统可以更灵活地安排应用程序所占用的内存空间,也简化了应用程序对内存空间的管理。
1.3.1 x86 的内存管理
- 32 位的处理器:可以寻址的物理内存地址空间为 2^32 = 4 G 字节
- 三个地址空间概念:
- 物理地址
- 处理器提交到总线上用于访问计算机系统中的内存和外设的最终地址
- 一个计算机系统中只有一个物理地址空间
- 线性地址
- 80386处理器通过段(Segment)机制控制下的形成的地址空间
- 段机制
- 在操作系统的管理下,每个运行的应用程序有相对独立的一个或多个内存空间段,每个段有各自的起始地址和长度属性,大小不固定,这样可让多个运行的应用程序之间相互隔离,实现对地址空间的保护。
- 在操作系统完成对80386处理器段机制的初始化和配置(主要是需要操作系统通过特定的指令和操作建立全局描述符表,完成虚拟地址与线性地址的映射关系)后,80386处理器的段管理功能单元负责把虚拟地址转换成线性地址
- 页机制
- 页机制,每个页的大小是固定的(4 KB),可完成对内存单元的安全保护,隔离,可有效支持大量应用程序分散的使用大内存的情况
- 在操作系统完成对80386处理器页机制的初始化和配置(主要是需要操作系统通过特定的指令和操作建立页表,完成虚拟地址与线性地址的映射关系)后,应用程序看到的逻辑地址先被处理器中的段管理功能单元转换为线性地址,然后再通过80386处理器中的页管理功能单元把线性地址转换成物理地址。
- 逻辑地址
- 物理地址
页机制和段机制有一定程度的功能重复,但Intel公司为了向下兼容,使得两者一直共存
- 分段机制启动,分页机制为启动时:逻辑地址——段机制处理——>线性地址==物理地址
- 两个机制都启动时:逻辑地址——段机制处理——>线性地址——页机制处理——>物理地址
1.4 CPU
CPU 硬件至少支持用户特权级和内核特权级**(控制隔离)和内存空间隔离(数据隔离)**
- 通用 CPU 一般能够在硬件上支持内存空间的隔离,使得多个程序在各自独立的内存空间中并发执行
- 这种硬件机制即支持用户特权级和内核特权级
- 应用程序运行在用户特权级,这样应用不能执行特权指令,且不能破坏操作系统内核的数据和操作系统执行过程
- 操作系统内核运行在内核特权级,可以访问特权指令,并管理和控制应用程序,硬件外设等
1.4.1 RISC-V 的 CPU 运行模式
- 80386 处理器有四种运行模式
- Machine 模式
- Hypervisor 模式
- Supervisor 模式
- User 模式
- 实模式
- 个人计算机早期8086处理器采用的一种简单运行模式
- 加点启动后处于实模式运行状态
- 实模式状态下,软件可访问的物理内存地址空间不能超过1 MB,且无法发挥 Intel 80386以上级别32位 CPU 的4 GB 内存管理能力
- 实模式将整个物理内存看成分段区域,程序代码和数据位于不同区域
- 操作系统和用户程序未区别对待,每一个指针都指向实际的物理地址
- 注意:若用户程序的一个指针指向了操作系统区域或者其他用户程序区域,并修改,后果不堪设想
对于ucore无必要涉及
- 保护模式
- 主要目标是确保应用程序无法对操作系统进行破坏
- 实际上,80386就是通过在实模式下初始化控制寄存器(如GDTR,LDTR,IDTR与TR等管理寄存器)以及页表,然后再通过设置CR0寄存器使其中的保护模式 使能位置位,从而进入到80386的保护模式
- 当80386工作在保护模式下的时候,其所有的32根地址线都可供寻址,物理寻址空间高达4 GB
- 在保护模式下,支持内存分页机制,提供了对虚拟内存的良好支持
- 保护模式下80386支持多任务,还支持优先级机制,不同的程序可以运行在不同的特权级上
- 特权级一共分0~3四个级别,操作系统运行在最高的特权级0上,应用程序则运行在比较低的级别上;
- 配合良好的检查机制后,既可以在任务间实现数据的安全共享也可以很好地隔离各个任务。
1.5 计算机硬件架构
- 操作系统在计算机硬件上运行,且第一要务:对硬件进行控制和管理
- 了解支撑操作系统运行的硬件环境,即了解处理器体系结构和机器指令集
- 为了对OS和计算机硬件之间的关系建立一个比较全面和概览性的理解,先理解一个抽象的简化计算机系统,在逐步进入到某一具体CPU,即 RISC-V
1.5.1 一般计算机硬件架构
运行操作系统的基本计算机硬件架构
一台计算机可抽象一台以**图灵机(Turing Machine)为理想模型,以冯诺依曼架构( Von Neumann Architecture)**为实现模型的电子设备,包括CPU、memory和 I/O 设备
- CPU (中央处理器):执行操作系统的指令,完成相关计算和读写内存
- 物理内存保存操作系统的指令和需要处理的数据
- 外部设备用于实现操作系统的输入(键盘,硬盘),输出(显示器、并口、串口),计时(时钟),永久存储(硬盘)
![计算机抽象图](https://i-blog.csdnimg.cn/blog_migrate/87f9e2c7a2ca9480e0cd6a5d1e3e0894.png)
CPU
-
CPU 是计算机系统的核心
-
CPU从一加电开始,从某设定好的内存地址开始,取指令,执行指令,并周而复始地运行
-
取指令的过程即从某寄存器(比如,程序计数器)中获取一个内存地址,从这个内存地址中读入指令,执行机器指令,不断重复
-
CPU运行期间会有分支和调用指令来修改程序计数器,实现地址跳转,否则程序计数器就自动加1,让CPU从下一个内存地址单元取指令,并继续执行
-
由于CPU执行速度很快(x86 CPU可达到2 GHZ以上的时钟频率,RISC-V CPU可达到1.5 GHZ的时钟频率),如果当前可以运行的程序太少,则会出现CPU无事可做的情况,导致计算机系统效率太低
-
操作系统除了能管理硬件外,还能管理应用程序,让它们能够按一定的顺序和优先级来依次使用CPU,充分发挥CPU的效能
-
如果管理多个程序的运行,需要考虑如何分配CPU资源的问题,如何避免程序执行期间发生“冲突”的问题等,这是操作系统需要完成的重要功能之一
Memory
![内存层次图](https://i-blog.csdnimg.cn/blog_migrate/a5982b097c6e9abfac47239804346834.png)
-
计算机中有多种多层次的存放数据和指令代码的硬件存储单元,比如在CPU内的寄存器(register)、高速缓存(cache)、内存(memory)、硬盘、磁带等
- 寄存器位于CPU内部,其访问速度最快但成本昂贵
- 对于传统的 CISC(复杂指令集计算机,如Intel 80386处理器)中一般只有几个到十个左右的通用寄存器,而对于RISC(精简指令集计算机,如RISC-V),则可能有几十个以上通用寄存器
- 高速缓存(cache) 一般也在CPU内部,cache是内存和寄存器在速度和大小上的折衷,比寄存器慢2~10倍,容量也有限
- 量级大约几百KB到几十MB不等
- 内存位于 CPU 外,比寄存器慢10倍以上,但容量大
- 目前一般以几百兆B到几百GB不等
- 硬盘容量更大,但一般比寄存器要慢1000倍以上,不过掉电后其存储的数据不会丢失
- 寄存器位于CPU内部,其访问速度最快但成本昂贵
-
寄存器、cache、内存、硬盘在读写速度和容量上的巨大差异,所以需要操作系统来协调数据的访问,尽量主动协助应用软件(这样可以达到让多个运行的应用程序“感觉”到它可用使用很大的空间,也可有很快的访问速度)
- 把最近访问的数据放到寄存器或cache中(实际上操作系统不能直接控制cache的读写)
- 把经常访问的数据放在内存中
- 把不常用的数据放到硬盘上
-
让在运行中的每个程序都能够得到“足够大”的内存空间,且程序间相互不能破坏对方的内存“领地”,且**建立他们之间的“数据共享”通道,**这是操作系统需要完成的重要功能之一。
I/O
-
CPU处理的数据需要有来源和输出,这里的来源和输出就是各种外设
- 键盘、鼠标、显示器、声卡、GPU、U盘、硬盘、SSD存储、打印机、网卡、摄像头等
-
操作系统给应用程序提供了简单的访问接口
- 应用程序如果直接访问外设,会有代码实现复杂,可移植性差,无法有效并发等问题
- 应用程序不需要了解硬件细节
-
操作系统通过 CPU 对数据进行加工:读外设数据和写外设数据
-
一般而言,IO外设把它的访问接口映射为一块内存区域,操作系统通过来用通常的内存读写指令来管理设备
-
或者CPU提供了特定的IO操作指令,操作系统通过这些特定的指令来完成对IO外设的访问
-
操作系统可以通过轮循、中断、DMA等访问方式来高效地管理外设
RISC-V 硬件架构
- 通用 CPU 一般能够在硬件上支持内存空间的隔离,使得多个程序在各自独立的内存空间中并发执行
- 即支持用户特权级和内核特权级
- 应用运行于用户特权级,不能执行内核特权级指令,且不能破坏系统内核的数据和操作系统执行的过程
- 操作系统内核运行于内核特权级,可以访问特权级指令,并管理和控制应用程序,硬件外设
- RISC-V 是发源于 Berkeley 的开源 instruction set architecture(ISA)
Modular ISA
RISC-V ISA 是模块化的,由一个基本指令集和一些扩展指令集组成
- Base integer ISAs
- RV32I
- RV64I
- RV128I
- Standard extensions
- M
- A
- F
- D
- G
1.6 了解操作性系统
1.6.1 操作系统的历史
- 操作系统主要完成对硬件控制和对应用程序的服务所必需的功能,操作系统的历史与计算机发展的历史密不可分
- 操作系统的内涵和功能随着历史的发展也在一直变化,改进中
三叶虫时代
- Operator:启动,板开关,装卡片/纸带等
- punch card:记录有程序和数据的卡片
- Monitor:监控系统
- 辅助完成输入、输出、加载、运行程序等工作
- 是操作系统的起源
恐龙时代
- 早期的操作系统,针对各自硬件的专用操作系统,大部分用汇编语言编写
- 1964年,IBM 开发了面向 System/360 系列机器的统一可兼容的操作系统—— OS/360
- OS/360 是批处理操作系统
- 一批作业以脱机方式输入到磁带上,并使这批作业能一个接着一个的连续处理:
- 将磁带上的一个作业装入内存
- 把运行控制权交给作业
- 当该作业处理完成后,把控制权交还给操作系统
- 重复1-3的步骤
- 批处理操作性系统分为单道批处理系统和多道批处理系统
- 单道批处理系统:只能管理内存中的一个(道)作业,
- 无法充分利用计算机系统中的所有资源,致使系统整体性能较差
- 多道批处理系统:管理内存中的多个(道)作业
- 比较充分的利用计算机系统中的所有资源,提升系统整体性能
- 人机交互性差,对于修改和调试程序很不方便
- 单道批处理系统:只能管理内存中的一个(道)作业,
爬行动物时代
- 20世纪60年代末,分时操作系统:提高人机交互方式
- 分时:多个用户和多个程序以很小的时间间隔来共享使用同一台计算机的 CPU 和其他硬件/软件资源
- 1964年,MULTICS(MULTIplexed Information and Computing System)操作系统
- 一套安装在大型主机上多人多任务的操作系统
- 项目工作进度过慢
- 1969年,AT&T 的Bell实验室,从MULTICS 研发中撤出,实验室中的两位软件工程师 Thompson 和 Ritchie 借鉴了MULTICS 中的重要理念,以 C 语言为基础,发展出 UNIX 操作系统
- 成为开发小型机操作系统的起点,是分时操作系统的典范
哺乳动物时代
- 20世纪70年代,微型处理器的发展使计算机的应用普及至中小企及个人爱好者
- 推动了个人计算机(Personal Computer)的发展
- 20世纪80年代,微软公司为个人计算机开发 DOS /Windows 操作系统
- 简单易用
- 基于 Windows 操作系统的 GUI 界面
智人时代
- 21 世纪以来,在服务器领域和个人终端的应用与需求大增
- iOS 和 Android 操作系统是 21 世纪个人终端操作系统的代表
- Android 2007 年 11 月,推出的基于Linux Kernel的开源手机操作系统
- Android 操作系统是一个包括 Linux 操作系统内核、基于 Java 的中间件、用户界面和关键应用软件的移动设备软件栈集合
- Linux 在巨型机到数据中心服务器操作系统中占据了统治地位
- Linux 操作系统内核——广泛用在服务器领域和个人终端中的操作系统内核
神人时代
- 当前,大数据、人工智能、机器学习、高速网络、AR/VR对操作系统等系统软件带来新挑战
1.6.2 操作系统的定义与目标
操作系统的定义
更准确的定义
- 计算机系统结构中的一个系统软件
- 职能:
- 对 计算机硬件 :有效地组织和管理计算机系统中的硬件资源(处理器、内存、硬盘、显示器、键盘、鼠标等各种外设)
- 对 应用程序或用户:提供简洁的服务功能接口,屏蔽硬件管理带来的差异性和复杂性,使得应用程序和用户能够灵活、方便、有效的使用计算机
- 操作系统起到资源管理器(source management)的作用
操作系统的目标
- 建立抽象,使得上层软件和用户更方便使用
- 管理软硬件资源,确保计算机系统更安全可靠、高性能
- 其他需求:节能、易用、可移植、实时等
1.6.3 操作系统的接口
- 操作系统内核是一个需要提供各种服务的系统软件,其服务对象使应用程序,而用户是通过应用程序的服务间接获得操作系统的服务
- 操作系统内核一般隐藏在用户看不到的地方
- 应用程序需要访问操作系统,获得操作系统的服务,需要通过操作系统的接口实现
- 应用程序不能直接读写操作系统内部函数的地址空间
- 安全可靠的接口:系统调用接口(System Call Interface)
- 应用程序可以通过系统调用接口请求获得操作系统的服务
- 不能直接调用操作系统的函数和全局变量
- 操作系统提供完服务后,返回应用程序继续执行
-
- 以 ucore OS 为例
- 进程管理:
- fork():复制创建
- exit():退出
- exec():执行
- 同步互斥的并发控制:
- semaphore:信号量
- monitor:管程
- condition variable:条件变量
- 进程间通信:
- pipe:管道
- signal:信号
- event:事件
- mailbox:邮箱
- shared mem:共享内存
- 文件 I/O 操作:
- read:读
- write:写
- open:打开
- close:关闭
- 外设 I/O 操作:
- 接口直接采用了文件 I/O操作的系统调用接口
- 说明文件是外设的一种抽象
- 接口使得应用程序不用考虑底层的细节,可在操作系统的服务支持和管理下简洁的完成其应用功能
1.6.4 操作系统抽象
在操作系统的发展过程中,计算机科学家提出了四个抽象概念
其他基本概念基于此
中断(Interrupt)
- 中断是处理器在执行过程中的突变,用来响应处理器状态中的特殊变化
- 比如当应用程序正在执行时,产生了时钟外设中断,导致操作系统打断当前应用程序的执行,转而去处理时钟外设中断,处理完毕后,再回到应用程序被打断的地方继续执行
- 三类中断:
- 外设中断(Device Interrupt):
- 由外部设备引起的外部 I/O 事件,如时钟中断、控制台中断等
- 异步产生,与处理器的执行无关
- 陷阱中断(Trap Interrupt):
- 在程序中使用请求操作系统服务的系统调用而引发的有意事件
- 故障终端(Fault Interrupt,exception):
- 在处理器执行指令期间检测到不正常的或非法的内部事件(除零错、地址访问越界)
- 外设中断(Device Interrupt):
进程(Process)
- 一个正在运行的程序
- 处理器是计算机系统中的硬件资源
- 为了提高处理器的利用率,操作系统采用了多道程序技术
- 为了刻画多道程序并发执行的过程,引入进程的概念
- 从操作系统原理上看,一个进程是一个具有一定独立功能的程序在一个数据集合上的一次动态执行过程
- 操作系统中的进程管理需要协调多道程序之间的关系,解决对处理器分配调度策略、分配实施和回收等问题,从而使得处理器得到最大利用
虚存(Virtual Memory)
- 虚存就是操作系统通过利用处理器中的 内存管理单元 给应用程序和用户提供的一个(超过计算机内存条容量)、一致的(连续的地址空间)、私有的(其他应用程序无法破坏)的存储空间
- 需要操作系统将内存和硬盘结合起来管理,为应用程序和用户提供一个容量比实际内存大得多的虚拟存储器
- 需要操作系统为应用程序分配内存空间
- 使得内存中的程序和代码彼此隔离
- 虚存管理与处理器的 MMU 密切相关
文件(File)
- 文件就是存放在持久存储介质(硬盘、光盘、U 盘)上,方便应用程序和用户读写的数据
- 当处理器需要访问文件中的数据时,可以通过操作系统把它们转入内存
- 放在硬盘上的程序也是一种文件
- 文件管理的任务:有效的支持文件的存储、检索和修改等操作
1.6.5 操作系统的特征
- 操作系统具有五个方面的特征:
- 虚拟性 Virtualization
- 从操作系统对内存、CPU的抽象和处理
- 并发性 concurrency
- 操作系统支持多个应用程序同时运行
- 异步性
- 从操作系统调度,中断处理对应用程序执行造成的影响
- 共享性
- 操作系统支持多个应用程序同时运行
- 持久性 persistency
- 从操作系统中的文件系统支持把数据方便的从磁盘等存储介质上存入和取出来
- 虚拟性 Virtualization
虚拟性
内存虚拟化
-
写应用程序的时候,不用考虑程序的起始内存地址放到实际内存的何处
-
操作系统建立了一个地址固定,空间巨大的虚拟内存给应用程序来运行,这是空间虚拟化
-
程序中的每个符号在运行时对应到具体的内存地址
-
虚拟地址
-
编译器设定一个固定地址为起始地址,编译器产生的地址就是虚拟地址
- 开始存放代码、数据
-
所有变量(全局变量)和函数的符号都在这个起始地址之后的某个固定偏移位置
- 假定程序每次运行都是位于一个不会变化的起始地址
-
全局变量的地址在程序编译链接后确定不变,局部变量放在堆栈中,会随着堆栈的大小的动态变化而变化
-
这里,编译器和链接器图省事,找了一个适合它们的解决办法。
当程序要运行的时候,这个符号到机器物理内存的映射必须要解决了,这自然就推到了操作系统身上。
操作系统会把编译器和链接器生成的执行代码和数据放到物理内存中的空闲区域中,并建立虚拟地址到物理地址的映射关系。
由于物理内存中的空闲区域是动态变化的,这也导致虚拟地址到物理地址的映射关系是动态变化的,需要操作系统来维护好可变的映射关系,确保编译器“固定起始地址”的假设成立。
只有操作系统维护好了这个映射关系,才能让程序员只需写一些易于人理解的字符串符号来代表一个内存空间地址,且编译器只需确定一个固定地址作为程序的起始地址就可以生成一个不用考虑将来这个程序要在哪里运行的问题,从而实现了空间虚拟化。
-
-
应用程序在运行时不应考虑当前物理内存是否够用
- 空间大小虚拟化:操作系统把物理内存中最近未使用的空间换出到硬盘上缓存起来
CPU 虚拟化
-
不同的应用程序可以在内存中并发执行,相同的应用程序也可有多个拷贝在内存中并发运行
-
时间虚拟化:每个程序都以为自己完全独占了 CPU 运行
-
其实是操作系统把时间分成小段,每个应用程序占用其中一小段时间片运行,用完一个时间片之后,操作系统会切换到另一个应用程序运行
-
时间片很短,操作系统的切换开销也很小,感觉到多个程序各自在独立“并行”执行,实现了时间虚拟化
-
并行(Parallel):两个或多个事件在同一时刻发生
并发(Concurrency):两个或多个事件在同一时间间隔内发生
对于单 CPU :各个“同时”运行的程序其实时串行分时复用一个CPU,任一个时刻点上只有一个程序在 CPU 上运行
并发性
- 操作系统为了让 CPU 忙起来并充分利用各种资源,就给很多任务让他去完成
- 分时完成,由操作系统完成运行时的切换
- 并发性虽然能有效改善系统资源的利用率,但也带来了对共享资源的争夺——同步互斥问题
异步性
- 异步是指由于操作系统的调度和中断等,会不时地暂停或打断当前正在运行的程序
- 使得程序的整个运行过程走走停停
- 应用程序的执行完成时间不可预测
- 但,若输入一致,结果是一定的
共享性
- 多个应用程序并发执行时,宏观上体现出他们可以同时访问同一个资源,即该资源可被共享
- 微观上,操作系统需要在硬件等的支持下确保应用程序互斥或交替访问这个共享资源
持久性
-
操作系统提供了文件系统来从可持久保存的存储介质(硬盘,SSD等)中取数据和代码到内存中,也可以把内存中的数据和代码写回到硬盘中
-
硬盘具有持久性,抽象为文件系统的形式呈现应用程序
-
文件系统也可看成操作系统对硬盘的虚拟化
这种持久性的特征进一步带来了共享属性,即在文件系统中的文件可以被多个运行的程序所访问,从而给应用程序之间实现数据共享提供了方便。
即使掉电,磁盘上的数据还不会丢失,可以在下一次机器加电后提供给运行的程序使用。持久性对操作系统的执行效率提出了挑战,如何让数据在高速的内存和慢速的硬盘间高效流动是需要操作系统考虑的问题。