最近在学习操作系统原理,也想尝试下如何编写一个操作系统,就查阅了相关资料,进行一番总结。
网络上有很多伟大的同志们,帮我们详细的讲解了操作系统从电脑加电后到引导启动,都进行了哪些操作。我在这里将整理的资料一一列举:
最基本的当然是从软盘上加载启动的方式了,最为代表的是国外MikeOS的制作教程,这篇博文是其中的翻译:
怎样写一个简单的操作系统?(原文标题:How to write a simple operating system)
其主要实现方式是解析FAT12软盘文件格式,加载其中的数据文件,实现的引导启动。
同样采用软盘引导的方式的:
大家一起写操作系统系列
这里的资料讲解了基本原理:
操作系统的安装与启动基本原理
还有更为神奇的是,还能用C#开发操作系统了:
打破传统,C#也能开发操作系统!
这个叫Cosmos(译为宇宙)的系统,从名字是就霸气威武,其实现方式也很厉害,通过开发了一款汇编器,将C#中间代码IL,编译成了机器码。而且他集成了C#模块化思想,做成了操作系统开发套件的形式,用户可以直接从VS上组织并编译它们。
下面是重头戏,我最推荐使用的方式,依然使用C语言开发,但使用Grub或isolinux进行引导,这样既避免了引导过程的使用汇编语言繁琐的操作硬件,又能直接为你导入C语言进行开发,体验操作系统中最核心的管理操作。
内核代号101 — 动手写自己的内核
这篇文章强烈推荐,实现简单明了,可能是最简单的内核引导方式,我在Github上也按照其方法搭建了一个简单的项目,大家也可以在上面继续开发:
https://github.com/sunxfancy/MoonOS
用SYSLINUX或ISOLINUX制作启动U盘或光盘
这篇文章重点讲解了启动盘的制作方法,我安装其方法,也成功配置成功了一个iso镜像,放置到了虚拟机中引导自己的内核启动,当然linux下有更简单的方式,用这样一句简单的指令也可以实现测试内核的功能,当然,你得先安装qemu虚拟机:
qemu-system-i386 -kernel kernel.elf
另外再推荐一个重要的资源网站,国外的http://wiki.osdev.org站,最权威的操作系统开发帮助网站。
从操作系统的引导谈起
操作系统,也是由伟大的程序猿们码出来的,首先要坚信这一点。在裸机上你无法进行内存的动态分配,多任务的调度,硬件的协调,这些都是需要操作系统进行管理。但操作系统也不是万能的,他也是需要依赖硬件和体系架构的,没有对应的体系,操作系统也无法工作。
操作系统主要就这几大目标:
- 多任务调度,让只有为数不多的核心的CPU分给多个任务跑,同时执行多个进程或线程。
- 内存管理,Intel x86-64架构下,内存是按照分段和分页的形式组织的,所谓分段,就是管理不同的数据段、代码段、栈段等,分页则是为了将不同的进程的虚拟地址分开,让其不互相影响。
- 硬件管理,设计不同种类的硬件驱动,将硬件抽象成较为方便使用的形式,供操作系统上层程序员使用,方便应用开发。
- 提供用户交互手段,无论是GUI还是控制台,都是交互方式。
- 设计系统调用,将用户态程序和内核态完全分开。
明确的操作系统的任务,那么我们要看,如何进行操作系统的开发呢?
当然首先,要把内核引导启动,并切换到32位模式下,运行操作系统的入口函数kmain()
,然后操作系统根据硬件架构,初始化各个部件,加载驱动,加载图像界面和用户交互。
那么我们从引导开始,我的环境是Ubuntu14.04版,如果手写一个引导程序,首先要安装必要的汇编器,这里我们使用nasm,因为新版的intel汇编语法比较简洁好看。
sudo apt-get install nasm
同时安装qemu虚拟机用来测试:
sudo apt-get install qemu
我们打包好iso文件后,我们可以这样用qemu测试iso文件的引导:
qemu-system-i386 -cdrom test.iso -boot d
-boot的参数一定要选d,a是软盘,c是硬盘,d是光盘
当然,如果你只是想测试内核,并且你的内核支持Multiboot格式,那么你也可以像上面讲的方式一样,用一句话引导内核程序:
qemu-system-i386 -kernel kernel.elf
引导程序是什么原理呢?首先操作系统不能自己把自己拉起来,因为没有加电前,电脑内存中是空的。这个过程叫bootstrap,
bootstrap这个词一直译为”自举”,源于英文中的一个搞笑谚语:”想通过提拉鞋带将自己提升离开地面的可笑
企图”,这说明了操作系统的尴尬情况。这个问题是通过硬件电路解决的,主板bios在上电后,会根据bios中的设置顺序扫描几个储存介质,硬盘、光驱、usb等等,找到第一个有引导区的介质,然后将其第一个扇区内的部分加载到0x7c00的位置,然后初始化寄存器,让指向代码的ip寄存器,指向该位置,然后程序开始运行。
如果要编写可引导的程序呢,就要用nasm汇编了,编写一个简单的在裸机上直接跑的程序。
;bootstrap.asm
BITS 16
start:
jmp main
;***************