一个操作系统的实现(1)-准备工作

来源:互联网 发布:网络歌曲你是我的唯 编辑:程序博客网 时间:2024/04/30 07:15

今天开始看《Orange’S:一个操作系统的实现》一书。这里是ubuntu 16.04下开发环境的搭建以及实现一个最小的操作系统(准确地说应该是一个引导扇区)。

工欲善其事,必先利其器。自制一个操作系统需要的工具如下:

  • 汇编编译器NASM
  • 虚拟机算计Bochs
  • 软盘绝对扇区读写工具(这里直接使用强大的dd

现在就来安装这些工具

安装NASM

通过源代码安装,官网下载最新版源代码,当前最新的是nasm-2.12.01版本,下面的内容以此来演示。

个人软件一般安装到/usr/local,所以压缩包解压到/usr/local

tar zxvf nasm-2.12.01.tar.gzcd nasm-2.12.01./configuremakesudo make install

安装Bochs

首先官网下载最新版源代码。当前最新的是bochs-2.6.8版本,下面的内容以此来演示。

不用ubuntu的包管理软件来安装一方面原因是包管理安装的不一定是最新版,另一方面原因是包管理默认安装的可能没有调试功能。

个人软件一般安装到/usr/local,所以压缩包解压到/usr/local

接下来按照如下步骤安装:

tar zxvf bochs-2.6.8.tar.gzcd bochs-2.6.8./configure --enable-debugger --enable-disasmmakesudo make install
安装过程中我遇到了如下错误
fatal error: X11/Xlib.h: No such file or directoryfatal error: X11/extensions/Xrandr.h: No such file or directory
这是由于缺少必要的依赖库。网上查找资料得到:第一行依赖于库libx11-dev,第二行依赖于库libxrandr-dev 因此分别安装这两个库即可解决问题:
sudo apt-get install libx11-dev libxrandr-dev
然后继续按照上面的步骤安装即可成功。

工具安装好了,下面通过一个输出`Hello, OS world!`的操作系统来对操作进行演示。 ## 一个简单的源程序 首先必须有源代码:
    org 07c00h    mov ax, cs    mov ds, ax    mov es, ax    call DispStr    jmp $DispStr:    mov ax, BootMessage    mov bp, ax    mov cx, 16    mov ax, 01301h    mov bx, 000ch    mov dl, 0    int 10h     ret BootMessage:    db  "Hello, OS world!"times   510-($-$$)  db  0dw  0xaa55

要理解这段代码,首先要会汇编(废话),其次要知道计算机启动操作系统的过程。

当计算机电源被打开时,首先进行加电自检(POST),然后寻找启动盘,如果是选择从软盘启动,计算机就会检查软盘的0面0磁道1扇区,如果发现此扇区以0xAA55结束,那么BIOS就认为它是一个引导扇区。一旦BIOS发现引导扇区,它就会将这512字节的内容装载到内存地址0000:7c00处,然后跳转到0000:7c00处将控制权彻底交给这段引导代码。到此位置,计算机不再由BIOS中固有的程序来控制,而变成操作系统的一部分来控制。

了解了启动过程,再来看上面的程序。

org 07c00horg是一个伪指令,这行代码告诉编译器,将来这段程序要被加载到内存偏移地址0x7c00h处。

mov ax, csmov ds, axmov es, ax:使dses两个段寄存器指向与cs相同的段,以便以后在进行数据操作的时候能定位到正确的位置。

call DispStr:调用子程序DispStr,子程序以ret返回。

int 10h:是BIOS提供关于屏幕和显示器操作的程序。他前面4行都使用来设置参数的。AH=13h表示调用显示字符串的子程序。这时ES:BP = 串地址、CX = 串长度 、DH, DL = 起始行列、BH = 页号、AL=01h时BL表示显示属性。

jmp $:这里的$表示当前行被汇编后的地址。举个例子,将汇编编译生成的二进制文件反汇编,形成下面的代码:

00007c09    EBFE        jmp short 0x7c09

在这里是实现无线循环的功能。

times 510-($-$$) db 0:这里的$$表示一个节(section)的开始处被汇编后的地址。这个程序只有一个节,所以$$表示的是程序被编译后的起始地址,也就是0x7c00。因此$-$$表示的是本行距离程序开始处的相对距离。这句话的意思是将512字节中剩下的部分赋值为0(最后两个字节除外)。

dw 0xaa55:将最后两个字节赋值为0xaa55,让BIOS把此扇区当作引导扇区,从而将此扇区装入内存0000:7c00处得到执行。

这段代码的大致功能就是这些,接下来就是如何使用Bochs引导并执行它。虚拟机当然不能引导源程序,执行上面的程序首先必须将其编译并制成软盘启动盘。

将源程序编译成可执行文件制作启动盘

使用NASM编译

安装好了NASM,源程序的编译过程一行命令搞定

nasm boot.asm -o boot.bin

这样就得到了一个512字节的boot.bin。接下来需要一个虚拟软盘存放上面的启动程序(放在扇区的0面0磁道1扇区,上面有介绍)

生成虚拟软盘

生成虚拟软盘使用的是Bochs组件中的一个工具:bximage,它既可以生成虚拟软盘,还可以生成虚拟硬盘(虚拟磁盘也被成为磁盘映像)。创建一个软盘映像的过程如下:

$ bximage ========================================================================                                bximage  Disk Image Creation / Conversion / Resize and Commit Tool for Bochs         $Id: bximage.cc 12690 2015-03-20 18:01:52Z vruppert $ ========================================================================1. Create new floppy or hard disk image2. Convert hard disk image to other format (mode)3. Resize hard disk image4. Commit 'undoable' redolog to base image5. Disk image info0. QuitPlease choose one [0] 1 <<输入1,代表创建一个软盘或硬盘映像Create imageDo you want to create a floppy disk image or a hard disk image?Please type hd or fd. [hd] fd <<输入fd,代表软盘Choose the size of floppy disk image to create, in megabytes.Please type 160k, 180k, 320k, 360k, 720k, 1.2M, 1.44M, 1.68M, 1.72M, or 2.88M. [1.44M] <<直接回车,默认左边内容What should be the name of the image?[a.img] <<直接回车,默认左边内容Creating floppy image 'a.img' with 2880 sectorsThe following line should appear in your bochsrc:  floppya: image="a.img", status=inserted

最后提示你在bochsrc中如何进行配置,到现在为止可执行程序(计算机)好了,虚拟软盘也好了,接下来就是将计算机写入虚拟软盘中了

将引导扇区写进软盘中

linux下使用dd命令:

dd if=boot.bin of=a.img bs=512 count=1 conv=notrunc
其中: `bs=512`:bs是用来规划一个block的大小,如果未指定则默认是512Bytes(一个扇区的大小) `count=1`:多少个bs的意思 `conv=notrunc`:如果不用它的话,软盘映像文件a.img会被截断(truncated),因为boot.bin比a.img小。 现在一切准备就绪了,接下来就是打开计算机电源,调试运行啦。 ## 如何用Bochs进行调试 Bochs是一个虚拟计算机,既然是虚拟计算机,首先要对他进行配置,告诉他你需要的计算机内存是多大的,硬盘映像和软盘映像都是那些文件等等。我的配置如下:
#################################################################### Configuration file for Bochs#################################################################### how much memory the emulated machine will havemegs: 32# filename of ROM imagesromimage: file=/usr/local/bochs-2.6.8/bios/BIOS-bochs-latest, address=0xfffe0000vgaromimage: file=/usr/local/bochs-2.6.8/bios/VGABIOS-elpin-2.40# what disk images will be usedfloppya: 1_44=/home/zpl/coding/os/a.img, status=inserted# choose the boot diskboot: floppy# where do we send log message?log: bochsout.txt# disable the mousemouse: enabled=0# enable key mapping, using US layout as defaultkeyboard: type=mf, serial_delay=200, paste_delay=100000

romimagevgaromimage指定的文件对应的其实就是真实机器的BIOS和VGA BIOS。

floppya指定的是使用哪个文件作文软盘的映像

为了避免错误,上述的文件最好以绝对路径的方式给出

现在只做了最简单的一些配置,详细的配置参考官方手册,讲的很详细。

接下来打开bochs并调试:

$ bochs ========================================================================                       Bochs x86 Emulator 2.6.8                Built from SVN snapshot on May 3, 2015                  Compiled on May 13 2016 at 04:39:37 ========================================================================00000000000i[      ] BXSHARE not set. using compile time default '/usr/local/share/bochs'00000000000i[      ] reading configuration from .bochsrc ------------------------------Bochs Configuration: Main Menu ------------------------------This is the Bochs Configuration Interface, where you can describe themachine that you want to simulate.  Bochs has already searched for aconfiguration file (typically called bochsrc.txt) and loaded it if itcould be found.  When you are satisfied with the configuration, goahead and start the simulation.You can also start bochs with the -q option to skip these menus.1. Restore factory default configuration2. Read options from...3. Edit options4. Save options to...5. Restore the Bochs state from...6. Begin simulation7. Quit nowPlease choose one: [6] <<这里选择功能菜单00000000000i[      ] installing x module as the Bochs GUI00000000000i[      ] using log file bochsout.txtNext at t=0(0) [0x0000fffffff0] f000:fff0 (unk. ctxt): jmpf 0xf000:e05b          ; ea5be000f0<bochs:1> b 0x7c00<<在内存0x7c00处设置断点<bochs:2> c<<运行到下一个断点处(此处是0x7c00)(0) Breakpoint 1, 0x00007c00 in ?? ()Next at t=29625394(0) [0x000000007c00] 0000:7c00 (unk. ctxt): mov ax, cs                ; 8cc8<bochs:3> n<<向下执行一不步Next at t=29625395(0) [0x000000007c02] 0000:7c02 (unk. ctxt): mov ds, ax                ; 8ed8<bochs:4> nNext at t=29625396(0) [0x000000007c04] 0000:7c04 (unk. ctxt): mov es, ax                ; 8ec0<bochs:5> nNext at t=29625397(0) [0x000000007c06] 0000:7c06 (unk. ctxt): call .+2 (0x00007c0b)     ; e80200<bochs:6> trace-reg on<<让Bochs每走一步都显示主要寄存器的值Register-Tracing enabled for CPU0<bochs:7> nNext at t=29626661eax: 0x00001301 4865ecx: 0x00090010 589840edx: 0x00000000 0ebx: 0x0000000c 12esp: 0x0000ffd6 65494ebp: 0x00007c1e 31774esi: 0x000e0000 917504edi: 0x0000ffac 65452eip: 0x00007c09eflags 0x00000082: id vip vif ac vm rf nt IOPL=0 of df if tf SF zf af pf cf(0) [0x000000007c09] 0000:7c09 (unk. ctxt): jmp .-2 (0x00007c09)      ; ebfe<bochs:8> x /64xb 0x7c00<<查看0x7c00开始的64字节内存[bochs]:0x00007c00 < bogus+       0> :    0x8c    0xc8    0x8e    0xd8    0x8e    0xc0    0xe8    0x020x00007c08 < bogus+       8> :    0x00    0xeb    0xfe    0xb8    0x1e    0x7c    0x89    0xc50x00007c10 < bogus+      16> :    0xb9    0x10    0x00    0xb8    0x01    0x13    0xbb    0x0c0x00007c18 < bogus+      24> :    0x00    0xb2    0x00    0xcd    0x10    0xc3    0x48    0x650x00007c20 < bogus+      32> :    0x6c    0x6c    0x6f    0x2c    0x20    0x4f    0x53    0x200x00007c28 < bogus+      40> :    0x77    0x6f    0x72    0x6c    0x64    0x21    0x00    0x000x00007c30 < bogus+      48> :    0x00    0x00    0x00    0x00    0x00    0x00    0x00    0x000x00007c38 < bogus+      56> :    0x00    0x00    0x00    0x00    0x00    0x00    0x00    0x00<bochs:9> 

在运行到jmp指令时即可出现如下界面:

看,左上角我们写的Hello,OS world!。到这里,一个最简单的操作系统实现出来了。关于Bochs调试的参数,以后详细介绍。


0 0
原创粉丝点击