0 00:00:00,000 --> 00:00:06,960 1 00:00:07,040 --> 00:00:10,320 练习四呢 2 00:00:10,400 --> 00:00:12,320 假定进入这个保护模式之后 3 00:00:12,360 --> 00:00:14,520 我们Bootloader需要干的很重要一个事情 4 00:00:14,560 --> 00:00:17,280 就是要能够加载ELF文件 5 00:00:17,320 --> 00:00:18,960 为什么要加载ELF文件呢 6 00:00:19,000 --> 00:00:22,080 因为我们的kernel 就是uCoreOS 7 00:00:22,120 --> 00:00:25,000 是以ELF形式存在在硬盘上的 8 00:00:25,040 --> 00:00:27,560 什么文件呢 就这个文件 9 00:00:27,600 --> 00:00:39,680 10 00:00:39,720 --> 00:00:40,520 可以看到这个kernel 11 00:00:40,560 --> 00:00:41,960 就是我们这个uCore 12 00:00:42,000 --> 00:00:45,680 它完成了刚才说的 13 00:00:45,720 --> 00:00:47,840 负责把这个中断初始化好 14 00:00:47,880 --> 00:00:49,000 然后产生时钟中断 15 00:00:49,040 --> 00:00:53,040 能够把这个信息显示在屏幕上等等 16 00:00:53,080 --> 00:01:00,760 这些功能都是uCore完成的很基本的一些功能 17 00:01:00,800 --> 00:01:02,960 那这里面比较有意思的是 18 00:01:03,000 --> 00:01:03,760 Bootloader怎么能够 19 00:01:03,800 --> 00:01:06,160 把uCore给加载到内存当中去 20 00:01:06,200 --> 00:01:08,480 其实它需要完成很重要的两步事情 21 00:01:08,520 --> 00:01:11,840 第一步 是怎么能够读取硬盘中的信息 22 00:01:11,880 --> 00:01:15,200 这需要Bootloader能够访问硬盘 23 00:01:15,240 --> 00:01:19,160 第二个是Bootloader把这个硬盘数据读出来之后 24 00:01:19,200 --> 00:01:22,840 要把其中ELF格式这个文件给分析出来 25 00:01:22,880 --> 00:01:25,800 从而知道我们uCore它的代码段 26 00:01:25,840 --> 00:01:27,480 应该放在什么地方 27 00:01:27,520 --> 00:01:30,280 应该有多大一块空间放这个代码段数据 28 00:01:30,320 --> 00:01:32,840 哪一段空间是放数据段的数据 29 00:01:32,880 --> 00:01:34,120 然后把它加载内存当中去 30 00:01:34,160 --> 00:01:35,320 然后同时还知道 31 00:01:35,360 --> 00:01:37,640 跳转到uCore哪个地方去执行 32 00:01:37,680 --> 00:01:41,000 那这一块代码 其实我们也是一样的 33 00:01:41,040 --> 00:01:48,920 有专门一个小的Project来完成这个事情 34 00:01:48,960 --> 00:02:06,640 我们的Project2就是干这个事情的 35 00:02:06,680 --> 00:02:08,600 那在Project2我们可以看到 36 00:02:08,640 --> 00:02:13,160 跟Project1比起来 它增加了一段代码 37 00:02:13,200 --> 00:02:15,360 这个代码主要是能够 38 00:02:15,400 --> 00:02:20,960 刚才说到这个 读扇区 39 00:02:21,000 --> 00:02:23,160 和分析这个文件 40 00:02:23,200 --> 00:02:28,360 读扇区呢主要是这个函数 readsect 41 00:02:28,400 --> 00:02:33,400 这是读取扇区 它用到了这个in b 42 00:02:33,440 --> 00:02:36,880 和out b这种机器指令 43 00:02:36,920 --> 00:02:38,760 那我们可以看到这里面 44 00:02:38,800 --> 00:02:41,680 其实inb和outb的实现 45 00:02:41,720 --> 00:02:43,320 都是用我们说的 46 00:02:43,360 --> 00:02:45,800 刚在lab0中介绍到过的 47 00:02:45,840 --> 00:02:50,120 内联汇编来实现的 48 00:02:50,160 --> 00:02:53,600 它采取了一种IO空间的寻址方式 49 00:02:53,640 --> 00:02:58,120 能够把外设的数据给读到内存中来 50 00:02:58,160 --> 00:03:01,760 这也是一种X86里面的寻址方式 51 00:03:01,800 --> 00:03:03,120 除了正常memory方式之外 52 00:03:03,160 --> 00:03:06,720 还有IO一种寻址方式 53 00:03:06,760 --> 00:03:11,320 好 那这一块细节呢其实大家不用特别看 54 00:03:11,360 --> 00:03:14,360 只是知道我们这个Bootloader 55 00:03:14,400 --> 00:03:16,920 知道怎么去从哪开始 56 00:03:16,960 --> 00:03:18,640 把相应的扇区给读进来 57 00:03:18,680 --> 00:03:21,160 以及它读多大 读完之后 58 00:03:21,200 --> 00:03:24,080 它就需要去进一步的分析 59 00:03:24,120 --> 00:03:26,480 那这个分析呢 需要去了解 60 00:03:26,520 --> 00:03:30,920 了解相应的格式ELF的格式 61 00:03:30,960 --> 00:03:32,720 好 我们可以看到在bootmain里面呢 62 00:03:32,760 --> 00:03:35,200 它有一个对ELF格式一个判断 63 00:03:35,240 --> 00:03:37,920 它怎么知道读进来这个扇区的数据 64 00:03:37,960 --> 00:03:39,760 是一个ELF格式的文件呢 65 00:03:39,800 --> 00:03:43,360 它其实是读取了一个ELF的header 66 00:03:43,400 --> 00:03:45,120 从磁盘中读取ELFheader 67 00:03:45,160 --> 00:03:49,760 然后判断它的一个特殊的成员变量 e magic 68 00:03:49,800 --> 00:03:52,600 看它是否等于一个特定的值 69 00:03:52,640 --> 00:03:53,320 如果等于特定值 70 00:03:53,360 --> 00:03:57,520 就认为是确实是一个合法的ELF格式的文件 71 00:03:57,560 --> 00:03:58,880 那我们在lab1里面 72 00:03:58,920 --> 00:04:02,760 有更详细把这个文件的ELF格式文件信息 73 00:04:02,800 --> 00:04:05,280 给读取进来一段判断 74 00:04:05,320 --> 00:04:06,760 大家可以看这个 75 00:04:06,800 --> 00:04:15,800 在这个bootmain里面呢有相应一些实现 76 00:04:15,840 --> 00:04:17,600 这个bootmain函数 77 00:04:17,640 --> 00:04:23,960 它怎么能够根据ELFheader和proghdr程序头 78 00:04:24,000 --> 00:04:25,920 来读出相应的代码段和数据段 79 00:04:25,960 --> 00:04:27,360 然后加到相应的地方去 80 00:04:27,400 --> 00:04:28,600 最后这一条比较关键 81 00:04:28,640 --> 00:04:31,440 这就决定了到底Bootloader把这个加载完之后 82 00:04:31,480 --> 00:04:32,720 到底要跳到什么地方去 83 00:04:32,760 --> 00:04:35,360 把控制权交给uCore去执行 84 00:04:35,400 --> 00:04:38,240 这就是Bootloader干的最主要的事情 85 00:04:38,280 --> 00:04:40,840 那其实也可以看到 我们练习一到练习四 86 00:04:40,880 --> 00:04:43,800 主要是对lab1Bootloader这一块 87 00:04:43,840 --> 00:04:45,960 给大家做相应一些练习 88 00:04:46,000 --> 00:04:47,400 那么练习五和六 89 00:04:47,440 --> 00:04:49,800 主要是针对这个uCore本身了 90 00:04:49,840 --> 00:04:51,960 那练习五主要是考虑的是 91 00:04:52,000 --> 00:04:55,400 怎么能够分析函数的调用栈 92 00:04:55,440 --> 00:04:59,280 练习六呢 主要是建立中断 93 00:04:59,320 --> 00:05:01,160 这两块相对来说要复杂一些 94 00:05:01,200 --> 00:05:08,240 需要大家去编程 95 00:05:08,280 --> 00:05:09,960 这里面显示练习五 96 00:05:10,000 --> 00:05:12,240 这一段输出呢 是正确的输出结果 97 00:05:12,280 --> 00:05:13,360 可以看出来 98 00:05:13,400 --> 00:05:18,440 如果你能正确的分析出这个栈帧格式 99 00:05:18,480 --> 00:05:19,960 栈帧它这个依赖关系 100 00:05:20,000 --> 00:05:21,280 栈帧格建立的链表 101 00:05:21,320 --> 00:05:24,400 那我们就可以把相应函数代码关系给展示出来 102 00:05:24,440 --> 00:05:26,400 那这就是一个最后展示的结果 103 00:05:26,440 --> 00:05:32,520 那怎么去把正确的ESP和EBP给读取出来 104 00:05:32,560 --> 00:05:35,720 这是完成这个lab5实验的关键 105 00:05:35,760 --> 00:05:38,520 这里面其实填的内容很少 就两句话 106 00:05:38,560 --> 00:05:41,440 但是你要把相应的细节要掌握清楚 107 00:05:41,480 --> 00:05:44,920 才能够正确的填写相应的代码 108 00:05:44,960 --> 00:05:48,400