【程序编程相关:两条命令彻底修复动态链接库】
【推荐阅读:即时日志记录:使用 Jabber 增强 】
【扩展信息:帮你免于失业的十大软件技术(转)】
说明:
qq:13916830 email:xieyubo@126.com 欢迎来信指教,如转载请注明作者及出处. 下载原文(pdf) 源代码下载原文:http://purec.binghua.com/article/class6/class7/200411/81.html
注: 此文发表在<<纯c论坛·电子杂志>>2004.10期上 (http://purec.binghua.com/soft/class2/dl_hpcem/200410/74.html) 操作系统引导探究 (version 0.02) 哈尔滨工业大学计算机体系结构实验室 谢煜波(xieyubo@126.com) version 0.02修改记录: 对与gdt有关的段描述符方面的描述进行了修订,更正了上一个版本中出现的一些错误,增加了一些描述,使其更完善. 与上个版本中不同的地方均用红色标记. 前言 本篇文章并不旨在完整的讨论一个多引导系统程序怎样去引导不同的操作系统,而只打算从编写操作系统的角度出发,谈谈计算机怎样从加电开始,从无到有,将操作系统运行起来,在其中将尽量详尽的描述从实模式到保护模式的过渡,目的只在于能将所学与广大爱好者共享,为希望开发操作系统的朋友留下一点资料,也为自己留下一点心得. 本篇文章将以开发中的pyos系统引导程序为例,pyos是一个正在开发中的实验型操作系统,它并不打算以目前任何一种运行中的操作系统为模式,而只想通过自己编写一个从头到尾的操作系统来学习知识,积累技术,如果你有兴趣,非常欢迎你的加入! 本篇纯属学习过程中的一点心得体会,如果你发现其中有错误或不当之处,非常希望你来信指教. 一.计算机从加电开始都做了什么? 当机算机的电源键被按下时,同这个键相联的电信号线就会送出一个电信号给主板,主板将此电信号传给供电系统,供电系统开始工作,为整个系统供电,并送出一个电信号给bios,通知bios供电系统已经准备完毕.随后bios启动一个程序,进行主机自检,主机自检的主要工作是确保系统的每一个部分都得到了电源支持,内存储器.主板上的其它芯片.键盘.鼠标.磁盘控制器及一些i/o端口正常可用,此后,自检程序将控制权还给bios.接下来bios读取bios中的相关设置,得到引导驱动器的顺序,然后依次检查,直到找到可以用来引导的驱动器(或说可以用来引导的磁盘,包括软盘.硬盘.光盘等),然后调用这个驱动器上磁盘的引导扇区进行引导.bios是怎么知道或说分辨哪一个磁盘可以用来引导的呢? 二.认识引导程序 bios将磁盘的第一个扇区(磁盘最开始的512字节)载入内存,放在0x0000:0x7c00处(见图三),如果这个扇区的最后两个字节是“55 aa”,那么这就是一个引导扇区,这个磁盘也就是一块可引导盘.通常这个大小为512b的程序就称为引导程序(boot).如果最后两个字节不是“55 aa”,那么bios就检查下一个磁盘驱动器. 通过上面的表述我们可以总结出如下三点引导程序所具有的特点: 1. 它的大小是512b,不能多一字节也不能少一字节,因为bios只读512b到内存中去. 2. 它的结尾两字节必须是“55 aa”,这是引导扇区的标志. 3. 它总是放在磁盘的第一个扇区上(0磁头,0磁道,1扇区),因为bios只读第一个扇区. (图一) 因此,在我们编写引导程序的时候,我们也必须注意上面的三点原则,符合上面三点原则的程序都可以看作是引导程序,至少bios是这样认为的,虽然它也许可能是你随意写的一段并没有什么实际意义的代码. 因为bios一次只读一个扇区也即512字节的数据到内存中,这显然是不够的,现在操作系统都比较庞大,因此我们必须在引导扇区里,将存在磁盘上的操作系统的核心部分读进内存,然后再跳转到操作系统的核心部分去执行. 三.通过bios读磁盘扇区 从上面的描述我们可以知道,引导程序需要将存在于磁盘上的操作系统读入内存,因此这里我们不得不再讲一讲,怎样不通过操作系统(因为现在还没有操作系统)去读取磁盘上的内容.一般说来这有两种方法可以实现,一种是直接读写磁盘的i/o端口,一种是通过bios中断实现.前一种方法是最低层的方法(后一种方法也是在它的基础上实现的),具有极高的灵活性,可以将磁盘上的内容读到内存中的任意地方,但编程复杂.第二种方法是前一种方法稍微高层一点的实现,牺牲了一点灵活性,比如,它不能把磁盘上的内容读到0x0000:0x0000 ~ 0x0000:0x03ff处.为什么不能读到此处呢?这里我们将不得不描述一下cpu在加电后的中断处理机制. 3.1 bios的中断处理 中断是什么?相信学过计算机的人都不会陌生,如果你对中断一点都不了解建议你翻看一下«计算机组成原理»(高等教育出版社 唐朔飞),上面有非常详尽的描述,而一般的汇编教材也多有谈及,因此这里只打算讲讲bios对中断的处理. (图二) 由上图(图二)我们可以清楚的看到,当中断信号产生时,中断信号通过“中断地址形成部件”产生一个中断向量地址,此向量地址其实就是指向一个实际内存地址的指针,而这个实际内存地址中往往安排一条跳转指令(jmp)跳转到实际处理此中断的中断服务程序中去执行.这一块专门用于处理中断跳转的内存就被称为中断向量表.在内存中,这块中断向量表被放在什么地方呢?而实际的中断处理程序又在什么地方呢? 3.2 系统的内存安排(1m) 要回答上面的两个问题,我们需要看看系统中内存是怎么安排的.在cpu被加电的时候,最初的1m的内存,是由bios为我们安排好了的,每一字节都有特殊的用处. (图三) 由上图我们现在可以很方便的问答上面提出的两个问题.由于0x00000~0x003ff是中断向量表所在,因此不能将磁盘中的操作系统读到此处,因为这样会覆盖中断向量表,就无法再通过bios中断读取磁盘内容了.你也许会说:我是先调用中断,再读的啊.但事实上bios在读的过程中自己会多次调用其它中断辅助完成. 3.3 利用bios 13号中断读取磁盘扇区 有了前面的描述作为基础,下面我们可以正式描述怎样通过bios中断读取磁盘扇区了.要读取磁盘扇区,我们需要使用bios的13号中断,13号中断会将几个寄存器的值作为其参数,因此,我们在调用13号中断的过程中需要首先设置寄存器.那么当怎样设置寄存器呢?会用到哪些寄存器呢?请往下看: ah寄存器:存放功能号,为2的时候,表示使用读磁盘功能 dl寄存器:存驱动器号,表示欲读哪一个驱动器 ch寄存器:存磁头号,表示欲读哪一个磁头 cl寄存器:存扇区号,表示欲读的起始扇区 al寄存器:存计数值,表示欲读入的扇区数量 在设置了这几个寄存器后,我们就可以使用 int 13这条指令调用bios 13号中断读取指定的磁盘扇区,它将磁盘扇区读到es:bx处,因此,在调用它之前,我们实际上还需要设置es与bx寄存器,以指出数据在内存中存放的位置. 四.保护模式下,段模式内存地址的访问 写程序离不开对内存的访问,然而在保护模式下内存的访问与在实模式下内存的访问完全不同,这里我们将详细描述一下保护模式下内存的访问方法.... 下一页