0 00:00:00,000 --> 00:00:16,080 1 00:00:16,120 --> 00:00:17,400 各位同学 大家好 2 00:00:17,440 --> 00:00:22,080 我们现在开始来讲 第二讲 3 00:00:22,120 --> 00:00:27,520 这一讲主要内容是中断 异常和系统调用 4 00:00:27,560 --> 00:00:30,440 首先我们需要来了解一下 5 00:00:30,480 --> 00:00:33,000 计算机系统在加电的时候 6 00:00:33,040 --> 00:00:37,480 从什么地方去读第一条指令 7 00:00:37,520 --> 00:00:40,000 从磁盘上的什么地方 8 00:00:40,040 --> 00:00:43,200 去读的我操作系统内容 9 00:00:43,240 --> 00:00:45,240 在这里头就相当于我们在说 10 00:00:45,280 --> 00:00:50,000 计算机系统的启动过程 11 00:00:50,040 --> 00:00:53,600 这张图大家在前面的课程当中都已经见到过了 12 00:00:53,640 --> 00:00:56,960 说CPU是有计算能力 13 00:00:57,000 --> 00:01:01,240 它可以执行指令 内存它有存储能力 14 00:01:01,280 --> 00:01:03,320 我们在程序运行的过程当中 15 00:01:03,360 --> 00:01:06,800 代码数据是存在这个内存里的 16 00:01:06,840 --> 00:01:10,000 然后这个I/O设备可以跟外交有交互能力 17 00:01:10,040 --> 00:01:11,600 我们的键盘输入 18 00:01:11,640 --> 00:01:14,880 我们的磁盘输入输出 网络的输入输出 19 00:01:14,920 --> 00:01:18,920 都是作为I/O设备来跟系统打交道的 20 00:01:18,960 --> 00:01:20,720 但是在今天的课程里头 21 00:01:20,760 --> 00:01:24,480 我们会更进一步来讨论这样一个问题 22 00:01:24,520 --> 00:01:26,920 CPU在加电之后 23 00:01:26,960 --> 00:01:29,800 它执行的第一条指令在哪 24 00:01:29,840 --> 00:01:33,120 那说我们在CPU在加电 25 00:01:33,160 --> 00:01:34,320 电源稳定之后 26 00:01:34,360 --> 00:01:38,920 那这个时候它会对里头的寄存器做一个初始化 27 00:01:38,960 --> 00:01:40,280 到一个指定状态 28 00:01:40,320 --> 00:01:43,160 这个时候开始去执行第一条指令 29 00:01:43,200 --> 00:01:44,800 那这第一指令在哪 30 00:01:44,840 --> 00:01:46,440 它会在内存里头 31 00:01:46,480 --> 00:01:50,040 但是我们在前面讲的内存的时候 32 00:01:50,080 --> 00:01:52,560 说内存是用来存数据的 33 00:01:52,600 --> 00:01:54,160 里头一关掉电源之后 34 00:01:54,200 --> 00:01:56,120 再加电的时候里面就没内容了 35 00:01:56,160 --> 00:01:58,280 这个时候你去执行第一条指令 36 00:01:58,320 --> 00:02:00,520 这第一条指令从哪来呢 37 00:02:00,560 --> 00:02:01,360 我们这个时候会 38 00:02:01,400 --> 00:02:06,080 内存会分成RAM 随机访问存储 39 00:02:06,120 --> 00:02:09,320 还有一个ROM只读存储 40 00:02:09,360 --> 00:02:12,720 这两个部分 内存当中有一部分区域里头 41 00:02:12,760 --> 00:02:14,440 就是ROM它是只读存储 42 00:02:14,480 --> 00:02:16,440 也就是说加电之后 43 00:02:16,480 --> 00:02:20,080 里头还会有一些我们原来写入的一些内容 44 00:02:20,120 --> 00:02:23,240 这些内容我们的系统初始化代码 45 00:02:23,280 --> 00:02:26,880 就从那里开始执行 46 00:02:26,920 --> 00:02:30,640 具体说起来我们可以这样来看 47 00:02:30,680 --> 00:02:33,440 在计算机系统加电的时候 48 00:02:33,480 --> 00:02:36,880 我们在这里头1MB下面有一段 49 00:02:36,920 --> 00:02:41,240 这段就是我们的BIOS固件 50 00:02:41,280 --> 00:02:45,760 这部分它在加电的时候我们蹦到那去执行 51 00:02:45,800 --> 00:02:48,520 这个时候就有一个约定 52 00:02:48,560 --> 00:02:52,000 计算机系统CPU在初始化完成之后 53 00:02:52,040 --> 00:02:58,040 里头的代码段寄存器和当前指针 54 00:02:58,080 --> 00:03:01,400 这两个寄存器的值是多少 55 00:03:01,440 --> 00:03:04,760 因为这个值直接决定了我们从内存当中 56 00:03:04,800 --> 00:03:06,360 读数据时候的位置 57 00:03:06,400 --> 00:03:10,400 我们在系统CPU完成初始化之后 58 00:03:10,440 --> 00:03:14,080 它处于实模式下 在实模式下 59 00:03:14,120 --> 00:03:18,280 它的地址计算把段寄存器左移四位 60 00:03:18,320 --> 00:03:21,600 然后加上它的当前指令指针 61 00:03:21,640 --> 00:03:23,400 这两个加在一起作为 62 00:03:23,440 --> 00:03:26,960 我们当前访问第一条指定位置 63 00:03:27,000 --> 00:03:29,160 还有一条限制是说 64 00:03:29,200 --> 00:03:32,160 在加电的时候 它处于实模式 65 00:03:32,200 --> 00:03:33,800 这个时候地址总线 66 00:03:33,840 --> 00:03:36,640 并不是像我们现在用到通常系统是32位 67 00:03:36,680 --> 00:03:38,960 它只有20位的地址可用 68 00:03:39,000 --> 00:03:40,600 那在这20位地址里头 69 00:03:40,640 --> 00:03:44,240 我们用的区域就是2的二十次方 70 00:03:44,280 --> 00:03:45,960 这个时候就只有1M 71 00:03:46,000 --> 00:03:50,920 所以放的区域就只能放在最底下1M里头一小块 72 00:03:50,960 --> 00:03:54,640 这块代码它为了从磁盘上读数据 73 00:03:54,680 --> 00:03:56,800 那这个时候必须提供相应的服务 74 00:03:56,840 --> 00:03:58,080 如果没有这些服务 75 00:03:58,120 --> 00:04:00,880 你是没有办法访问到磁盘设备的 76 00:04:00,920 --> 00:04:04,360 为了做到这件事情 77 00:04:04,400 --> 00:04:07,480 在BIOS里头 它需要提供这样一些功能 78 00:04:07,520 --> 00:04:09,600 基本的输入输出 79 00:04:09,640 --> 00:04:11,800 然后系统的配置信息 80 00:04:11,840 --> 00:04:14,960 开机自检和系统启动程序 81 00:04:15,000 --> 00:04:17,760 这几个部分基本输入 输出 82 00:04:17,800 --> 00:04:21,160 它是完成能够我从磁盘上读数据 83 00:04:21,200 --> 00:04:24,400 从键盘上读用户的输入 84 00:04:24,440 --> 00:04:27,520 我可以在显示器上显示相应的输出 85 00:04:27,560 --> 00:04:29,560 这是它基本的输入 输出的功能 86 00:04:29,600 --> 00:04:31,120 然后系统的配置 87 00:04:31,160 --> 00:04:33,560 我们都知道系统在刚开始的时候 88 00:04:33,600 --> 00:04:34,240 你需要有配置 89 00:04:34,280 --> 00:04:38,880 我到底是从硬盘启动 从网络启动 90 00:04:38,920 --> 00:04:41,160 还是说从光盘启动 91 00:04:41,200 --> 00:04:43,520 那这些启动是在你加电的时候 92 00:04:43,560 --> 00:04:46,160 由你的BIOS的设置来完成 93 00:04:46,200 --> 00:04:49,800 依据这些设置系统执行它的启动程序 94 00:04:49,840 --> 00:04:54,400 我能从硬盘把我的加载程序和操作系统内容 95 00:04:54,440 --> 00:04:56,280 加载到系统当中来 96 00:04:56,320 --> 00:04:59,160 具体的过程 我们可以这样来看 97 00:04:59,200 --> 00:05:03,040 在BIOS里头 它启动起来的时候 98 00:05:03,080 --> 00:05:05,680 它的初始化完成之后 99 00:05:05,720 --> 00:05:08,400 它就会从磁盘上读引导散区 100 00:05:08,440 --> 00:05:13,000 这个引导散区是只有长度512字节 101 00:05:13,040 --> 00:05:15,760 更长的它没有这个能力在BIOS程序 102 00:05:15,800 --> 00:05:18,440 它不允许你能读更多内容 103 00:05:18,480 --> 00:05:20,520 读进来放到指定的位置 104 00:05:20,560 --> 00:05:23,960 然后跳转到其中的固定位置 105 00:05:24,000 --> 00:05:26,800 就是这里的7C00 106 00:05:26,840 --> 00:05:28,320 然后这个时候我们就把控制权 107 00:05:28,360 --> 00:05:31,640 转到从磁盘上读进来的程序 108 00:05:31,680 --> 00:05:35,320 在我们这里 这是我们这里的加载程序 109 00:05:35,360 --> 00:05:39,080 加载程序里头我们又可以做进一步的事情 110 00:05:39,120 --> 00:05:40,840 这加载程序能干什么呢 111 00:05:40,880 --> 00:05:45,440 它能将操作系统的代码读到内存里头来 112 00:05:45,480 --> 00:05:48,800 并且能把控制权交给操作系统 113 00:05:48,840 --> 00:05:50,440 来继续执行操作系统功能 114 00:05:50,480 --> 00:05:53,240 这个时候有个问题 说 115 00:05:53,280 --> 00:05:55,480 你既然能从磁盘上读数据 116 00:05:55,520 --> 00:05:58,000 那为啥我不是直接从BIOS里头 117 00:05:58,040 --> 00:06:02,280 直接把操作系统的内核映像读进来呢 118 00:06:02,320 --> 00:06:05,040 实际上这时候它是有这样一些问题 119 00:06:05,080 --> 00:06:08,040 首先我们磁盘上是有文件系统的 120 00:06:08,080 --> 00:06:10,040 文件系统是多种多样的 121 00:06:10,080 --> 00:06:12,840 我们在机器出厂的时候 122 00:06:12,880 --> 00:06:15,280 不可以说我直接限制死你 123 00:06:15,320 --> 00:06:17,200 你只能用某一种文件系统 124 00:06:17,240 --> 00:06:18,760 为了增加这种灵活性 125 00:06:18,800 --> 00:06:22,280 那我在BIOS又不可能加上认识 126 00:06:22,320 --> 00:06:24,120 所有文件系统代码 127 00:06:24,160 --> 00:06:27,200 那怎么办 我就在里有一个基本约定 128 00:06:27,240 --> 00:06:28,800 我不需要认识格式 129 00:06:28,840 --> 00:06:32,320 我也能从里头读到你的第一块 130 00:06:32,360 --> 00:06:36,000 读了这块之后 这块的加载程序里头 131 00:06:36,040 --> 00:06:40,640 我们会用加载程序来识别你磁盘上文件系统 132 00:06:40,680 --> 00:06:44,000 这时候我认识磁盘上文件系统之后 133 00:06:44,040 --> 00:06:47,280 我就可以读到我内核的镜像 134 00:06:47,320 --> 00:06:50,080 并且把它加载到内存当中来 135 00:06:50,120 --> 00:06:51,800 这就是我们这里看到 136 00:06:51,840 --> 00:06:55,640 用加载程序读到操作系统来 137 00:06:55,680 --> 00:06:56,960 有了这个过程之后 138 00:06:57,000 --> 00:07:00,640 我们再把相应的控制权转到 139 00:07:00,680 --> 00:07:03,760 读进来的操作系统内核代码上 140 00:07:03,800 --> 00:07:06,800 我们操作系统就可以开始运行的 141 00:07:06,840 --> 00:07:09,200 我们在BIOS还要提供一些什么样的功能 142 00:07:09,240 --> 00:07:10,960 基本的输入 输出功能 143 00:07:11,000 --> 00:07:12,480 比如说我们需要知道 144 00:07:12,520 --> 00:07:16,040 如何在屏幕上显示基本的信息 145 00:07:16,080 --> 00:07:19,240 然后我从磁盘上读写扇区 146 00:07:19,280 --> 00:07:22,200 那我能知道我的内存有多大 147 00:07:22,240 --> 00:07:25,520 我能从键盘上读用户的输入 148 00:07:25,560 --> 00:07:28,560 当然在这里BIOS只能提供最简单 149 00:07:28,600 --> 00:07:30,880 最基本的输入 输出功能 150 00:07:30,920 --> 00:07:33,720 并且它的使用也受到很大的限制 151 00:07:33,760 --> 00:07:36,440 比如说在我们的英特尔的CPU上 152 00:07:36,480 --> 00:07:37,520 它受到一条限制 153 00:07:37,560 --> 00:07:41,920 就是你只能是在实模式下工作 154 00:07:41,960 --> 00:07:44,680 那如果说我们的操作系统是工作在保护模式下 155 00:07:44,720 --> 00:07:46,520 那这些就都不可以用了 156 00:07:46,560 --> 00:07:46,600