相信很多人都有一个自己制作操作系统的梦想吧。我们在文章中介绍了制作一个只能显示字符的“操作系统”,今天往后,我们要学习用汇编 + C语言制作一个简单的操作系统。 这篇文章的标题叫做了解基础知识,所以我们就先不放代码了。 既然是基础知识,我们就要先了解我们的“敌人”,就是硬件。 电脑中最主要的就是CPU了,它是干什么的大家肯定都知道的。那么,它是怎么工作的呢? 说白了,CPU就是个算数的。一个算数的必须有以下功能: 能算数 能记住数 能控制自己 CPU其实大体就可以分成这几个部分,但它不这么叫,CPU的各个部件名称分别是: 寄存器——记住数 运算器——算数 控制器——控制自己 其中,控制器是最重要的。不管一个人多么聪明,有多么厉害的大脑,不能控制自己就一点用都没有。 CPU这三个部件中,由总线相连。总线又可以分为数据总线、控制总线和地址总线。数据总线用于传输数据,控制总线用于传输命令,地址总线用于传输地址(分不清管脚和总线了,欢迎指出错误)。数据总线就决定了CPU的位数,例如,64位CPU数据总线的宽度是64Bits,一次可以传输8Bytes的数据。 CPU虽然厉害,但是它的寄存器却没有多大,全部都用上也不够(当然,这里面还有一些不是用于存储数据的,例如IP和SP)所以,人们使用内存来存储一些比较大的数据。 内存这东西就很大了,CPU用总线联络内存。例如,CPU要读取内存地址0x7c00处的指令,就要这样: CPU 内存 指令总线 -----读取指令---------> 地址总线------地址0x7c00------> 数据总线<-----数据--------------- 然后,CPU就会使用数据总线发来的数据或指令了。 但是,内存很大,CPU不一定都可以用啊?这是因为,8086CPU只有16根数据总线,它只可以保存或传输(CPU要使用数据必须要通过数据总线)0xFFFF以下的数据(0x开头都是16进制的数字)但是8086CPU有20根地址总线,地址总线可以表示0xFFFFF以下的数据(1MB),可CPU却只能表示0xFFFF以下的数据,再大了就没法表示,这样地址总线就浪费了。于是,8086想出了一种表示0xFFFFF以下数据的办法,就是将数据分开表示。 假如CPU需要处理内存地址0x13BC处,那么,他会先将这段地址转换为0x13与0xBC(0x13B和0xC也可以),然后通过一个专门用于计算地址的计算器来计算出结果再传输给地址总线。8086CPU这样特殊的传输方式也被后来的CPU使用。最终计算出的地址叫做物理地址,类似于0x13的地址叫做段地址,类似于0xBC的地址叫做偏移地址。 在8086CPU寻址能力上说了这么多,我们来说说别的吧。 CPU不光只连接着内存一个东西,还连接着类似于硬盘,软盘,键盘之类的。像键盘这种对CPU来说可有可不有的东西一般都叫做外部的,像内存之类的CPU不能缺少的叫做内部的东西。现在,我们先来说一说外部的东西们。 外部的东西主要就是键盘,鼠标(不大用)以及网卡,光驱等等。CPU每一段时间就会去查看这些器件中有没有积攒的数据,如果有就去处理。这是因为在早期的计算机中一般只有键盘这一个外部器件,CPU可以使用这种查询的笨办法。但是,现在的计算机一般都连着鼠标、网卡之类需要CPU快速响应的东西。于是,CPU就换了一种策略,这种策略就叫做中断。计算机又添加了一个叫做中断处理器的东西,它在有中断触发时(例如你按下鼠标)会提醒CPU去工作,这时候CPU就会按照IDT(Interrupt vector table,中断向量表)中写的来调用响应的函数,然后就继续执行刚才的指令。(CPU中,会有专门记录CPU执行到哪里的寄存器,分别是CS和IP)(例如,我们写了一个函数keyboard在键盘按下的时候会显示一行信息,我们只需要将他注册到IDT中就可以了。) 想一想,还有什么关于硬件的没有讲呢……对了,想起来了,我们来看一看什么是GDT吧。 在8086这种CPU中是没有GDT的,32位CPU才会有这种高级的东西。它的全称是Global (Segment) Descriptor Table,全局(段)描述表。它是用于记录CPU的分段的。咦?难道32位CPU懒到这个程度了?连段地址都要操作系统制定?不是的。16位CPU的这种模式有一种专门的名词,叫做实模式,就是说在这种模式下的程序想要访问内存的哪里就可以访问哪里。这样虽然直观,但是一旦病毒潜入操作系统就麻烦了,操作系统无法拦截病毒也无法识别病毒,只能眼睁睁看着系统崩溃(实模式下,程序可以随便访问内存地址而不会遭到拦截。可能导致病毒程序潜入操作系统管理的内存区域破坏)。32位CPU比较高级,可以自动拦截疑似病毒的机器语言程序,这叫保护模式。但是在此之前,为了兼容以前的操作系统,CPU在开机时是处于实模式的。只有操作系统去设置一个名为CR0的寄存器(Control Register 0,0号控制寄存器)。当然,设置之前必须要先设置GDT,这是由于保护模式的CPU依赖GDT的设置。GDT大约由这几部分组成: 段的属性(系统专用与应用程序用。其中还有4个模式详细分类,以后讲解) 段的起始位置(内存地址) 段的大小(不说了,看不懂的自己出去) 设置完这几部分,然后使用汇编语言中GDTR命令就可以设置了。 硬件到此结束,我们现在讲一讲你家电脑是怎么启动的。 首先,你肯定是要连上电而且要按下POWER键。(说不定未来的电脑可以识别你要玩电脑了,就自动启动呢。呵呵) 然后,硬件中一个叫ROM(Read Only Memory,只读存储器(记忆器))中储存的一个叫BIOS(Basic Input Output System,基本输入输出系统)的东西会先检查硬件。(别看他名字觉得就是个输入输出系统,以后很长一段时间内我们都会和他打交道。)如果你没有喂你的电脑吃冰激凌,他就会去你设置的启动方式(硬盘启动、软盘启动、网络启动)来找操作系统。网络启动这玩意儿太高级了,我们不讲,硬盘和软盘这两个东西很相似,我们这次要用这个。 硬盘这东西,你想像内存地址一样问他“给我0x7c00处的东西”,他会打你的。他使用磁道、扇区与磁头表示一个扇区(一般为512字节,这是硬盘的最小单元)。例如,5磁道8扇区第0个磁头,磁盘才会忍住不打你。这里的磁道,扇区与磁头请看下面这篇文章。 看完了吗?这下应该明白了吧? BIOS好像很懒,他会从第0磁道的第1扇区用第0磁头读取一个扇区(512字节)的数据,然后判断这些数据的结尾是不是0xaa和0x55,如果是的话就认定这是一个启动层,就会将这段数据(代码)放到内存中,再让CPU执行内存地址0x7c00处的代码。(我们可以使用指令org来确保这段代码会被加载到内存地址0x7c00处,然后就是变相的让CPU执行这段代码)由于一个扇区只用512字节,还要以0xaa与0x55两个字节结尾,那么我们只可以写一个扇区512字节 - 0xaa和0x55两个字节 = 510字节的代码。然后写入到磁盘第0磁道第1扇区,这样,使用这个磁盘做启动盘就可以了成功让CPU执行我们的代码了。 将这段代码放到磁盘的第零磁道第一扇区,然后启动,应该不会报No Boot Found的错误了。 今天我们就聊这么多,下次继续。 (责任编辑:) |