自由软件社区是一个充满自由和梦想的地方在余年的时间里它创造了一个又一个奇迹然而这些奇迹的创造者不只是Stallman也不只是Linus Torvalds而是活跃在世界各地的不计其数的开发人员 在使用各种功能强大的自由软件时我总会对其开发者充满崇敬之情期盼有朝一日自己也能成为他们中的一员很多对自由社区充满向往之情的人虽然也想努力融身于其中但又不知该怎么做那么就请与我们一起从编写一个简单的操作系统开始吧! 我们要做的事情 有人可能担心自己既没有学过计算机原理也没有学过操作系统原理更不懂汇编语言对C语言也一知半解能写操作系统吗?答案是没问题我将带大家一步一步完成自己的操作系统当然如果学一学上述内容再好不过 首先要明确处理器(也就是CPU)控制着计算机对PC而言启动的时候CPU都处在实模式状态相当于只是一个Intel 处理器也就是说即使你现在拥有一个奔腾处理器它的功能也只能是级别从这一点上来讲可以使用一些软件把处理器转换到着名的保护模式只有这样我们才可以充分利用处理器的强大功能 编写操作系统开始是对BIOS控制取出存储在ROM里的程序BIOS是用来执行POST(Power On Self Test自检)的自检是检查计算机的完整性(比如外设是否工作正常键盘是否连接等)这一切完成以后你就会听到PC喇叭发出一声清脆的响声如果一切正常BIOS就会选择一个启动设备并且读取该设备的第一扇区(即启动扇区)然后控制过程就会转移到指定位置启动设备可能是一个软盘光盘硬盘或者其它所选择的设备在此我们把软盘作为启动设备如果我们已经在软盘的启动扇区里写了一些代码这时它就被执行因此我们的目的很明确就是往软盘的启动扇区写一些程序 首先使用汇编来写一个小程序然后将其拷贝至软盘的启动扇区为了实现拷贝要写一个C程序最后使用软盘启动计算机 需要的工具 ● as这是一个汇编程序它负责把写的代码转换成目标文件 ● ld这是一个连接器as产生的目标代码由它来转换成真正的机器语言机器语言是能够解读的形式 ● GCC着名的C编程器因为我们需要写一个C程序将自己的OS转移到软盘中 ● 一张空软盘它用于存储编写的操作系统也是启动设备 ● 一台装有Linux的计算机这台机器可以很旧都可以 在大部分标准Linux发行版中都会带有as和ld在我使用的Red Hat 中就包含有这两个工具并且在默认的情况下它已经安装在机器里如果使用的Linux没有这两个工具可以从网上下载(~mayday/)这两个工具都包含在一个名为bin的软件包中此外有关的文档也可以在网上获得(/docs/ldp/howto/AssemblyHOWTO/l) 开始工作 使用一个你喜欢的编辑器输入以下内容 entry start start: mov ax#xb mov esax seg es mov []#x seg es mov []#xf loop: jmp loop 这是as可以读懂的一段汇编程序第一个句子指明了程序的入口点声明整个过程从start处开始第二行指明了start的位置说明整个程序要从start处开始执行xb是显存的开始地址#表明其后是一个立即数执行语句 mov ax#oxb ax寄存器的值就变为xb这就是显存的地址下面再将这个值移至es寄存器es是附加段寄存器请记住有一个分段的体系结构它的各段寄存器为代码段数据段堆栈段和附加段对应的寄存器名称分别为csdsss和es事实上我们把显存地址送入了附加段因此任何送入附加段的东西都会被送到显存中 要在屏幕上显示字符就需要向显存中写两个字节前一个是所要显示字符的ASCⅡ值第二个字节表示该字符的属性属性包括字符的前景色背景色及是否闪烁等等seg es指明下一个将要执行的指令是指向es段的所以我们把值x(在ASCⅡ中表示的字符是A)送到显存的第一个字节中接下来要把字符的属性送到下一个字节当中在此输入的是xf该属性指的是在蓝色背景下显示白色的字符因此如果执行这个程序就可以在屏幕上得到显示在蓝底上的一个白色的A接着是一个循环因为在执行完显示字符的任务后要么让程序结束要么使用一个循环使其永远运行下去把该文件命名为boots然后存盘 此处显存的概念说得不是很清楚有必要进一步解释一下假设屏幕由列×行组成那么第一行就需要字节其中一个字节用于表示字符另外一个字节用于表示字符的属性如果要在第三行显示某一字符的话就要跳过显存的第和字节(它们是用于显示第列的)第和字节(它们是用于显示第列的)然后把需要显示字符的ASCⅡ码值入第字节把字符的属性写入第字节 把程序写至启动扇区 下面写一个C程序把我的操作系统写入软盘第一扇区程序内容如下 #include <sys/typesh> /* unistdh 需要这个文件 */ #include /* 包含有read和write函数 */ #include int main() { char boot_buf[]; int floppy_desc file_desc; file_desc = open(/boot O_RDONLY); read(file_desc boot_buf ); close(file_desc); boot_buf[] = x; boot_buf[] = xaa; floppy_desc = open(/dev/fd O_RDWR); lseek(floppy_desc SEEK_CUR); write(floppy_desc boot_buf ); close(floppy_desc); } 首先以只读模式打开boot文件然后在打开文件时把文件描述符复制到file_desc变量中从文件中读取个字符或者读取直到文件结束在本例中由于文件很小所以是读取至文件结束然后关闭文件 最后行代码打开软盘驱动设备(一般来说是/dev/fd)使用lseek找到文件开始处然后从缓沖中向软盘写个字节 在readwriteopen和lseek的帮助页中可以看到与函数所有有关的参数及其使用方法程序中有两行比较难懂 boot_buf[] = x; boot_buf[] = xaa; 该信息是用于BIOS的如果它识别出该设备是一个可启动的设备那么在第和的位置该值就应该是x和xaa程序会把文件boot读至名为boot_buf的缓沖中它要求改变第和第字节然后把boot_buf写至软盘之上如果执行代码软盘上的前字节就包含了启动代码最后把文件存为writec 编译运行 使用下面的命令把文件变为可执行文件 as boots o booto ld d booto o boot cc writec o write 首先将boots文件编译成目标文件booto然后将该文件连接成最终的boot文件最后C程序编译成可执行的write文件 插入一个空白软盘运行以下程序 /write 重新启动电脑进行BIOS的界面设置并且把软盘设为第一个启动的设备然后插入软盘电脑从软盘上启动 启动完成后在屏幕上可以看到一个字母A(蓝底白字)启动速度很快几乎是在瞬间完成这就意味着系统已经从我们制作的软盘上启动了并且执行了刚才写入启动扇区的程序现在它正处在一个无限循环的状态所以如果想进入Linux必需拿掉软盘并且重启机器 至此这个操作系统就算完成了虽然它没有实现什么功能但是它已经可以启动机器了 下一期我将在这个启动扇区程序里加入一些代码使它可以做一些比较复杂的事情(比如使用BIOS中断保护模式切换等等) |