0 00:00:00,000 --> 00:00:06,560 1 00:00:06,680 --> 00:00:07,680 好 那我们前面已经 2 00:00:07,760 --> 00:00:09,440 把这个空间建立完毕 3 00:00:09,480 --> 00:00:10,280 那接下来干什么 4 00:00:10,320 --> 00:00:12,640 我们希望我们的这个进程 5 00:00:12,680 --> 00:00:15,120 用户进程能够去到用户态去执行 6 00:00:15,160 --> 00:00:17,200 为此我们需要做个小练习 7 00:00:17,240 --> 00:00:21,480 来完成trapframe一个设置 8 00:00:21,560 --> 00:00:24,160 大家再回顾一下trapframe在哪见着呢 9 00:00:24,200 --> 00:00:25,240 其实在我们lab1 10 00:00:25,280 --> 00:00:26,880 lab1就已经涉及到了有一个 11 00:00:26,920 --> 00:00:29,280 trapframe完成了中断的一个 12 00:00:29,320 --> 00:00:30,960 打断的一个状态的保存 13 00:00:31,000 --> 00:00:31,840 就放在什么地方呢 14 00:00:31,880 --> 00:00:33,400 trapframe里面 15 00:00:33,440 --> 00:00:34,720 那为什么要用这个trapframe呢 16 00:00:34,760 --> 00:00:36,560 因为我们希望通过这个设置 17 00:00:36,600 --> 00:00:39,680 来完成一个特权级的一个转变 18 00:00:39,720 --> 00:00:44,160 从kernel空间切换到用户空间 19 00:00:44,200 --> 00:00:46,440 去执行我们的程序 20 00:00:46,480 --> 00:00:49,760 从而实现所谓的用户进程的一个执行 21 00:00:49,800 --> 00:00:53,160 那这个过程建立在前面的基础之上 22 00:00:53,200 --> 00:00:54,720 把这一步建好之后呢 23 00:00:54,760 --> 00:00:57,840 就可以让这个用户进程去执行了 24 00:00:57,880 --> 00:00:59,040 这是我们的练习 25 00:00:59,080 --> 00:01:00,520 那为此我们需要了解一下 26 00:01:00,560 --> 00:01:04,200 怎么从特权态0到特权态3 27 00:01:04,240 --> 00:01:07,080 这么一个切换 28 00:01:07,120 --> 00:01:08,320 其实这个过程呢 29 00:01:08,360 --> 00:01:10,600 在我们讲特权级的时候呢有提及 30 00:01:10,640 --> 00:01:15,120 但这里面我们再回顾一下 31 00:01:15,160 --> 00:01:17,040 那时候讲的时候第一个是说 32 00:01:17,080 --> 00:01:20,480 我们有一个ring0一个栈空间 33 00:01:20,520 --> 00:01:23,920 然后呢我们为了能够到ring3去 34 00:01:23,960 --> 00:01:26,960 我们做什么事情 35 00:01:27,000 --> 00:01:28,480 在这里面构造一个 36 00:01:28,520 --> 00:01:30,240 中断打断时候这个 37 00:01:30,280 --> 00:01:32,640 硬件保存的栈信息 38 00:01:32,680 --> 00:01:34,040 这一块 39 00:01:34,080 --> 00:01:35,640 正常情况下在内核态里面 40 00:01:35,680 --> 00:01:36,440 产生一个中断之后呢 41 00:01:36,480 --> 00:01:38,680 它会在它这个内核堆栈里面 42 00:01:38,720 --> 00:01:39,840 保存这个信息 43 00:01:39,880 --> 00:01:40,680 当然你完全可以自己 44 00:01:40,720 --> 00:01:42,120 构造出这么一个信息出来 45 00:01:42,160 --> 00:01:44,080 因为我们希望根据这个信息呢 46 00:01:44,120 --> 00:01:48,120 来使得在执行iret这条指令之后呢 47 00:01:48,160 --> 00:01:50,000 能够回到用户态去 48 00:01:50,040 --> 00:01:53,080 但这里面还不行 49 00:01:53,120 --> 00:01:53,880 为此我们要对它 50 00:01:53,920 --> 00:01:57,000 这个堆栈要做进一步的修改 51 00:01:57,040 --> 00:01:59,960 SS和CS呢重新设置 52 00:02:00,000 --> 00:02:02,480 从特权级0变成特权级3 53 00:02:02,520 --> 00:02:05,760 而且它的地址ESP还有EIP 54 00:02:05,800 --> 00:02:08,360 这个地址一个是堆栈的offset 55 00:02:08,400 --> 00:02:10,760 一个是执行地址的offset 56 00:02:10,800 --> 00:02:12,480 那么要重新设置 57 00:02:12,520 --> 00:02:15,400 从而可以使得这个区域呢 58 00:02:15,440 --> 00:02:17,720 正好是说模拟的一个 59 00:02:17,760 --> 00:02:20,120 当从ring3产生中断之后 60 00:02:20,160 --> 00:02:21,520 回到ring0的时候 61 00:02:21,560 --> 00:02:22,880 硬件保存的信息 62 00:02:22,920 --> 00:02:23,920 有了这个信息 63 00:02:23,960 --> 00:02:27,800 如果我们再执行iret的时候呢 64 00:02:27,840 --> 00:02:30,080 就会跳到ring3去了 65 00:02:30,120 --> 00:02:31,640 当然这个前提是我们前面已经 66 00:02:31,680 --> 00:02:35,320 建好了所谓这个中断门 67 00:02:35,360 --> 00:02:37,960 这是我们在lab1里面要掌握的内容 68 00:02:38,000 --> 00:02:39,080 那区别是什么呢 69 00:02:39,120 --> 00:02:42,240 lab1呢是从ring0里面产生中断 70 00:02:42,280 --> 00:02:43,920 依然回到ring0 71 00:02:43,960 --> 00:02:45,280 我们这里面是要从ring0里面 72 00:02:45,320 --> 00:02:47,200 要跳到ring3去执行 73 00:02:47,240 --> 00:02:49,280 lab1的challenge其实要完成这个事情 74 00:02:49,320 --> 00:02:51,800 直到lab5呢我们必须要完成这个事情 75 00:02:51,840 --> 00:02:56,400 才能实现用户进程在用户空间执行 76 00:02:56,440 --> 00:02:58,800 其实我们关注的是怎么能够去 77 00:02:58,840 --> 00:03:01,720 构造出一个合理一个trapframe 78 00:03:01,760 --> 00:03:05,120 使得在接下来执行iret之后呢 79 00:03:05,160 --> 00:03:07,960 能够跳到用户空间去执行 80 00:03:08,000 --> 00:03:10,880 那我们再小结一下可以看出来 81 00:03:10,920 --> 00:03:14,480 为了能够完成ring0到ring3这个跳转 82 00:03:14,520 --> 00:03:16,240 我们的进程 创建这个进程 83 00:03:16,280 --> 00:03:17,920 用户进程 它有两个栈 84 00:03:17,960 --> 00:03:20,960 一个是内核的stack kernel stack 85 00:03:21,000 --> 00:03:22,160 一个是用户的stack 86 00:03:22,200 --> 00:03:24,200 这样才能确保在用户态的时候 87 00:03:24,240 --> 00:03:25,640 它用的是用户stack 88 00:03:25,680 --> 00:03:27,880 在内核态的时候呢是用内核stack 89 00:03:27,920 --> 00:03:29,800 它可以通过系统调用 90 00:03:29,840 --> 00:03:33,040 来完成到内核的一个执行过程 91 00:03:33,080 --> 00:03:33,920 在一开始 92 00:03:33,960 --> 00:03:35,760 我们创建这个进程的时候呢 93 00:03:35,800 --> 00:03:37,560 还需要通过特殊的机制 94 00:03:37,600 --> 00:03:38,760 构造一个trapframe 95 00:03:38,800 --> 00:03:41,240 使得它能够跳到 这个 96 00:03:41,280 --> 00:03:43,800 用户进程的第一条指令去执行 97 00:03:43,840 --> 00:03:44,920 那这个过程 98 00:03:44,960 --> 00:03:46,880 需要大家通过练习来完成 99 00:03:46,920 --> 00:03:47,240 100 00:03:47,280 --> 00:03:47,320