0 00:00:00,000 --> 00:00:07,120 1 00:00:07,320 --> 00:00:10,640 好 那我们首先再回顾一下历史 2 00:00:10,680 --> 00:00:12,800 就是Lab1完成了什么事情 3 00:00:12,840 --> 00:00:15,400 我们lab1其实一开始的时候 4 00:00:15,440 --> 00:00:16,200 它有个很重要的功能 5 00:00:16,240 --> 00:00:18,120 就是printf能够输出 6 00:00:18,160 --> 00:00:19,720 能够输出字符串 7 00:00:19,760 --> 00:00:21,200 那别小看printf 8 00:00:21,240 --> 00:00:22,720 那么printf这个输出呢 9 00:00:22,760 --> 00:00:25,480 能够有效地帮助我们来知道 10 00:00:25,520 --> 00:00:26,680 我们当前执行在什么地方了 11 00:00:26,720 --> 00:00:28,560 可以通过输出一些有意义的一些 12 00:00:28,600 --> 00:00:31,040 字符或者数字来帮助你理解 13 00:00:31,080 --> 00:00:33,280 你程序的一个执行行为 14 00:00:33,400 --> 00:00:34,880 再接下来我们是完成了 15 00:00:34,920 --> 00:00:36,480 保护模式和段机制的建立 16 00:00:36,520 --> 00:00:38,240 那这个建立在我们80386 17 00:00:38,280 --> 00:00:40,640 这个硬件基础之上的 18 00:00:40,680 --> 00:00:42,560 那有了这个保护模式和段机制呢 19 00:00:42,600 --> 00:00:44,560 为我们后续的页机制的建立 20 00:00:44,600 --> 00:00:45,680 打下了一个基础 21 00:00:45,720 --> 00:00:47,840 且有了段机制和保护模式之后 22 00:00:47,880 --> 00:00:49,520 我们可以使用32位的地址空间 23 00:00:49,560 --> 00:00:50,600 这是一个很重要的一个 24 00:00:50,640 --> 00:00:52,960 就是在lab1要完成的事情 25 00:00:53,000 --> 00:00:56,440 然后我们还完成了中断的机制 26 00:00:56,480 --> 00:00:57,440 这一点很重要 27 00:00:57,480 --> 00:01:00,000 因为中断我们前面在原理课讲到 28 00:01:00,040 --> 00:01:01,080 中断是干什么呢 29 00:01:01,120 --> 00:01:04,880 中断可以来响应外设的请求 30 00:01:04,920 --> 00:01:06,840 第二个呢我们应用程序呢 31 00:01:06,880 --> 00:01:08,800 也可以通过中断这种机制 32 00:01:08,840 --> 00:01:10,640 来得到操作系统的服务 33 00:01:10,680 --> 00:01:12,400 甚至说我们应用程序写错了 34 00:01:12,440 --> 00:01:14,560 这所谓的异常 产生异常之后呢 35 00:01:14,600 --> 00:01:16,640 我们操作系统也可以有效地去处理 36 00:01:16,680 --> 00:01:18,960 那这里面呢 建立好中断机制之后呢 37 00:01:19,000 --> 00:01:22,040 为我们这次实验这个缺页异常 38 00:01:22,080 --> 00:01:23,680 缺页异常或者访问页异常 39 00:01:23,720 --> 00:01:25,920 这种情况的处理打下很好的基础 40 00:01:25,960 --> 00:01:29,000 那有了这三个的工作之后呢 41 00:01:29,040 --> 00:01:31,160 那我们在完成lab3的时候 42 00:01:31,200 --> 00:01:34,960 就可以做到有的放矢 43 00:01:35,000 --> 00:01:36,400 那我们再看一下 44 00:01:36,440 --> 00:01:38,440 这个中断机制怎么建立的 45 00:01:38,480 --> 00:01:41,200 大家还回顾一下有没有印象 46 00:01:41,240 --> 00:01:43,960 首先这里面有一个中断的一个 47 00:01:44,000 --> 00:01:45,440 中断描述符表一个寄存器 48 00:01:45,480 --> 00:01:48,920 它记录了中断描述符表的起始地址 49 00:01:48,960 --> 00:01:51,240 那中断描述符表是干什么的呢 50 00:01:51,280 --> 00:01:53,720 它其实是存了很多的中断门 51 00:01:53,760 --> 00:01:54,880 一项一项的中断门 52 00:01:54,920 --> 00:01:56,400 这个中断门指出了 53 00:01:56,440 --> 00:01:58,160 当产生一个中断之后 54 00:01:58,200 --> 00:02:00,760 它对应的中断服务例程 55 00:02:00,800 --> 00:02:02,040 应该位于什么地方 56 00:02:02,080 --> 00:02:03,200 就是干这个事情的 57 00:02:03,240 --> 00:02:04,280 那么这相当于存了一个 58 00:02:04,320 --> 00:02:06,920 相关的所有中断或者异常的 59 00:02:06,960 --> 00:02:10,160 一个记录它地址的一个地方 60 00:02:10,200 --> 00:02:11,680 这是IDT 那么我们在lab1里面 61 00:02:11,720 --> 00:02:13,440 需要把这个IDT给建立好 62 00:02:13,480 --> 00:02:14,080 还要完成一系列 63 00:02:14,120 --> 00:02:15,520 中断初始化工作之后呢 64 00:02:15,560 --> 00:02:20,240 我们中断整个机制就可以建好了 65 00:02:20,280 --> 00:02:21,840 那建好中断处理机制之后 66 00:02:21,880 --> 00:02:24,920 我们可以看到一旦产生了一个中断 67 00:02:24,960 --> 00:02:26,800 那么中断都是有个中断号 68 00:02:26,840 --> 00:02:27,680 那么这里面我说的中断 69 00:02:27,720 --> 00:02:30,200 其实也包含了异常 70 00:02:30,240 --> 00:02:31,840 中断 异常产生之后呢 71 00:02:31,880 --> 00:02:33,520 会根据它的编号 72 00:02:33,560 --> 00:02:36,160 硬件 我们CPU会找这个IDT 73 00:02:36,200 --> 00:02:38,600 我们lab1我们ucore建好这个IDT 74 00:02:38,640 --> 00:02:40,040 找到你对应的中断号 75 00:02:40,080 --> 00:02:43,400 所对应的那个我们说叫中断 76 00:02:43,440 --> 00:02:46,200 或者陷井这个gate 门 这个门 77 00:02:46,240 --> 00:02:47,280 在这个门里面呢 78 00:02:47,320 --> 00:02:48,640 很重要一点它有offset 79 00:02:48,680 --> 00:02:49,680 就是它有一个偏移 80 00:02:49,720 --> 00:02:51,000 这里面记的偏移 81 00:02:51,040 --> 00:02:53,000 同时还记录一个信息 82 00:02:53,040 --> 00:02:54,320 就是它那个selector 83 00:02:54,360 --> 00:02:56,080 我们称之为选择子 84 00:02:56,120 --> 00:02:58,600 这些概念其实在lab1里面都碰到过 85 00:02:58,640 --> 00:02:59,840 这选择子实际上 86 00:02:59,880 --> 00:03:01,200 跟我们段机制又结合起来了 87 00:03:01,240 --> 00:03:03,680 这个选择子作为Index作为一个索引 88 00:03:03,720 --> 00:03:06,520 来查找我们另外一个 另外一个表 89 00:03:06,560 --> 00:03:07,600 我们称之为GDT 90 00:03:07,640 --> 00:03:08,720 就是全局描述符表 91 00:03:08,760 --> 00:03:10,840 或者简单说就是段表 92 00:03:10,880 --> 00:03:12,280 有了段表之后呢 93 00:03:12,320 --> 00:03:13,880 根据它(选择子)的Index可以查找 94 00:03:13,920 --> 00:03:15,960 你到底它(选择子)属于哪一个段 95 00:03:16,000 --> 00:03:19,960 然后从而可以知道这个段的 96 00:03:20,000 --> 00:03:21,480 Base Address 就是基址 97 00:03:21,520 --> 00:03:25,320 这个基址加上offset形成了最终的这个 98 00:03:25,360 --> 00:03:29,160 中断服务例程的入口地址 99 00:03:29,200 --> 00:03:31,120 所以说你可以看到我们的硬件 100 00:03:31,160 --> 00:03:33,280 一旦识别产生了一个中断之后呢 101 00:03:33,320 --> 00:03:35,120 根据它的中断号或者异常号 102 00:03:35,160 --> 00:03:38,000 来再进一步查找IDT和GDT 103 00:03:38,040 --> 00:03:40,720 从而可以跳到我们说 104 00:03:40,760 --> 00:03:43,480 中断服务例程的起始地址去执行 105 00:03:43,520 --> 00:03:46,120 这是说中断机制建立完之后呢 106 00:03:46,160 --> 00:03:49,200 我们硬件可以干的事情 107 00:03:49,240 --> 00:03:50,760 那我们操作系统从哪开始工作呢 108 00:03:50,800 --> 00:03:51,920 就从这儿开始工作 109 00:03:51,960 --> 00:03:54,920 一旦我们这个EIP说 110 00:03:54,960 --> 00:03:56,720 我们程序计数器跳这个地方 111 00:03:56,760 --> 00:03:58,360 我们CPU跳出来执行之后呢 112 00:03:58,400 --> 00:04:00,280 接下来的工作就是中断服务例程 113 00:04:00,320 --> 00:04:02,360 整个处理过程也是我们ucore 114 00:04:02,400 --> 00:04:04,320 里面的lab1来完成的 115 00:04:04,360 --> 00:04:07,280 它完成了怎么去响应和进一步去 116 00:04:07,320 --> 00:04:09,760 处理这个中断或者异常这个情况 117 00:04:09,800 --> 00:04:11,760 那也意味着如果说我们在lab3里面 118 00:04:11,800 --> 00:04:13,560 产生了一个页异常的一个中断 119 00:04:13,600 --> 00:04:14,680 那我们相应应该有一个 120 00:04:14,720 --> 00:04:16,880 页异常的一个中断服务例程 121 00:04:16,920 --> 00:04:18,280 来应对这种事情 122 00:04:18,320 --> 00:04:20,360 这需要我们去在lab3中 123 00:04:20,400 --> 00:04:22,120 去完成这个练习的 124 00:04:22,160 --> 00:04:26,840 125 00:04:26,880 --> 00:04:28,040 那我们再看看lab2 126 00:04:28,080 --> 00:04:29,400 lab1做了一个简单回顾 127 00:04:29,440 --> 00:04:31,520 我们再看lab2 那lab2是干什么呢 128 00:04:31,560 --> 00:04:34,360 lab2主要是完成对物理内存的管理 129 00:04:34,400 --> 00:04:36,360 主要完成这个页表机制建立 130 00:04:36,400 --> 00:04:37,280 所以说你可以看到 131 00:04:37,320 --> 00:04:39,320 它首先要去查找当前我们内存中 132 00:04:39,360 --> 00:04:40,520 有多少物理空间 133 00:04:40,560 --> 00:04:42,360 可以去使用 建立好一个 134 00:04:42,400 --> 00:04:44,600 就是对空闲物理空间的管理 135 00:04:44,640 --> 00:04:45,960 那这里面需要注意的是 136 00:04:46,000 --> 00:04:47,920 这个物理空间呢是连续的地址 137 00:04:47,960 --> 00:04:49,640 我们管理的是一块连续地址空间 138 00:04:49,680 --> 00:04:52,120 那和我们原理课里面讲的这个 139 00:04:52,160 --> 00:04:54,200 说连续地址空间内存分配呢 140 00:04:54,240 --> 00:04:55,880 是有紧密对应关系的 141 00:04:55,920 --> 00:04:58,080 第二个我们建立一个 142 00:04:58,120 --> 00:05:00,880 很简单的一个内存分配算法 143 00:05:00,920 --> 00:05:02,800 基于连续地址空间的内存分配算法 144 00:05:02,840 --> 00:05:04,960 这个算法其实在我们 145 00:05:05,000 --> 00:05:08,360 数据结构课里面也都会涉及到 146 00:05:08,400 --> 00:05:11,320 再最后就是要建立页机制 147 00:05:11,360 --> 00:05:12,920 它从而可以实现离散地址空间的 148 00:05:12,960 --> 00:05:14,160 一个有效的管理 149 00:05:14,200 --> 00:05:16,000 可以把一个所谓的虚地址 150 00:05:16,040 --> 00:05:17,360 映射到一块物理地址 151 00:05:17,400 --> 00:05:19,280 那么这是有页表机制在这里面 152 00:05:19,320 --> 00:05:22,080 完成了所谓的地址映射工作 153 00:05:22,120 --> 00:05:23,280 怎么去建立页表机制呢 154 00:05:23,320 --> 00:05:26,960 应该说是lab2里一个重要的实验内容 155 00:05:27,000 --> 00:05:32,080 好 页表机制涉及到什么呢 156 00:05:32,120 --> 00:05:34,360 涉及到我们说页表里面 157 00:05:34,400 --> 00:05:35,760 每一项一些功能 158 00:05:35,800 --> 00:05:37,320 那里面其实关注几个 159 00:05:37,360 --> 00:05:40,520 第一个页表呢它有一个起始地址 160 00:05:40,560 --> 00:05:41,600 这个起始地址是放在 161 00:05:41,640 --> 00:05:44,440 我们的CR3寄存器里面存着的 162 00:05:44,480 --> 00:05:45,520 它CR3寄存器这是 163 00:05:45,560 --> 00:05:47,080 我们一个特殊的控制寄存器 164 00:05:47,120 --> 00:05:48,840 它存着我们建立页表的 165 00:05:48,880 --> 00:05:50,400 起始地址在什么地方 166 00:05:50,440 --> 00:05:53,280 然后页表其实也是一个大数组 167 00:05:53,320 --> 00:05:55,280 里面每一项我们称之为页目录项 168 00:05:55,320 --> 00:05:56,160 或者是页表项 169 00:05:56,200 --> 00:05:58,440 如果是对于80386 32位机器而言 170 00:05:58,480 --> 00:06:01,160 它是一个二级的一个分层的页表 171 00:06:01,200 --> 00:06:03,640 所以呢它这里面会有所谓这个 172 00:06:03,680 --> 00:06:06,440 页目录项和页表项 173 00:06:06,480 --> 00:06:07,520 这两者是不一样的 174 00:06:07,560 --> 00:06:09,520 那么是二层的一个页表结构 175 00:06:09,560 --> 00:06:10,840 对于页目录项而言 176 00:06:10,880 --> 00:06:12,480 它里面的每一项存放着什么呢 177 00:06:12,520 --> 00:06:15,560 是存放着页表的基地址就是这一块 178 00:06:15,600 --> 00:06:18,760 这是一个项 那么这一项呢是32位 179 00:06:18,800 --> 00:06:22,840 那对于页目录项来说 180 00:06:22,880 --> 00:06:24,240 它很重要的一个信息就是这个 181 00:06:24,280 --> 00:06:25,600 page table address 182 00:06:25,640 --> 00:06:29,000 就是它所指向的对应页表的起始地址 183 00:06:29,040 --> 00:06:30,720 而对于页表项来说呢 184 00:06:30,760 --> 00:06:31,800 那它存的是什么呢 185 00:06:31,840 --> 00:06:33,320 存的是对应那个物理页 186 00:06:33,360 --> 00:06:35,680 页帧的起始地址 187 00:06:35,720 --> 00:06:37,160 那有了这个起始地址 188 00:06:37,200 --> 00:06:38,600 再加上我们说那个 189 00:06:38,640 --> 00:06:40,560 EIP所表示的offset 190 00:06:40,600 --> 00:06:42,000 就是页内的偏移 191 00:06:42,040 --> 00:06:43,520 我们就会形成最终的物理地址 192 00:06:43,560 --> 00:06:46,560 那这是整个说CR3 193 00:06:46,600 --> 00:06:50,240 然后这个是页目录项还有页表项 194 00:06:50,280 --> 00:06:51,840 这三者结合在一起呢 195 00:06:51,880 --> 00:06:54,280 就可以构成一个映射机制 196 00:06:54,320 --> 00:06:56,760 那这是我们lab2里面来完成的工作 197 00:06:56,800 --> 00:07:00,040 相信大家在完成lab1 lab2之后呢 198 00:07:00,080 --> 00:07:01,920 对我刚才提到中断处理机制 199 00:07:01,960 --> 00:07:04,040 页表机制有更深刻的理解 200 00:07:04,080 --> 00:07:05,320 那么有了这个基础 201 00:07:05,360 --> 00:07:06,480 等于是有了这个机制之后呢 202 00:07:06,520 --> 00:07:10,280 我们就可以来完成虚存管理了 203 00:07:10,320 --> 00:07:13,080 那我们虚存管理要干什么事情 204 00:07:13,120 --> 00:07:15,280 首先要充分利用lab1和lab2 205 00:07:15,320 --> 00:07:16,680 已经实现好的框架 206 00:07:16,720 --> 00:07:18,160 我们已经实现好的中断处理框架 207 00:07:18,200 --> 00:07:19,400 我们实现好了页表这个 208 00:07:19,440 --> 00:07:22,080 映射机制的框架 这个我们要重用 209 00:07:22,120 --> 00:07:24,120 在基础之上我们要去设计一个 210 00:07:24,160 --> 00:07:27,120 虚存的管理总体框架 从而可以达到 211 00:07:27,160 --> 00:07:30,080 我们刚才说的那个实验目标 212 00:07:30,120 --> 00:07:31,800 在实验总体框架之后呢 213 00:07:31,840 --> 00:07:33,920 我们要去针对总体框架关键部分 214 00:07:33,960 --> 00:07:35,000 来进行处理 215 00:07:35,040 --> 00:07:38,240 比如说怎么去有效处理这个页的 216 00:07:38,280 --> 00:07:41,480 缺页错之后这个中断处理例程 217 00:07:41,520 --> 00:07:43,760 中断服务例程这一块是要去完成的 218 00:07:43,800 --> 00:07:45,440 怎么去处理针对硬盘 219 00:07:45,480 --> 00:07:47,120 因为你要把页换入换出 220 00:07:47,160 --> 00:07:49,800 换入到内存里面 从硬盘换入到内存 221 00:07:49,840 --> 00:07:52,600 或者从内存导出到我们的硬盘 222 00:07:52,640 --> 00:07:54,400 那这个swap机制 223 00:07:54,440 --> 00:07:56,320 我们称之为swap机制你要去实现 224 00:07:56,360 --> 00:07:57,960 你需要涉及到硬盘的读写 225 00:07:58,000 --> 00:08:00,160 而这一块其实在我们的原理课里面 226 00:08:00,200 --> 00:08:01,440 讲的比较少一点 227 00:08:01,480 --> 00:08:03,880 因为它很具体的和我们这个 228 00:08:03,920 --> 00:08:05,920 外设disk有打交道 229 00:08:05,960 --> 00:08:08,480 而这个其实是分散的 230 00:08:08,520 --> 00:08:11,280 那再后面就是完成页替换算法 231 00:08:11,320 --> 00:08:12,400 这是我们专门的 232 00:08:12,440 --> 00:08:14,400 就是原理课很重要的部分 233 00:08:14,440 --> 00:08:16,480 就是讲各种各样的页替换算法 234 00:08:16,520 --> 00:08:18,200 那我们需要建立好 235 00:08:18,240 --> 00:08:19,240 前面这些机制之后呢 236 00:08:19,280 --> 00:08:20,360 就可以实现页替换算法 237 00:08:20,400 --> 00:08:22,400 从而可以最终的完成 238 00:08:22,440 --> 00:08:23,400 让这个页替换算法能够 239 00:08:23,440 --> 00:08:25,400 在我们这个系统中能够正常的工作 240 00:08:25,440 --> 00:08:27,640 来实现它所表达的功能 241 00:08:27,680 --> 00:08:29,560 就是换入换出的功能 242 00:08:29,600 --> 00:08:32,920 那这是说我们是整个虚存管理 243 00:08:32,960 --> 00:08:36,080 这个lab3的总体的一个框架 244 00:08:36,120 --> 00:08:38,600 那可以看出来它和我们原理课 245 00:08:38,640 --> 00:08:39,960 有很紧密的联系 246 00:08:40,000 --> 00:08:41,320 这里面涉及到很多的知识点 247 00:08:41,360 --> 00:08:43,480 在我们原理课里面都涉及到了 248 00:08:43,520 --> 00:08:46,920 那它和原理课之间的区别在什么地方 249 00:08:46,960 --> 00:08:49,800 区别在于实验是把原理课 250 00:08:49,840 --> 00:08:51,320 一些分散的知识点 251 00:08:51,360 --> 00:08:52,880 分散的关键的一些知识点呢 252 00:08:52,920 --> 00:08:54,080 给它集中在一起 253 00:08:54,120 --> 00:08:56,760 形成有机的整体来解决问题 254 00:08:56,800 --> 00:08:58,520 那这也是说希望大家做实验 255 00:08:58,560 --> 00:09:01,240 希望能体会到一点和原理课互相补充 256 00:09:01,280 --> 00:09:03,720 一个很重要的一个方面 257 00:09:03,760 --> 00:09:05,640 它的重要作用是什么呢 258 00:09:05,680 --> 00:09:06,920 希望大家把原理课里面 259 00:09:06,960 --> 00:09:08,680 所有学到的知识点 260 00:09:08,720 --> 00:09:10,920 能够通过做实验 能够融会贯通 261 00:09:10,960 --> 00:09:12,440 形成一体的一个感觉 262 00:09:12,480 --> 00:09:14,000 你能够知道做一个系统 263 00:09:14,040 --> 00:09:15,200 做一个操作系统应该 264 00:09:15,240 --> 00:09:17,400 怎么把这些知识点给贯彻在一起 265 00:09:17,440 --> 00:09:19,400 来完成相应的功能 266 00:09:19,440 --> 00:09:21,240 而不是说一个一个分散的一个点 267 00:09:21,280 --> 00:09:23,160 之间没有任何联系 268 00:09:23,200 --> 00:09:24,480 当你完成这个lab3之后 269 00:09:24,520 --> 00:09:26,240 你就会把前面介绍这些知识呢 270 00:09:26,280 --> 00:09:28,560 能够有效地整合在一起 271 00:09:28,600 --> 00:09:33,440 有效地整合在一起 272 00:09:33,480 --> 00:09:36,640 好 那我就把这个总体框架 273 00:09:36,680 --> 00:09:39,000 再逐一给大家做个简单介绍 274 00:09:39,040 --> 00:09:42,120 第一点是要完成虚拟内存的管理机制 275 00:09:42,160 --> 00:09:44,080 这里面最主要涉及到IDT硬盘的读写 276 00:09:44,120 --> 00:09:46,640 和缺页异常的建立 277 00:09:46,680 --> 00:09:48,800 好 那这个虚拟内存的这个管理呢 278 00:09:48,840 --> 00:09:52,040 首先是需要初始化一些相关的工作 279 00:09:52,080 --> 00:09:53,280 那初始化工作很明显就是 280 00:09:53,320 --> 00:09:56,240 我们在ucore整体初始化函数 281 00:09:56,280 --> 00:09:58,960 kern_ init这里面展开的 282 00:09:59,000 --> 00:10:02,000 这个函数其实从我们lab1到lab8 283 00:10:02,040 --> 00:10:03,400 都是从这个开始展开的 284 00:10:03,440 --> 00:10:04,960 所以说有同学说要看这个 285 00:10:05,000 --> 00:10:06,880 我看代码怎么去看 286 00:10:06,920 --> 00:10:09,200 首先从这儿开始看起 287 00:10:09,240 --> 00:10:12,440 可以从这个函数开始可以知道 288 00:10:12,480 --> 00:10:15,400 整个这个系统初始化的一个过程 289 00:10:15,440 --> 00:10:18,240 那在lab3之前是lab1 lab2 290 00:10:18,280 --> 00:10:19,520 它们完成的是什么呢 291 00:10:19,560 --> 00:10:21,240 是物理内存初始化 292 00:10:21,280 --> 00:10:23,840 pmm 以及中断的初始化 293 00:10:23,880 --> 00:10:27,520 比如PIC中断控制器IDT中断描述符表 294 00:10:27,560 --> 00:10:29,440 这两部分的初始化 295 00:10:29,480 --> 00:10:31,400 那这也是呢给我们进一步 296 00:10:31,440 --> 00:10:33,720 去做虚存管理呢也是奠定了基础 297 00:10:33,760 --> 00:10:36,400 298 00:10:36,440 --> 00:10:40,400 第二步就是要设立这个页帧的空间 299 00:10:40,440 --> 00:10:43,240 就是虚地址和物理地址对应关系 300 00:10:43,280 --> 00:10:44,520 你要设置好这个 301 00:10:44,560 --> 00:10:46,040 我们说这个实验环境 302 00:10:46,080 --> 00:10:49,000 比如说我们说有5个物理页 303 00:10:49,040 --> 00:10:51,760 但是你现在有6到7个虚拟页 304 00:10:51,800 --> 00:10:52,720 那页不够了 305 00:10:52,760 --> 00:10:53,920 你把这个环境要建好之后 306 00:10:53,960 --> 00:10:55,520 才能够去进一步去验证 307 00:10:55,560 --> 00:10:58,320 后续这个页替换算法 308 00:10:58,360 --> 00:10:59,480 那为了建立好这个关系 309 00:10:59,520 --> 00:11:00,840 要把这个关系表现清楚 310 00:11:00,880 --> 00:11:04,120 我们还需要去进一步去阐述 311 00:11:04,160 --> 00:11:06,040 就是这里面有些不在物理内存中的 312 00:11:06,080 --> 00:11:08,200 合法的虚拟页 313 00:11:08,240 --> 00:11:11,120 怎么去表述这个属性 314 00:11:11,160 --> 00:11:13,560 因为有时候这个页被换出去了 315 00:11:13,600 --> 00:11:15,760 它从应用程序的角度或者 316 00:11:15,800 --> 00:11:18,720 站在使用者角度来说它还是存在的 317 00:11:18,760 --> 00:11:20,520 但其实已经被我们OS换出去了 318 00:11:20,560 --> 00:11:22,240 我们需要把这个特征给表述出来 319 00:11:22,280 --> 00:11:24,840 那你需要去考虑怎么去设计 320 00:11:24,880 --> 00:11:26,680 那第二点是关于我们说刚才 321 00:11:26,720 --> 00:11:29,320 前面提到要给内存的使用者 322 00:11:29,360 --> 00:11:31,920 提供一个虚拟的一个使用的内存空间 323 00:11:31,960 --> 00:11:32,960 那这个内存空间呢 324 00:11:33,000 --> 00:11:35,680 表示这是我们要去建立好的 325 00:11:35,720 --> 00:11:36,880 用了两个关键数据结构 326 00:11:36,920 --> 00:11:38,040 一个是mm struct 327 00:11:38,080 --> 00:11:39,240 一个是vma struct 328 00:11:39,280 --> 00:11:40,600 后续会进一步展开 329 00:11:40,640 --> 00:11:41,560 其实这两个数据结构呢 330 00:11:41,600 --> 00:11:43,640 我们可以把我们使用者或者 331 00:11:43,680 --> 00:11:45,680 将来我们这个用户进程 332 00:11:45,720 --> 00:11:47,840 它所使用的这个合法的一个 333 00:11:47,880 --> 00:11:49,880 虚拟内存空间给表示出来 334 00:11:49,920 --> 00:11:52,400 这是这一块的一些表述 335 00:11:52,440 --> 00:11:53,720 那我们再看第三点 336 00:11:53,760 --> 00:11:56,000 第三点要建立页表映射 337 00:11:56,040 --> 00:11:58,160 页访问异常处理等函数的实现 338 00:11:58,200 --> 00:12:00,560 这希望把前面两者给结合起来 339 00:12:00,600 --> 00:12:03,840 把页表映射和缺页中断这一块 340 00:12:03,880 --> 00:12:05,520 给有机的结合起来 341 00:12:05,560 --> 00:12:06,920 当产生了缺页中断之后 342 00:12:06,960 --> 00:12:09,920 我们需要把相应它缺失的页表的 343 00:12:09,960 --> 00:12:11,560 映射关系给重新建立起来 344 00:12:11,600 --> 00:12:14,040 从而可以使得在一个有限的 345 00:12:14,080 --> 00:12:15,600 物理空间里面能够访问 346 00:12:15,640 --> 00:12:18,200 更大的虚拟空间这么一个目标 347 00:12:18,240 --> 00:12:21,320 这是我们第三步要去完善的 348 00:12:21,360 --> 00:12:24,200 那第三点我们是需要去把这个 349 00:12:24,240 --> 00:12:25,720 缺页异常之后要把这个相应的 350 00:12:25,760 --> 00:12:27,840 物理内存和我们虚拟内存的 351 00:12:27,880 --> 00:12:29,520 映射关系重新建立起来 352 00:12:29,560 --> 00:12:30,880 为此我们需要完成一个 353 00:12:30,920 --> 00:12:32,720 重要的函数do_pgfault的实现 354 00:12:32,760 --> 00:12:35,640 它也位于这个vmm.c这里面 355 00:12:35,680 --> 00:12:37,440 这里面有很详细的讲解 356 00:12:37,480 --> 00:12:40,720 讲述了它一旦接收到这个任务之后呢 357 00:12:40,760 --> 00:12:42,080 它怎么来完成的 358 00:12:42,120 --> 00:12:44,040 它的call graph就是函数调用关系 359 00:12:44,080 --> 00:12:46,320 这是它列出来的函数调用关系 360 00:12:46,360 --> 00:12:49,560 那这里面你需要去完成一系列工作 361 00:12:49,600 --> 00:12:52,200 要识别到底是什么原因 362 00:12:52,240 --> 00:12:55,360 产生了这个缺页错误或者缺页异常 363 00:12:55,400 --> 00:12:57,880 那么结合你进一步去分析 364 00:12:57,920 --> 00:12:59,680 这个页呢是否是合法的 365 00:12:59,720 --> 00:13:00,640 如果是合法的 366 00:13:00,680 --> 00:13:02,240 你就要把这个映射关系建立好 367 00:13:02,280 --> 00:13:04,320 如果不是合法的那么应该报错 368 00:13:04,360 --> 00:13:07,200 甚至把当前这个系统给停下来 369 00:13:07,240 --> 00:13:09,160 这是说这个do_pgfault 370 00:13:09,200 --> 00:13:10,920 大致要完成的工作 371 00:13:10,960 --> 00:13:12,720 第四步呢就是要开始测试了 372 00:13:12,760 --> 00:13:14,320 就是我们说你前面 373 00:13:14,360 --> 00:13:15,560 建好这一部分之后呢 374 00:13:15,600 --> 00:13:18,280 我们怎么能够来看你建好这个页表项 375 00:13:18,320 --> 00:13:21,480 是否能完成虚拟地址映射 376 00:13:21,520 --> 00:13:23,680 其实如果说你正确完成lab2 377 00:13:23,720 --> 00:13:24,800 那么这一步 378 00:13:24,840 --> 00:13:28,440 我觉得第四步应该是比较容易完成的 379 00:13:28,480 --> 00:13:30,680 第五步呢第五步要检查 380 00:13:30,720 --> 00:13:34,000 你这个能否正确的表述 381 00:13:34,040 --> 00:13:36,400 我们这个虚拟页它到底 382 00:13:36,440 --> 00:13:38,600 是在内存中还是在硬盘中 383 00:13:38,640 --> 00:13:42,840 那么这个也需要考虑怎么去能够 384 00:13:42,880 --> 00:13:45,520 检测你前面的实现是否正确 385 00:13:45,560 --> 00:13:47,680 那第六点呢 实际上是说我们要看看 386 00:13:47,720 --> 00:13:51,040 当某一个虚拟的这个页表映射关系 387 00:13:51,080 --> 00:13:52,960 它实际是把这个对应的页呢 388 00:13:53,000 --> 00:13:54,240 是放到了硬盘上 389 00:13:54,280 --> 00:13:56,600 那能否正常的从硬盘读进来 390 00:13:56,640 --> 00:13:58,080 或者是写回去 391 00:13:58,120 --> 00:14:00,920 那这里面需要去再做一个检查 392 00:14:00,960 --> 00:14:01,760 我们需要去检查 393 00:14:01,800 --> 00:14:03,120 在做实验上需要注意 394 00:14:03,160 --> 00:14:04,760 基本上步骤一步步来检查 395 00:14:04,800 --> 00:14:06,200 你前面的实现是否正确 396 00:14:06,240 --> 00:14:08,880 那最后一步呢 假如说这些都做好了 397 00:14:08,920 --> 00:14:09,800 最后一步干啥呢 398 00:14:09,840 --> 00:14:11,160 就看你那个页替换算法 399 00:14:11,200 --> 00:14:12,200 是否正确工作了 400 00:14:12,240 --> 00:14:14,480 因为你的页替换算法其实是 401 00:14:14,520 --> 00:14:16,240 需要前面那些能够正常工作之后 402 00:14:16,280 --> 00:14:19,080 才能够去检查你的页替换算法 403 00:14:19,120 --> 00:14:20,400 是否正常工作 404 00:14:20,440 --> 00:14:21,800 所以说你最后才去检查你这个 405 00:14:21,840 --> 00:14:23,800 你实现的页替换算法 406 00:14:23,840 --> 00:14:26,960 是否能正常的完成它所需要的 407 00:14:27,000 --> 00:14:28,200 把先进来的页 408 00:14:28,240 --> 00:14:31,400 给先换出去这么一个功能 409 00:14:31,440 --> 00:14:35,040 那其实关于这个vmm这个后面测试 410 00:14:35,080 --> 00:14:36,520 其实有一系列的测试 411 00:14:36,560 --> 00:14:38,880 要确保我们刚才建立合法的 412 00:14:38,920 --> 00:14:40,520 虚拟空间是合理的 413 00:14:40,560 --> 00:14:42,480 这里面有个check_vma_struct 414 00:14:42,520 --> 00:14:44,320 这方面的一些工作 415 00:14:44,360 --> 00:14:45,720 第二部分是要测试什么呢 416 00:14:45,760 --> 00:14:47,000 测试你的page fault 417 00:14:47,040 --> 00:14:48,360 这个机制能够正确的响应 418 00:14:48,400 --> 00:14:49,960 就比如说我要访问 419 00:14:50,000 --> 00:14:53,480 一个合法的一个虚拟地址 420 00:14:53,520 --> 00:14:54,480 这个虚拟地址它其实 421 00:14:54,520 --> 00:14:56,960 是可以被正常访问的 422 00:14:57,000 --> 00:14:58,320 但是它的映射关系还没建好 423 00:14:58,360 --> 00:14:59,560 所以一旦产生异常之后呢 424 00:14:59,600 --> 00:15:02,200 我们这个do_pgfault需要能够建好 425 00:15:02,240 --> 00:15:03,000 check_pgfault 426 00:15:03,040 --> 00:15:06,120 是看你完成的那个函数是否建好了 427 00:15:06,160 --> 00:15:07,880 这是看函数正确性这一块 428 00:15:07,920 --> 00:15:09,960 就关于异常处理这一块 429 00:15:10,000 --> 00:15:11,720 关于缺页异常处理这一块 430 00:15:11,760 --> 00:15:12,920 怎么来完成 431 00:15:12,960 --> 00:15:14,720 这是一个check 432 00:15:14,760 --> 00:15:16,440 好 做完这个check之后 433 00:15:16,480 --> 00:15:17,280 接下来check什么呢 434 00:15:17,320 --> 00:15:19,040 check你的页替换算法 435 00:15:19,080 --> 00:15:21,920 所以我们重点看swap这一块 436 00:15:21,960 --> 00:15:25,440 这个check_swap实际上是要测试 437 00:15:25,480 --> 00:15:27,560 你的页替换算法是否正确 438 00:15:27,600 --> 00:15:29,720 当然你这边会涉及到什么呢 439 00:15:29,760 --> 00:15:32,520 涉及到怎么去有效实现页替换算法 440 00:15:32,560 --> 00:15:36,520 在swap_fifo.c和swap.h里面 441 00:15:36,560 --> 00:15:38,000 这里面有详细的描述 442 00:15:38,040 --> 00:15:40,480 你怎么去实现一个页替换算法 443 00:15:40,520 --> 00:15:42,160 在这个框架之下实现就OK了 444 00:15:42,200 --> 00:15:45,800 那整个这个关于 445 00:15:45,840 --> 00:15:47,840 实现所谓的这个不同的 446 00:15:47,920 --> 00:15:49,720 页替换算法框架在哪呢 447 00:15:49,760 --> 00:15:52,480 就是在swap.c和swap.h里面 448 00:15:52,520 --> 00:15:55,640 这里面建好了整体的一个框架 449 00:15:55,760 --> 00:15:58,280 你可以看到这个框架里面 450 00:15:58,320 --> 00:16:00,400 大致的一个关键一些函数 451 00:16:00,440 --> 00:16:03,080 在这个swap_manager里面要去体现 452 00:16:03,120 --> 00:16:04,160 这是要去测试的 453 00:16:04,200 --> 00:16:04,880