0 00:00:00,000 --> 00:00:06,440 1 00:00:06,480 --> 00:00:08,800 那接下来我们会把这里面 2 00:00:08,840 --> 00:00:10,120 涉及到的一些比较关键的 3 00:00:10,160 --> 00:00:12,480 一些流程和关键的数据结构呢 4 00:00:12,520 --> 00:00:14,440 给大家做一个介绍 5 00:00:14,480 --> 00:00:15,720 流程一开始一样的 6 00:00:15,760 --> 00:00:17,240 就是我们要完成初始化工作 7 00:00:17,280 --> 00:00:19,360 那在lab3开始之前 8 00:00:19,400 --> 00:00:20,760 我们lab1 lab2已经有一个 9 00:00:20,800 --> 00:00:23,200 很重要的一系列的初始化 10 00:00:23,240 --> 00:00:25,760 比如涉及到的物理内存的初始化 11 00:00:25,800 --> 00:00:28,520 这是我们在lab1和lab2里面 12 00:00:28,560 --> 00:00:29,880 其实已经碰到了 13 00:00:29,920 --> 00:00:32,160 第二是中断初始化和IDT初始化 14 00:00:32,200 --> 00:00:34,000 这一块其实也是在lab1和lab2里面 15 00:00:34,040 --> 00:00:38,480 也都会相应的一个实现 那这个呢 16 00:00:38,520 --> 00:00:41,400 其实还是在给我们lab3打基础 17 00:00:41,440 --> 00:00:44,280 并没有涉及到lab3的一些功能 18 00:00:44,320 --> 00:00:46,000 如果要实现lab3的功能 19 00:00:46,040 --> 00:00:48,720 我们需要还做进一步初始化 20 00:00:48,760 --> 00:00:51,640 特别是这个swap_init这一块 21 00:00:51,680 --> 00:00:53,600 还有vmm_init 22 00:00:53,640 --> 00:00:56,000 那这两块 swap主要是说 23 00:00:56,040 --> 00:00:58,320 假设我能够读写硬盘之后 24 00:00:58,360 --> 00:01:01,360 我怎么能够去建立交换分区 25 00:01:01,400 --> 00:01:03,520 从而可以使得我们把一些页 26 00:01:03,560 --> 00:01:05,240 可以写入到我们的硬盘的 27 00:01:05,280 --> 00:01:06,680 特定的分区里面去 28 00:01:06,720 --> 00:01:08,200 或者从这个分区里面 29 00:01:08,240 --> 00:01:09,560 把这个对应的页给读进来 30 00:01:09,600 --> 00:01:12,000 这个就是叫swap这一块 31 00:01:12,040 --> 00:01:13,040 它要完成的工作 32 00:01:13,080 --> 00:01:16,280 它要完成对以页为单位的读写 33 00:01:16,320 --> 00:01:17,840 对硬盘的读写 34 00:01:17,880 --> 00:01:21,720 第二个呢vmm_init这一块是干什么呢 35 00:01:21,760 --> 00:01:22,960 就是我们前面说到的 36 00:01:23,000 --> 00:01:26,040 你要搭好这个环境来进行检测 37 00:01:26,080 --> 00:01:27,760 假设你前面已经完成了 38 00:01:27,800 --> 00:01:29,640 中断的异常初始化 39 00:01:29,680 --> 00:01:32,160 你已经完成了这个页替换算法 40 00:01:32,200 --> 00:01:35,160 完成了这个swap的这个读写 41 00:01:35,200 --> 00:01:37,040 那么在vmm_init里面 42 00:01:37,080 --> 00:01:38,560 它又把这个模拟环境建好 43 00:01:38,600 --> 00:01:40,920 那我先要分配大约4个 44 00:01:40,960 --> 00:01:43,560 假如说举个例子4个物理页 45 00:01:43,600 --> 00:01:46,120 但我这里面存在6 7或者8 46 00:01:46,160 --> 00:01:47,640 更多的虚拟页 47 00:01:47,680 --> 00:01:48,840 这种情况下我访问虚拟页 48 00:01:48,880 --> 00:01:51,560 还能够正常的工作 那怎么来完成 49 00:01:51,600 --> 00:01:53,640 就需要前面建好的中断机制 50 00:01:53,680 --> 00:01:56,360 swap机制 还有你这个页替换算法 51 00:01:56,400 --> 00:01:57,920 都能够正常工作之后呢 52 00:01:57,960 --> 00:02:00,040 才能确保这个vmm_init里面 53 00:02:00,080 --> 00:02:02,160 才能够完成相应的检测 54 00:02:02,200 --> 00:02:04,240 这里面就是建立这个模拟环境 55 00:02:04,280 --> 00:02:06,520 进行测试这就是vmm_init里面 56 00:02:06,560 --> 00:02:11,520 重点要完成的工作 57 00:02:11,560 --> 00:02:13,640 好 那在检查的时候呢 58 00:02:13,680 --> 00:02:16,640 这里面有两块需要注意的是 59 00:02:16,680 --> 00:02:20,320 在vmm_init里面它要检查 60 00:02:20,360 --> 00:02:22,640 我们说要搭好虚拟那一套 61 00:02:22,680 --> 00:02:24,440 就是使用环境 62 00:02:24,480 --> 00:02:28,000 这里面有个check_vmm和check_vma 63 00:02:28,040 --> 00:02:30,600 后面会讲到这个mm和vma 64 00:02:30,640 --> 00:02:32,000 是关键两个数据结构 65 00:02:32,040 --> 00:02:34,160 会给大家做一个介绍 66 00:02:34,200 --> 00:02:36,280 第二个呢是要check_pgfault 67 00:02:36,320 --> 00:02:37,400 就看你这个刚才说那个 68 00:02:37,440 --> 00:02:39,920 假设你产生了缺页异常之后 69 00:02:39,960 --> 00:02:42,880 你能否正确的进行响应和处理 70 00:02:42,920 --> 00:02:45,520 这一块就是这两块是说 71 00:02:45,560 --> 00:02:47,080 要完成相应的检查 72 00:02:47,120 --> 00:02:48,000 当然你只有在 73 00:02:48,040 --> 00:02:50,840 正确建立好了vma和page fault 74 00:02:50,880 --> 00:02:52,160 以及mm这个结构之后 75 00:02:52,200 --> 00:02:54,480 才能够完成 76 00:02:54,520 --> 00:02:56,280 我们再看看这个vma这个结构 77 00:02:56,320 --> 00:02:59,800 什么叫vma 叫virtual memory area 78 00:02:59,840 --> 00:03:01,120 简称叫vma 79 00:03:01,160 --> 00:03:04,000 其实这个词我们是从Linux里面来的 80 00:03:04,040 --> 00:03:06,360 跟它是一致的 vma这个结构 81 00:03:06,400 --> 00:03:09,480 vma结构重点是描述什么呢 82 00:03:09,520 --> 00:03:12,160 它描述了就是一个一个的 83 00:03:12,200 --> 00:03:15,240 合法的内存块的一个空间 84 00:03:15,280 --> 00:03:17,480 那么这一个一个合法的内存块空间呢 85 00:03:17,520 --> 00:03:19,120 可以说我们可以用来形成一个 86 00:03:19,160 --> 00:03:22,320 应用程序的一个大的应用空间 87 00:03:22,360 --> 00:03:24,000 合法使用的应用空间 88 00:03:24,040 --> 00:03:27,080 所以说呢一个一个相对离散的 89 00:03:27,120 --> 00:03:28,320 用户空间块 90 00:03:28,360 --> 00:03:30,240 那其实就是形成了一个list 91 00:03:30,280 --> 00:03:33,400 也用到我们前面在lab0讲到的一个 92 00:03:33,440 --> 00:03:34,720 list一个结构 93 00:03:34,760 --> 00:03:36,920 来把这些离散的空间给管理起来 94 00:03:36,960 --> 00:03:38,560 然后呢还有一个什么呢 95 00:03:38,600 --> 00:03:40,120 就是它有一个总的一个头 96 00:03:40,160 --> 00:03:42,840 就是说一个 假设用户进程 97 00:03:42,880 --> 00:03:44,640 我们这里做实验 还没有用户进程 98 00:03:44,680 --> 00:03:46,280 假设用户一个进程 99 00:03:46,320 --> 00:03:47,960 它需要把所有空间给管起来 100 00:03:48,000 --> 00:03:49,600 它有自己的页表 101 00:03:49,640 --> 00:03:51,360 那页表的相关信息 102 00:03:51,400 --> 00:03:54,560 总体的信息是放在一个所谓的mm(即指mm_struct) 103 00:03:54,600 --> 00:03:56,320 这么一个结构里面有vm_mm 104 00:03:56,360 --> 00:03:59,520 这个结构里面等于是它一个根 105 00:03:59,560 --> 00:04:00,840 这个根下面有一堆 106 00:04:00,880 --> 00:04:02,960 有一个list 这个list就是 107 00:04:03,000 --> 00:04:05,400 来表述了不同的分离的 108 00:04:05,440 --> 00:04:08,840 这个合法的内存 这里什么叫合法 109 00:04:08,880 --> 00:04:12,280 所谓合法就是说我们的应用程序 110 00:04:12,320 --> 00:04:14,720 我们跑这个程序可以去访问它 111 00:04:14,760 --> 00:04:17,520 访问它肯定是可以得到一个反馈 112 00:04:17,560 --> 00:04:19,200 可以正常读或者写的 113 00:04:19,240 --> 00:04:21,640 无论这个页对应的内存页 114 00:04:21,680 --> 00:04:23,240 是在我们内存中 115 00:04:23,280 --> 00:04:25,480 还是在我们硬盘里面 无所谓 116 00:04:25,520 --> 00:04:27,720 它是透明的 对我们应用程序来说 117 00:04:27,760 --> 00:04:29,920 对我们访问者来说是透明的 118 00:04:29,960 --> 00:04:36,240 这一点是虚存的很重要的一个概念 119 00:04:36,280 --> 00:04:38,440 第二个是mm这个struct 120 00:04:38,480 --> 00:04:42,600 这个是一个总述 它这里面呢是建立 121 00:04:42,640 --> 00:04:45,160 刚才说到的一个总的信息 122 00:04:45,200 --> 00:04:47,640 比如说对于一个应用程序来说 123 00:04:47,680 --> 00:04:49,560 它有它自己的页表 124 00:04:49,600 --> 00:04:51,120 页表起始地址在什么地方 125 00:04:51,160 --> 00:04:52,720 以及它映射了多少块 126 00:04:52,760 --> 00:04:54,920 这个vma这个结构等等 127 00:04:54,960 --> 00:04:56,320 还有呢就是可能很重要一点 128 00:04:56,360 --> 00:04:58,840 就是它如果说是需要 129 00:04:58,880 --> 00:05:00,800 去做一些查找工作的话 130 00:05:00,840 --> 00:05:02,400 就是它有一个排序 131 00:05:02,440 --> 00:05:03,760 对这里面地址空间有个排序 132 00:05:03,800 --> 00:05:06,400 可以便于后续去查找 133 00:05:06,440 --> 00:05:07,440 当一个应用程序 134 00:05:07,480 --> 00:05:09,040 访问一个内存地址之后 135 00:05:09,080 --> 00:05:10,880 这个地址到底处于哪个vma 136 00:05:10,920 --> 00:05:12,040 那么它有一个排序 137 00:05:12,080 --> 00:05:16,440 这是一个所谓的mmap_list这么一个结构 138 00:05:16,480 --> 00:05:18,920 这个结构和前面vma里面那个list 139 00:05:18,960 --> 00:05:21,400 形成了整个一个链表 140 00:05:21,440 --> 00:05:24,400 那这里面呢还有一个sm_priv 141 00:05:24,440 --> 00:05:29,360 这个是和swap机制是建立了联系 142 00:05:29,400 --> 00:05:31,080 可以看到这个是和我们 143 00:05:31,120 --> 00:05:32,480 后面会讲到swap manager 144 00:05:32,520 --> 00:05:33,800 就是说专门管理 145 00:05:33,840 --> 00:05:36,600 怎么去有效去把一个页 146 00:05:36,640 --> 00:05:39,600 给写到我们硬盘中或者读进来 147 00:05:39,640 --> 00:05:43,800 那这个就是跟它建立一个link 148 00:05:43,840 --> 00:05:46,840 那我们可以看到当vma和mm 149 00:05:46,880 --> 00:05:48,200 这两个结构对应的 150 00:05:48,240 --> 00:05:49,880 全局变量建立好之后呢 151 00:05:49,920 --> 00:05:51,120 我们就可以完成检查 152 00:05:51,160 --> 00:05:52,440 来看你这个vma结构 153 00:05:52,480 --> 00:05:55,360 就是所谓描述合法虚空间 154 00:05:55,400 --> 00:05:57,640 是否是正确工作的 155 00:05:57,680 --> 00:05:58,480 这是用什么的 156 00:05:58,520 --> 00:06:00,320 就是check _vma_ struct 157 00:06:00,360 --> 00:06:02,120 这个函数里面有一系列的检测 158 00:06:02,160 --> 00:06:05,560 它可以看到它有创建mm_struct 159 00:06:05,600 --> 00:06:07,080 创建vma_struct 160 00:06:07,120 --> 00:06:10,200 然后再塞入一系列测试数据 161 00:06:10,240 --> 00:06:13,520 模拟出来使用者的一个虚拟环境 162 00:06:13,560 --> 00:06:14,800 虚拟内存环境 163 00:06:14,840 --> 00:06:17,720 然后最后呢通过一系列的assert来检查 164 00:06:17,760 --> 00:06:20,720 应该当插入做完这个操作之后 165 00:06:20,760 --> 00:06:22,440 应该是具有什么样的值 166 00:06:22,480 --> 00:06:23,480 这里面有一系列的find 167 00:06:23,520 --> 00:06:24,880 来确保你是对的 168 00:06:24,920 --> 00:06:27,360 你整个结构建立是正确的 169 00:06:27,400 --> 00:06:28,960 那这是建立一个合法的 170 00:06:29,000 --> 00:06:33,760 虚拟内存空间的一个检查工作 171 00:06:33,800 --> 00:06:38,640 好 假设我们已经建立好了说有了mm 172 00:06:38,680 --> 00:06:41,160 有了vma 那其实可以描述 173 00:06:41,200 --> 00:06:43,800 描述一个应用程序 174 00:06:43,840 --> 00:06:45,080 或者是一个使用者 175 00:06:45,120 --> 00:06:46,160 它所需要的一个 176 00:06:46,200 --> 00:06:48,000 合法的虚拟的内存空间 177 00:06:48,040 --> 00:06:49,920 那么我们有了这个信息之后 178 00:06:49,960 --> 00:06:53,000 我们看看操作系统怎么去应对它 179 00:06:53,040 --> 00:06:54,640 可以看着这里面 180 00:06:54,680 --> 00:06:56,200 总体上有个mm_struct 181 00:06:56,240 --> 00:06:59,280 它会形成一个list双向链表 182 00:06:59,320 --> 00:07:01,560 双向链表由一系列的vma组成 183 00:07:01,600 --> 00:07:04,040 每一个vma表述了这个使用者 184 00:07:04,080 --> 00:07:08,440 所用到的一块虚拟的连续空间 185 00:07:08,480 --> 00:07:14,360 好 这虚拟连续空间 186 00:07:14,400 --> 00:07:16,880 所有的空间都应该是合法使用的 187 00:07:16,920 --> 00:07:18,560 就是我可以正常去做读或者写 188 00:07:18,600 --> 00:07:21,400 这是合法的 所谓合法那也意味着 189 00:07:21,440 --> 00:07:23,560 其实你这个里面描述的虚地址 190 00:07:23,600 --> 00:07:26,280 那么通过我们这个页表机制 191 00:07:26,320 --> 00:07:27,440 你们有页表 192 00:07:27,480 --> 00:07:29,360 我们在lab2里面不是建立好页表了吗 193 00:07:29,400 --> 00:07:31,040 那所有这个地址 194 00:07:31,080 --> 00:07:32,520 那么都应该在这个页表项里面 195 00:07:32,560 --> 00:07:34,040 有对应的映射关系 196 00:07:34,080 --> 00:07:36,120 它是以页为单位的映射关系 197 00:07:36,160 --> 00:07:37,560 好 有这个映射关系之后呢 198 00:07:37,600 --> 00:07:42,800 我们就可以来完成从一级页表 199 00:07:42,840 --> 00:07:45,720 到二级页表的一个转换 然后找到 200 00:07:45,760 --> 00:07:48,560 可以找到对应这个物理地址空间 201 00:07:48,600 --> 00:07:50,880 那个物理页帧就可以找着了 202 00:07:50,920 --> 00:07:55,120 也就是说这里面vma一个结构 203 00:07:55,160 --> 00:07:57,000 就是一个连续地址空间这么一大块 204 00:07:57,040 --> 00:07:59,200 其实可能映射到在这里面是 205 00:07:59,240 --> 00:08:04,560 多块离散的这个物理页帧 206 00:08:04,600 --> 00:08:06,360 这是通过我们页表机制 207 00:08:06,400 --> 00:08:08,440 来完成这个映射的 208 00:08:08,480 --> 00:08:11,160 那在这里面还会出现什么其它情况呢 209 00:08:11,200 --> 00:08:15,760 有可能 由于我们的给一开始 210 00:08:15,800 --> 00:08:18,480 给这个使用者分配这个虚拟空间 211 00:08:18,520 --> 00:08:20,960 虚拟空间呢超过了我们物理空间 212 00:08:21,000 --> 00:08:23,400 比如说在这里面只有1 2 3 4 5 213 00:08:23,440 --> 00:08:25,960 只有5个物理页帧 214 00:08:26,000 --> 00:08:28,280 但其实我们给它分了7个 215 00:08:28,320 --> 00:08:30,360 7个虚拟页 分了7个虚拟页 216 00:08:30,400 --> 00:08:33,640 那很明显一定会有两个虚拟页 217 00:08:33,680 --> 00:08:36,800 它没有对应的物理页帧 218 00:08:36,840 --> 00:08:39,080 那么如果访问到这两个虚拟页 219 00:08:39,120 --> 00:08:40,560 会出现什么情况呢 220 00:08:40,600 --> 00:08:42,720 很明显在这个里面 221 00:08:42,760 --> 00:08:44,480 应该说在我们实验里面会涉及到 222 00:08:44,520 --> 00:08:47,760 在二级页表里面它会什么 223 00:08:47,800 --> 00:08:50,440 它会没有对应映射关系 224 00:08:50,480 --> 00:08:51,680 一旦没有对应映射关系 225 00:08:51,720 --> 00:08:52,880 会出现什么现象呢 226 00:08:52,920 --> 00:08:55,280 一旦我们的使用者访问了 227 00:08:55,320 --> 00:08:57,640 某一个没有对应的映射关系的 228 00:08:57,680 --> 00:08:59,680 一个虚拟页的一个地址 229 00:08:59,720 --> 00:09:00,920 会出现什么情况 230 00:09:00,960 --> 00:09:02,640 大家考虑一下这个问题 231 00:09:02,680 --> 00:09:07,920 那其实就会产生缺页异常 OK 232 00:09:07,960 --> 00:09:09,720 一旦产生缺页异常就需要我们后续 233 00:09:09,760 --> 00:09:11,080 我们后面讲到这个缺页异常 234 00:09:11,120 --> 00:09:13,560 怎么处理啊 235 00:09:13,600 --> 00:09:17,600 一旦你建立好所谓do_pgfault 236 00:09:17,640 --> 00:09:18,640 这么一个机制 237 00:09:18,680 --> 00:09:20,440 也意味着你可以正确处理 238 00:09:20,480 --> 00:09:23,520 当一个合法的虚地址不存在的时候 239 00:09:23,560 --> 00:09:25,840 我怎么能够把这个映射关系建立好 240 00:09:25,880 --> 00:09:27,640 没有对应物理内存对应的时候 241 00:09:27,680 --> 00:09:29,640 需要把映射关系建立好 242 00:09:29,680 --> 00:09:30,800 怎么来检查正确性 243 00:09:30,840 --> 00:09:32,880 这有个check_pgfault 244 00:09:32,920 --> 00:09:34,240 在这里面一开始是完成 245 00:09:34,280 --> 00:09:36,840 对这个虚拟环境的建立 246 00:09:36,880 --> 00:09:38,400 虚拟内存环境的一个建立 247 00:09:38,440 --> 00:09:40,280 OK 建立完之后 248 00:09:40,320 --> 00:09:43,440 那也意味着当前访问到的 249 00:09:43,480 --> 00:09:45,520 虚拟内存是合法的 250 00:09:45,560 --> 00:09:48,080 因为vma里面有相应的表示 251 00:09:48,120 --> 00:09:50,240 也就是说 在这个合法区域里面 252 00:09:50,280 --> 00:09:53,800 虚拟内存可以进行正常读或者写操作 253 00:09:53,840 --> 00:09:56,840 这里面就是完成了相应的读写操作 254 00:09:56,880 --> 00:09:58,040 但是由于它没有建立 255 00:09:58,080 --> 00:09:59,560 相应的映射关系 256 00:09:59,600 --> 00:10:01,920 所以说一旦执行操作的时候 257 00:10:01,960 --> 00:10:03,160 读写操作的时候 258 00:10:03,200 --> 00:10:05,560 其实会产生缺页异常 259 00:10:05,600 --> 00:10:08,240 一旦你能够正确实现缺页异常 260 00:10:08,280 --> 00:10:10,720 那么这一部分的工作 261 00:10:10,760 --> 00:10:13,800 最后这个assert是可以得到确认的 262 00:10:13,840 --> 00:10:15,360 也就这句话是可以过的 263 00:10:15,400 --> 00:10:17,080 这个语句过了之后呢 264 00:10:17,120 --> 00:10:19,520 那基本上证明你的工作是做对了 265 00:10:19,560 --> 00:10:21,400 那么这里面会有一个 266 00:10:21,440 --> 00:10:24,920 打印你这个do_pgfault是成功的 267 00:10:24,960 --> 00:10:25,400 268 00:10:25,440 --> 00:10:25,480