0 00:00:00,000 --> 00:00:06,400 1 00:00:06,440 --> 00:00:09,680 为了能够覆盖到刚才说到那些知识点 2 00:00:09,720 --> 00:00:11,160 我们设计了一共8个实验 3 00:00:11,200 --> 00:00:15,360 可以看到从OS启动开始 OS怎么启动的 4 00:00:15,400 --> 00:00:17,240 为此能够跟外设打交道 5 00:00:17,280 --> 00:00:21,120 从一开始200行代码形成小code 6 00:00:21,160 --> 00:00:25,480 到最后Lab8文件系统 大约一共加起来 7 00:00:25,520 --> 00:00:28,120 整个过程大概形成了大约一万行代码 8 00:00:28,160 --> 00:00:31,680 那么整个这些实验内容基本上覆盖了 9 00:00:31,720 --> 00:00:36,520 我们上操作系统原理重要一些基本概念 10 00:00:36,560 --> 00:00:40,240 整个过程我给大家做个介绍 大家知道这个砖头 11 00:00:40,280 --> 00:00:44,440 怎么一步一步搭成最后一个建筑的 12 00:00:44,480 --> 00:00:47,000 一开始我们看到我们这里有一个硬件层 13 00:00:47,040 --> 00:00:50,600 这个硬件层其实是模拟了整个X86大致的架构 14 00:00:50,640 --> 00:00:52,320 包含各种各样的外设 15 00:00:52,360 --> 00:00:55,120 以及我们最主要的CPU内存 16 00:00:55,160 --> 00:00:57,760 这是我们硬件环境 17 00:00:57,800 --> 00:01:00,200 为了能够让我们超系统能够管理这些硬件 18 00:01:00,240 --> 00:01:01,440 我们首先设计一个Bootloader 19 00:01:01,480 --> 00:01:05,560 能够说它的目标干什么 它的目标就是加载OS 20 00:01:05,600 --> 00:01:07,040 我们用Bootloader加载OS 21 00:01:07,080 --> 00:01:10,320 让OS在我们类型中运行 这是第一步 22 00:01:10,360 --> 00:01:13,920 然后OS要运行之后它首先知道 23 00:01:13,960 --> 00:01:17,680 它所处的环境是什么 它需要去管理CPU 24 00:01:17,720 --> 00:01:21,600 第二管理内存 第三管理外设 25 00:01:21,640 --> 00:01:28,240 比如说时钟 键盘 串口 并口等等 26 00:01:28,280 --> 00:01:30,960 只有把这些都能够有效管理起来之后 27 00:01:31,000 --> 00:01:33,760 才能够控制这个硬件 28 00:01:33,800 --> 00:01:35,880 这是我们说前面几个实验 29 00:01:35,920 --> 00:01:39,360 首先从Lab1我们说Bootloader中断处理 30 00:01:39,400 --> 00:01:43,400 Lab2物理内存管理 Lab3虚拟内存管理 31 00:01:43,440 --> 00:01:46,120 都是跟内存打交道 那么Lab4和Lab5 32 00:01:46,160 --> 00:01:49,600 都是说内核线程和用户进程 33 00:01:49,640 --> 00:01:51,840 那跟谁打交道跟CPU打交道 34 00:01:51,880 --> 00:01:54,520 然后Lab6实际上我们说是一个调度 35 00:01:54,560 --> 00:01:56,560 它也是为了能更有效的利用CPU 36 00:01:56,600 --> 00:02:01,480 Lab7是完成同步互斥 这里面Lab7在这块 37 00:02:01,520 --> 00:02:04,560 有了Lab7同步互斥机制之后 我们就可以实现什么 38 00:02:04,600 --> 00:02:08,200 实现解决一些问题 可以实现进程之间的通讯 39 00:02:08,240 --> 00:02:11,520 就是我们运行程序之间可以有效进行通讯 40 00:02:11,560 --> 00:02:16,280 很多可以用来协调的一些工作都可以用这个 41 00:02:16,320 --> 00:02:18,280 有了同步互斥之后就可以完成了 42 00:02:18,320 --> 00:02:21,800 那么在进程和内存管理之上 43 00:02:21,840 --> 00:02:25,240 我们就可以给我们应用程序提供相应的支持 44 00:02:25,280 --> 00:02:26,640 那我们应用程序可以跑起来 45 00:02:26,680 --> 00:02:28,480 来可以完成它们特定的功能 46 00:02:28,520 --> 00:02:31,320 有了进程管理 内存管理 47 00:02:31,360 --> 00:02:33,920 我们就可以有用户态的各种各样的应用 48 00:02:33,960 --> 00:02:36,400 如果说你这些应用的数据 49 00:02:36,440 --> 00:02:39,560 或者你这个代码需要放在永久存储设备上面 50 00:02:39,600 --> 00:02:42,040 比如说硬盘或者磁盘那需要什么呢 51 00:02:42,080 --> 00:02:44,440 需要我们文件系统来完成相应的 52 00:02:44,480 --> 00:02:49,680 把内存中的数据存到我们这个硬盘上的功能 53 00:02:49,720 --> 00:02:54,240 它可以用很简单方式提供很简单的接口来使用 54 00:02:54,280 --> 00:02:56,800 那么最后也许还有同学说可以做扩展 55 00:02:56,840 --> 00:02:59,120 比如你可以完成网络协议栈等等 56 00:02:59,160 --> 00:03:01,840 这都是形成了我们这个完整OS 57 00:03:01,880 --> 00:03:03,920 可以看出来其实包含了三部分 58 00:03:03,960 --> 00:03:05,720 前面说一部分是硬件 59 00:03:05,760 --> 00:03:09,160 第二部分是运行在内核态的kernel 60 00:03:09,200 --> 00:03:11,320 我们说OS kernel软件 61 00:03:11,360 --> 00:03:13,520 然后有了这个OS kernel之后 62 00:03:13,560 --> 00:03:15,400 我们可以设计各种各样的应用 63 00:03:15,440 --> 00:03:19,320 来使用我们内核提供各种各样的服务 64 00:03:19,360 --> 00:03:20,640 那我们重点实现的部分 65 00:03:20,680 --> 00:03:23,120 在内核态这些各个大的模块 66 00:03:23,160 --> 00:03:24,880 涉及到我们提到的八个实验 67 00:03:24,920 --> 00:03:26,240 就是基本上覆盖了这么多内容 68 00:03:26,280 --> 00:03:30,400 简单我们会把这个八个实验做一个逐一的介绍 69 00:03:30,440 --> 00:03:33,280 从Lab1开始 Lab1讲的是Bootloader 70 00:03:33,320 --> 00:03:37,520 中断还有设备驱动 这三部分内容 71 00:03:37,560 --> 00:03:39,800 那这三部分内容实际上就是说 72 00:03:39,840 --> 00:03:41,560 首先你要理解操作系统怎么启起来的 73 00:03:41,600 --> 00:03:44,000 其实它通过Bootloader启起来的 74 00:03:44,040 --> 00:03:47,880 同时当操作系统启起来之后 它怎么管理硬件 75 00:03:47,920 --> 00:03:50,480 它需要通过中断机制 76 00:03:50,520 --> 00:03:54,240 还有通过设备驱动程序来完成对硬件的管理 77 00:03:54,280 --> 00:03:56,360 比如各种各样的外设的管理 78 00:03:56,400 --> 00:03:59,080 这是说我们在Lab1的时候会去碰到 79 00:03:59,120 --> 00:04:02,520 需要大家掌握和理解的知识 80 00:04:02,560 --> 00:04:05,520 也需要大家通过对这些知识的了解 81 00:04:05,560 --> 00:04:09,320 来进一步去完成对一些操作系统 82 00:04:09,360 --> 00:04:13,440 运行时候机制的掌握 比如说堆栈处理 83 00:04:13,480 --> 00:04:16,120 比如说它怎么去控制一些外设的 84 00:04:16,160 --> 00:04:18,240 当然具体的外设的控制 85 00:04:18,280 --> 00:04:20,240 我们这里面可以不用看那么细 86 00:04:20,280 --> 00:04:21,520 可以看的简单一点 87 00:04:21,560 --> 00:04:22,880 只要知道它大致的过程就行了 88 00:04:22,920 --> 00:04:25,720 不用去了解它那些细节 89 00:04:25,760 --> 00:04:27,400 这个我们可以不用去掌握 90 00:04:27,440 --> 00:04:29,120 主要知道它大致处理过程 91 00:04:29,160 --> 00:04:32,120 特别是它怎么去建立好这个中断机制 92 00:04:32,160 --> 00:04:34,040 这点很重要 有了中断之后 93 00:04:34,080 --> 00:04:36,880 我们就可以完成后续很多很重要功能 94 00:04:36,920 --> 00:04:39,960 这个代码其实可以看到 最开始那个代码 95 00:04:40,000 --> 00:04:41,720 比如我们加载一个OS最简单代码 96 00:04:41,760 --> 00:04:45,640 其实只有很小一些代码量 可能不到一千 97 00:04:45,680 --> 00:04:49,320 几百行代码就可以完成打印一个字符串OS 98 00:04:49,360 --> 00:04:53,080 当然它没什么功能 但是它确实就可以看到 99 00:04:53,120 --> 00:04:58,200 我们 bootloader怎么把OS加载起来了 100 00:04:58,240 --> 00:05:02,720 当OS被bootloader加载到内存中运行之后 101 00:05:02,760 --> 00:05:04,680 那OS很重要一个目标 102 00:05:04,720 --> 00:05:06,680 肯定不是仅仅是打印一个字符串 103 00:05:06,720 --> 00:05:09,680 它需要更好去管理整个计算机系统 104 00:05:09,720 --> 00:05:11,240 那第一步管理是什么呢 105 00:05:11,280 --> 00:05:14,200 管理我们内存 物理内存管理 106 00:05:14,240 --> 00:05:16,160 我们知道一个计算机系统 107 00:05:16,200 --> 00:05:17,920 它有大片的物理内存 108 00:05:17,960 --> 00:05:20,200 这个物理内存哪些可以用 哪些不能用 109 00:05:20,240 --> 00:05:22,480 实际上是由我们操作系统管理起来的 110 00:05:22,520 --> 00:05:25,240 首先我们需要去了解 既然我们说 111 00:05:25,280 --> 00:05:29,200 我们这个针对硬件是X86 32位的CPU 112 00:05:29,240 --> 00:05:32,560 那我们就需要理解X86架构下面 113 00:05:32,600 --> 00:05:35,960 它内存管理的模式 它有分段分页机制 114 00:05:36,000 --> 00:05:40,880 我们知道通过理解内存地址的表示来 115 00:05:40,920 --> 00:05:45,760 完成基于分段和分页的方式 116 00:05:45,800 --> 00:05:49,880 能够实现页表 实现对连续物理空间的管理 117 00:05:49,920 --> 00:05:52,440 这实际上是我们Lab2重点考虑内容 118 00:05:52,480 --> 00:05:54,480 我们可以看到在X86架构下 119 00:05:54,520 --> 00:05:56,760 整个内存一个分布图 120 00:05:56,800 --> 00:05:59,000 很重要的一点就是操作系代码段 数据段 121 00:05:59,040 --> 00:06:00,960 ucore代码段 数据段放在什么地方 122 00:06:01,000 --> 00:06:03,800 以及它管理空闲空间在什么地方 123 00:06:03,840 --> 00:06:07,960 这些地方都会被我们ucore操作系统管理起来 124 00:06:08,000 --> 00:06:12,520 来实现一个对内存动态分配和释放这么一个机制 125 00:06:12,560 --> 00:06:15,560 这是我们Lab2里要掌握的几点 126 00:06:15,600 --> 00:06:18,720 对Lab3而言我们还需要知道 127 00:06:18,760 --> 00:06:21,840 在有限物理空间里面 怎么实现一种更大 128 00:06:21,880 --> 00:06:25,240 超过有限物理空间的一个虚拟内存空间 129 00:06:25,280 --> 00:06:27,840 映射和管理机制 就是虚存管理 130 00:06:27,880 --> 00:06:30,720 这是Lab3的功能 那么在Lab3里面 131 00:06:30,760 --> 00:06:34,320 它需要借助我们前面之前讲到中断机制 132 00:06:34,360 --> 00:06:36,400 就是缺页故障处理 133 00:06:36,440 --> 00:06:40,760 还有借助于我们原理课讲到页面置换算法 134 00:06:40,800 --> 00:06:43,480 这两个结合在一起来实现给我们应用程序 135 00:06:43,520 --> 00:06:47,320 提供一个大的虚拟空间 即使我们物理空间很小 136 00:06:47,360 --> 00:06:49,120 比如说只有1M 但是我们虚拟空间 137 00:06:49,160 --> 00:06:52,040 给它虚拟出来一个4M 8M等等 138 00:06:52,080 --> 00:06:53,400 从而可以使得 我们应用程序 139 00:06:53,440 --> 00:06:56,920 可以更好在我们操作系统管理之下去运行 140 00:06:56,960 --> 00:06:59,280 这是我们Lab3需要去掌握的知识 141 00:06:59,320 --> 00:07:00,600 这里面需要了解什么呢 142 00:07:00,640 --> 00:07:02,520 需要知道换页这个机制 143 00:07:02,560 --> 00:07:04,280 就是我们把这个页换出去 144 00:07:04,320 --> 00:07:06,200 比如说这里边一个程序 145 00:07:06,240 --> 00:07:09,280 它怎么能够从内存换到我们硬盘 146 00:07:09,320 --> 00:07:11,880 以及从硬盘再换回到内存里面去 147 00:07:11,920 --> 00:07:13,120 这个机制怎么实现的 148 00:07:13,160 --> 00:07:16,520 这实际上需要我们软硬件协同在一起来完成 149 00:07:16,560 --> 00:07:18,000 并不是说只是靠操作系统来完成 150 00:07:18,040 --> 00:07:21,320 需要我们的CPU和我们外设 151 00:07:21,360 --> 00:07:23,480 有一定支持才能完成 152 00:07:23,520 --> 00:07:26,760 第二我们需要了解页面调换算法 153 00:07:26,800 --> 00:07:30,680 以及对应页出错的之后异常处理机制 154 00:07:30,720 --> 00:07:35,120 这个实际上是我们操作系统来完成的 155 00:07:35,160 --> 00:07:37,840 当产生这个缺页之后我们应该怎么做 156 00:07:37,880 --> 00:07:40,880 第二个就是选择哪页换出去和换入 157 00:07:40,920 --> 00:07:43,720 这个也是一样 就是我们操作系统来管理 158 00:07:43,760 --> 00:07:47,600 有相应的算法 这一套实际上实现了 159 00:07:47,640 --> 00:07:50,280 我们整个Lab3大致的一个内容 160 00:07:50,320 --> 00:07:53,280 就是关于虚拟内存管理这块 161 00:07:53,320 --> 00:07:55,480 Lab2和Lab3实现了什么 162 00:07:55,520 --> 00:07:58,280 实现了我们对内存的一个管理 163 00:07:58,320 --> 00:08:00,480 无论是虚拟还是物理的 164 00:08:00,520 --> 00:08:02,160 操作系统一个很重要部分 165 00:08:02,200 --> 00:08:03,720 就算基本上告一段落 166 00:08:03,760 --> 00:08:05,200 接下来是对什么管理呢 是对CPU的管理 167 00:08:05,240 --> 00:08:06,680 CPU的管理实际上什么呢 168 00:08:06,720 --> 00:08:14,360 我们需要让不同的程序来分时占用CPU去执行 169 00:08:14,400 --> 00:08:16,840 这实际上是我们线程管理 170 00:08:16,880 --> 00:08:18,840 和进程管理很重要一个思路 171 00:08:18,880 --> 00:08:21,080 为了实现线程管理 172 00:08:21,120 --> 00:08:23,720 我们首先是在内核里面实现一个线程管理 173 00:08:23,760 --> 00:08:26,160 这个实验相对来说比我们后面讲到 174 00:08:26,200 --> 00:08:29,640 在Lab5中的用户态进程管理要简单一些 175 00:08:29,680 --> 00:08:33,120 但是它他基本的一些机制是类似的 176 00:08:33,160 --> 00:08:35,760 我们通过在内核实现线程管理 177 00:08:35,800 --> 00:08:39,280 可以使得我们利用CPU来高效完成各种工作 178 00:08:39,320 --> 00:08:41,880 你要创建它 你必须要干什么呢 179 00:08:41,920 --> 00:08:46,280 需要建立关于线程的内部一些关键数据的描述 180 00:08:46,320 --> 00:08:49,120 你可以看到在这里面它有堆有栈 181 00:08:49,160 --> 00:08:51,120 有它的代码有它的数据 182 00:08:51,160 --> 00:08:52,320 那怎么去表示它 183 00:08:52,360 --> 00:08:56,000 这需要我们在内核线程中有相应一些关键信息 184 00:08:56,040 --> 00:08:59,640 第二个如果CPU只有一个 185 00:08:59,680 --> 00:09:02,160 这个时候每某一个时刻有一个线程运行 186 00:09:02,200 --> 00:09:04,800 下一时刻可能是另一个线程运行了 187 00:09:04,840 --> 00:09:08,840 你怎么完成切换 这也是需要去理解的 188 00:09:08,880 --> 00:09:12,080 你需要有效地管理它 完成切换 189 00:09:12,120 --> 00:09:15,160 这点是我们在内核线程管理上 190 00:09:15,200 --> 00:09:16,560 重点去考虑的问题 191 00:09:16,600 --> 00:09:18,480 当你能够完成这个切换之后 192 00:09:18,520 --> 00:09:22,520 那其实应该说关于大家不同的进程 193 00:09:22,560 --> 00:09:26,080 或者线程来分时占用CPU基本机制 194 00:09:26,120 --> 00:09:28,920 就已经建立好了 那接下来问题是什么呢 195 00:09:28,960 --> 00:09:31,240 我们说我们需要应用程序 196 00:09:31,280 --> 00:09:33,480 也能够完成各自特定功能 197 00:09:33,520 --> 00:09:34,760 而这些应用程序呢 198 00:09:34,800 --> 00:09:36,640 由于它的可靠性不够高 也可能出错 199 00:09:36,680 --> 00:09:39,400 我们希望把应用程序放在用户态 200 00:09:39,440 --> 00:09:41,520 它出错了没关系 不影响内核 201 00:09:41,560 --> 00:09:44,960 不影响我们处于内核态的这个操作系统 202 00:09:45,000 --> 00:09:47,600 为了能够让应用程序运行在用户态 203 00:09:47,640 --> 00:09:49,760 我们需要设计一个所谓用户进程 204 00:09:49,800 --> 00:09:54,320 我们怎么能够让应用程序运用在用户态 205 00:09:54,360 --> 00:09:56,760 为此我们需要创建所谓的用户进程 206 00:09:56,800 --> 00:09:59,480 这里面设计到进程的创建 执行切换 207 00:09:59,520 --> 00:10:01,560 等等一系列动态管理过程 208 00:10:01,600 --> 00:10:03,560 这个过程我们Lab4是很相近 209 00:10:03,600 --> 00:10:05,440 但是又有不同 为什么呢 210 00:10:05,480 --> 00:10:09,360 这里面其实可以体现出来你需要了解 211 00:10:09,400 --> 00:10:10,800 建立一个用户级的进程 212 00:10:10,840 --> 00:10:13,120 它需要的一些关键信息 213 00:10:13,160 --> 00:10:15,160 这些信息运行在这个空间 214 00:10:15,200 --> 00:10:16,920 而不是在内核空间 215 00:10:16,960 --> 00:10:18,880 那么运行在所谓用户空间的话 216 00:10:18,920 --> 00:10:21,360 很明显它不能够破坏我们用户空间 217 00:10:21,400 --> 00:10:22,920 怎么能保证这种机制 218 00:10:22,960 --> 00:10:26,400 我们实际上去分析进程和内存这种关系 219 00:10:26,440 --> 00:10:30,120 才能知道它们有一定区别 这是一个 220 00:10:30,160 --> 00:10:34,240 第二个你还要知道运行在用户空间应用程序 221 00:10:34,280 --> 00:10:37,840 无法直接访问我们操作系统内核里面的函数 222 00:10:37,880 --> 00:10:39,120 它不得不通过另外一种机制 223 00:10:39,160 --> 00:10:41,680 我们称之为系统调用 224 00:10:41,720 --> 00:10:44,640 才能够得到操作系统提供的服务 225 00:10:44,680 --> 00:10:48,960 这点大家也需要通过Lab5中 226 00:10:49,000 --> 00:10:51,640 来实现系统调用才能知道这回事 227 00:10:51,680 --> 00:10:53,000 这也是我们操作系统 228 00:10:53,040 --> 00:10:55,720 在Lab5中需要去完成一些工作 229 00:10:55,760 --> 00:10:59,440 你可以看到系统调用和我们中断相关 230 00:10:59,480 --> 00:11:03,520 我们进程创建和我们内存管理相关 231 00:11:03,560 --> 00:11:07,040 它的调度和我们Lab4的线程切换相关 232 00:11:07,080 --> 00:11:09,080 就是你要切换到另一个线程上去执行 233 00:11:09,120 --> 00:11:11,040 其实你看到Lab5其实建立在 234 00:11:11,080 --> 00:11:16,480 我们前面的Lab1到Lab4基础之上才有Lab5 235 00:11:16,520 --> 00:11:17,520 那么有Lab5之后 236 00:11:17,560 --> 00:11:21,280 我们最终基本就可以完成一个很简单的OS 237 00:11:21,320 --> 00:11:24,800 它有能够支持用户空间进程来运行 238 00:11:24,840 --> 00:11:26,640 它建立一个基本的功能 239 00:11:26,680 --> 00:11:30,360 它有了内存管理 CPU管理 240 00:11:30,400 --> 00:11:33,360 接下来我们看Lab6 241 00:11:33,400 --> 00:11:35,960 那既然说我可以让不同的进程 242 00:11:36,000 --> 00:11:39,240 或者线程来分时占用CPU执行 243 00:11:39,280 --> 00:11:43,040 到底那个时刻需要那个进程占用CPU执行 244 00:11:43,080 --> 00:11:44,840 这点其实是有一个策略在里面的 245 00:11:44,880 --> 00:11:49,280 这实际就涉及到什么呢 进程调度 246 00:11:49,320 --> 00:11:51,880 我们需要去了解操作系统调度过程 247 00:11:51,920 --> 00:11:57,160 基于哪些原则来选择哪一个进程去运行 248 00:11:57,200 --> 00:12:02,160 这点你会涉及到怎么去设计一个调度器的框架 249 00:12:02,200 --> 00:12:05,520 怎么实现不同调度算法 这里面的调度算法 250 00:12:05,560 --> 00:12:09,040 和我们在原理课讲的调度算法也是一一对应的 251 00:12:09,080 --> 00:12:11,800 但是你会发现 原理上讲的一些知识 252 00:12:11,840 --> 00:12:14,520 如果真的在实际机器里面去实现 253 00:12:14,560 --> 00:12:16,640 比如我们在一个ucore里实现 254 00:12:16,680 --> 00:12:19,440 跑在X86这个机器里面的话 255 00:12:19,480 --> 00:12:21,360 你会发现可能还有点偏差 256 00:12:21,400 --> 00:12:25,760 为什么 这也是希望大家通过做实验 257 00:12:25,800 --> 00:12:29,560 能够知道实践和理论之间其实还是有偏差的 258 00:12:29,600 --> 00:12:31,080 并不是完全对应的 259 00:12:31,120 --> 00:12:32,480 这也希望大家做实验的时候 260 00:12:32,520 --> 00:12:36,040 能够深刻的体会到这点 261 00:12:36,080 --> 00:12:38,120 那Lab7是同步互斥 既然我们现在 262 00:12:38,160 --> 00:12:41,640 已经可以在计算机系统里面 263 00:12:41,680 --> 00:12:45,000 在操作系统管理之下可以同时跑多个进程 264 00:12:45,040 --> 00:12:49,600 但是其实这些进程之间它们也是需要去沟通的 265 00:12:49,640 --> 00:12:52,800 并不是完全隔离 相互之间没有任何打交道 266 00:12:52,840 --> 00:12:55,280 它们还是需要去说交换一个信息 267 00:12:55,320 --> 00:12:58,280 相互之间有一个谁先谁后执行 268 00:12:58,320 --> 00:13:00,520 这么一个相互关系 这里面就涉及到 269 00:13:00,560 --> 00:13:04,000 所谓同步互斥一些技术 我们需要知道 270 00:13:04,040 --> 00:13:06,600 我们操作系统要建立哪些机制 271 00:13:06,640 --> 00:13:10,480 来支持进程间的同步互斥 272 00:13:10,520 --> 00:13:13,840 为此我们需要了解比如说 273 00:13:13,880 --> 00:13:17,120 我们后面说到spinlock 就是锁机制 274 00:13:17,160 --> 00:13:20,360 semphpore信号量机制 还有condition variable 275 00:13:20,400 --> 00:13:22,760 就是调节变量机制 它是怎么实现的 276 00:13:22,800 --> 00:13:24,280 那么这些实现应该说 277 00:13:24,320 --> 00:13:26,480 和我们操作系统原理课也是一一对应的 278 00:13:26,520 --> 00:13:29,640 但是比原理课要更加贴近实际 279 00:13:29,680 --> 00:13:31,840 它和我们硬件是紧密相关的 280 00:13:31,880 --> 00:13:34,400 第二个假设有了这些实验之后 281 00:13:34,440 --> 00:13:36,520 我们怎么能够用这些同步机制 282 00:13:36,560 --> 00:13:39,520 来解决所谓同步问题 比如说我们原理课里面 283 00:13:39,560 --> 00:13:42,800 经常讲哲学家问题 哲学家吃饭 284 00:13:42,840 --> 00:13:44,040 在有限的资源情况下 285 00:13:44,080 --> 00:13:46,840 怎么确保更多哲学家能够吃上饭 286 00:13:46,880 --> 00:13:49,080 而不被饿死 这些基本问题 287 00:13:49,120 --> 00:13:53,040 其实当你在我们ucore里面实现这些机制 288 00:13:53,080 --> 00:13:56,720 就可以用完全原理和算法来实现 289 00:13:56,760 --> 00:13:58,360 这也是我们说在Lab7里面 290 00:13:58,400 --> 00:14:01,800 需要大家去体会的一些问题 291 00:14:01,840 --> 00:14:04,680 如果说你实现不对 有可能出现死锁 292 00:14:04,720 --> 00:14:06,680 有可能出现其它异常情况 293 00:14:06,720 --> 00:14:08,720 这就避免了一些问题 294 00:14:08,760 --> 00:14:15,320 通过实验相信对同步有更深入的理解 295 00:14:15,360 --> 00:14:18,200 最后一个实验文件系统 296 00:14:18,240 --> 00:14:20,560 为什么要有文件系统 很明显 297 00:14:20,600 --> 00:14:23,120 有了文件系统之后 我们写的代码 298 00:14:23,160 --> 00:14:24,960 可以永久存在一个地方 299 00:14:25,000 --> 00:14:27,160 我不用每次要敲代码进去 300 00:14:27,200 --> 00:14:29,960 我只要重新放在一个永久存储介质 301 00:14:30,000 --> 00:14:31,800 比如我们硬盘上面的一个代码 302 00:14:31,840 --> 00:14:34,160 加载到内存中去执行就可以了 303 00:14:34,200 --> 00:14:36,560 我们不需要说每次要重新敲代码 304 00:14:36,600 --> 00:14:41,280 所以这个永久存储这个介质有效管理和方便管理 305 00:14:41,320 --> 00:14:43,440 实际上我们说是操作系统 306 00:14:43,480 --> 00:14:45,720 很重要一个功能文件系统来完成的 307 00:14:45,760 --> 00:14:48,080 它可以把我们内存中的数据 308 00:14:48,120 --> 00:14:50,200 按照某种简单的方式 309 00:14:50,240 --> 00:14:53,080 我们从文件系统转换到磁盘上去 310 00:14:53,120 --> 00:14:55,520 本身对磁盘的处理实际上挺复杂的 311 00:14:55,560 --> 00:14:57,280 有了这个文件系统之后 312 00:14:57,320 --> 00:15:00,960 应用程序只需要通过一些简单的原语 313 00:15:01,000 --> 00:15:04,520 比如说打开文件 读文件 写文件 关闭文件 314 00:15:04,560 --> 00:15:05,920 这些基本的简单的原语 315 00:15:05,960 --> 00:15:08,720 就可以完成对数据的存储 316 00:15:08,760 --> 00:15:11,360 甚至包括我们执行代码存储也是一样的 317 00:15:11,400 --> 00:15:13,520 最后你就发现 连我们操作系统本身 318 00:15:13,560 --> 00:15:16,680 也是一个文件形式存在我们硬盘上面的 319 00:15:16,720 --> 00:15:19,160 整个文件系统完成之后 320 00:15:19,200 --> 00:15:22,560 你就可以理解它和我们内存有什么关系 321 00:15:22,600 --> 00:15:23,960 和我们进程有有什么关系 322 00:15:24,000 --> 00:15:25,680 和我们外设有什么关系 323 00:15:25,720 --> 00:15:29,160 在文件系统里面都会有涉及 324 00:15:29,200 --> 00:15:31,560 那我们最后还可以考虑一下 325 00:15:31,600 --> 00:15:34,840 这个文件系统不同组织方式以及抽样方式 326 00:15:34,880 --> 00:15:36,760 怎么样来支持不同的存储介质 327 00:15:36,800 --> 00:15:39,160 不同的设计机制 328 00:15:39,200 --> 00:15:40,480 所以说还有一些什么呢 329 00:15:40,520 --> 00:15:42,520 文件系统抽象层设计等等 330 00:15:42,560 --> 00:15:47,320 这些都是一个相对来说比较实际的 331 00:15:47,360 --> 00:15:48,440 文件系统需要考虑的问题 332 00:15:48,480 --> 00:15:49,960 有了硬件系统之后 我们最后就可以 333 00:15:50,000 --> 00:15:55,520 完成一个用户可以操作的小型的OS了 334 00:15:55,560 --> 00:15:59,520 相对来说功能比较完备了 有内存管理 335 00:15:59,560 --> 00:16:04,720 有进程管理 有同步互斥 有文件系统 336 00:16:04,760 --> 00:16:08,520 有了这些应该说我们可以在这个基础之上 337 00:16:08,560 --> 00:16:11,040 开发一些简单的小的应用程序是没有问题的 338 00:16:11,080 --> 00:16:14,880 就类似于大家写算法 上算法课上数据结构课一样 339 00:16:14,920 --> 00:16:16,160 你开发简单小应用程序 340 00:16:16,200 --> 00:16:17,760 就可以在ucore里面跑起来了 341 00:16:17,800 --> 00:16:19,480 当然也许有些同学说 342 00:16:19,520 --> 00:16:23,640 这个实验还是比较简单 不具有挑战 343 00:16:23,680 --> 00:16:27,880 我们的同学也去做了很多具有挑战性的实验 344 00:16:27,920 --> 00:16:30,400 下面列出了一些例子 大家可以看到 345 00:16:30,440 --> 00:16:34,280 比如说能够把ucore跑在64位CPU上面 346 00:16:34,320 --> 00:16:38,560 我们同学已经完成了 把ucore跑在X86 64位上面 347 00:16:38,600 --> 00:16:42,040 能不能说设计一些不同的页替换算法 348 00:16:42,080 --> 00:16:45,360 并不仅仅简单我们在实验课中提到 349 00:16:45,400 --> 00:16:47,760 页替换算法 350 00:16:47,800 --> 00:16:52,960 还更复杂一些 比如说像Linux一些页替换算法能不能实现 351 00:16:53,000 --> 00:16:56,400 也有同学去做尝试 还有支持其它CPU 352 00:16:56,440 --> 00:16:58,360 不光是X86 CPU 我们可以支持 353 00:16:58,400 --> 00:17:02,720 现在在手机平板用的很广泛armCPU 354 00:17:02,760 --> 00:17:05,760 这个有同学做过尝试 355 00:17:05,800 --> 00:17:07,720 还有支持新的文件系统 356 00:17:07,760 --> 00:17:10,680 我们前面讲到是这种最简单一种实验文件系统 357 00:17:10,720 --> 00:17:12,080 相对来说比较实际一些文件系统 358 00:17:12,120 --> 00:17:13,560 比如说FAT文件系统等等 359 00:17:13,600 --> 00:17:16,360 那么这些文件系统也有同学做过尝试 360 00:17:16,400 --> 00:17:20,960 能够去实现让ucore支持FAT格式的系统 361 00:17:21,000 --> 00:17:22,600 最后甚至还有同学去尝试 362 00:17:22,640 --> 00:17:25,720 让操作系统支持不同的语言 363 00:17:25,760 --> 00:17:28,840 我们都知道像ucore基于C语言来开发的 364 00:17:28,880 --> 00:17:31,080 那么我们能不能在ucore之上跑一些 365 00:17:31,120 --> 00:17:33,840 基于其它语言的一些应用程序 366 00:17:33,880 --> 00:17:35,280 有同学尝试了GO语言 367 00:17:35,320 --> 00:17:38,840 这是谷歌开发的一种新的编程语言 368 00:17:38,880 --> 00:17:40,120 也取得了一定成功 369 00:17:40,160 --> 00:17:42,440 我觉得这是很好的扩展 370 00:17:42,480 --> 00:17:46,000 那也有更多一些扩展 这里面没有一一列出 371 00:17:46,040 --> 00:17:47,760 其实操作系统这个领域 372 00:17:47,800 --> 00:17:51,640 有很多事情值得大家去探索和摸索的 373 00:17:51,680 --> 00:17:54,800 从中可以掌握更多一些功能和知识 374 00:17:54,840 --> 00:17:57,680 最后大家想了解一点是说 375 00:17:57,720 --> 00:18:02,400 你做了这么多实验 你到底有什么样的收获 376 00:18:02,440 --> 00:18:04,080 这个收获其实有好有坏 377 00:18:04,120 --> 00:18:07,840 我们这边把同学一些反馈给大家列出来 378 00:18:07,880 --> 00:18:12,680 可以看到 第一个理论和实践能够很好结合 379 00:18:12,720 --> 00:18:14,720 这样不会在感到OS课本 380 00:18:14,760 --> 00:18:16,080 只是需要一个死记硬背的课 381 00:18:16,120 --> 00:18:17,680 以前如果说不做实验的话 382 00:18:17,720 --> 00:18:20,000 基本上把概念死记下来就行了 383 00:18:20,040 --> 00:18:23,760 至于这个概念到底是怎么实现的 不用去关心 384 00:18:23,800 --> 00:18:26,800 上这门课你们需要了解这个实验 385 00:18:26,840 --> 00:18:29,000 和理论怎么去对应 这是一个很重要点 386 00:18:29,040 --> 00:18:33,280 第二点你在一个全局观 我们说上OS课里面 387 00:18:33,320 --> 00:18:35,480 原理课里面很多讲的是一些 388 00:18:35,520 --> 00:18:37,600 概念相对分散独立的概念 389 00:18:37,640 --> 00:18:39,200 那么你通过做实验 390 00:18:39,240 --> 00:18:41,320 你需要把这些概念揉合在一起形成 391 00:18:41,360 --> 00:18:44,080 一个完整可以工作的OS 392 00:18:44,120 --> 00:18:45,840 这也是通过实验能得到 393 00:18:45,880 --> 00:18:50,200 第三个很多概念和原理做了大量的抽象 394 00:18:50,240 --> 00:18:52,320 对于很多细节 395 00:18:52,360 --> 00:18:54,880 没有再进一步展开讲解 396 00:18:54,920 --> 00:18:57,960 那么通过做实验能够把这些细节知道更清楚 397 00:18:58,000 --> 00:19:00,560 特别是跟硬件结合 这实际上说 398 00:19:00,600 --> 00:19:02,680 在某种程度上可以说是计算机原理课 399 00:19:02,720 --> 00:19:05,000 和操作系统课一个综合 400 00:19:05,040 --> 00:19:09,160 能够知道在OS里面怎么控制一个硬件 401 00:19:09,200 --> 00:19:10,560 同时也有同学提出来 402 00:19:10,600 --> 00:19:14,600 这确实是大学期间碰到最复杂软件设计 403 00:19:14,640 --> 00:19:17,960 那么学到了分析和设计大型系统软件的方法 404 00:19:18,000 --> 00:19:20,400 也许大家将来不会开发OS 405 00:19:20,440 --> 00:19:22,160 但是你这种方法的掌握 406 00:19:22,200 --> 00:19:25,680 便于你后续去做跟计算机软件系统 407 00:19:25,720 --> 00:19:27,920 相关的一些事情打下很好的基础 408 00:19:27,960 --> 00:19:29,280 大家可以看到 409 00:19:29,320 --> 00:19:32,400 其实完成操作系统实验可以有很大的收获 410 00:19:32,440 --> 00:19:36,600 所以说这些实验之确实值得你去做深入的尝试