拼一个自己的操作系统(SnailOS 0.03的实现)

拼一个自己的操作系统 SnailOS 0.03的实现

拼一个自己的操作系统SnailOS0.03源代码-Linux文档类资源-CSDN下载

操作系统SnailOS学习拼一个自己的操作系统-Linux文档类资源-CSDN下载

SnailOS0.00-SnailOS0.00-其它文档类资源-CSDN下载

准备一些工具软件包吧

 

https://pan.baidu.com/s/19tBHKyzOSKACX-mGxlvIeA?pwd=i889

 

相信“工欲善其事必先利其器”这句话在大家的耳朵里已经磨出了茧子。不过无论如何拼操作系统都是有点小难度的事情。我们也不能例外,要是打一场无准备之丈,失败的后果对于我这样脆弱的心灵的人恐怕是无法承受的。

啰嗦了这么多,还是让给大家展示一个我们精挑细选浓缩精华的工具清单。

Bochs-win64-2.6.11.exe

dd.exe

mingw-get-setup.exe

nasm-2.15.05-installer-x64.exe

npp.8.1.4.Installer.x64.exe

ue_chinese.exe

UQiDong_STA_bd.exe U启动U盘启动盘制作工具

VirtualBox-6.1.34-150636-Win.exe

Windows7以上自带分区工具diskpart、copy、move

Grub2.06

 

 

嗯,就是清单上的这几种工具了,这些就可能完全够用了,而且是分别针对两种开发环境的。Bochs和virtualbox是虚拟机软件,也就是在windows上模拟PC机裸机的软件。当然,这些年的这类软件层出不穷,据说还有一款国产的。本来想支持国货来的,不过真的是用惯了这两种比较早的虚拟机,特别地懒得迁移到新的产品上去。dd.exe和diskpart、copy、move软件是将编译好的内核文件拷贝到硬盘镜像文件的必备工具,它们能够很大程度地提高开发平台的自动化率(吹吹小牛了)。Mingw和nasm分别是汇编和C语言的编译器,内核的所有代码的编译都是它们的功劳。notepad++和ue是文本编辑软件,同时ue还是一款二进制查看和编辑软件,这类软件真的是数不胜数了,你甚至可以使用windows自带的记事本,当然效率上就毁誉参半了。U启动是一款用于生成winpe启动引导镜像iso文件的软件。有了它我们可以极其方便地将grub2安装到虚拟机的虚拟硬盘上。而上面提到的grub2是一款符合multiboot2标准的引导加载程序,向unix、linux、windows都可以通过它来引导启动。

 

当然还有必不可少的基本参考书,

30天自制操作系统.pdf

bochs中文用户手册.pdf

CLK-5.0.1-WithCover.pdf

GCC 中文手册.pdf

nasm中文手册.pdf

x86汇编语言 从实模式到保护模式完整版.pdf

[ORANGE’S:一个操作系统的实现].于渊.清晰扫描版.pdf

操作系统真象还原.pdf

汇编语言程序设计.林邦杰.陈明.扫描版.pdf

 

顺便说一下,这些都是之前下载得到pdf版本了,只是书不在跟前的时候方便我自己使用。网上很可能存在版权问题,真心强烈的建议大家购买正版书籍了!同时上面这些书也不是都真正的用到了,这还是要根据大家自己学习的程度了。而且仅仅这些东西,恐怕也还是不够用的,还是以后用到的时候,再一一介绍吧。

 

搭建一个可靠、快捷的工作环境

bochs和dd搭配组成的工作环境

Bochs就是一款模拟x86硬件的软件,它本身能够在Windows等不同的操作系统上运行,而且是一款开源的模拟器,如果你对它的实现感兴趣,可以从网络上轻易下载到源代码。不过,在这里我们更关心它在Windows平台上的安装和应用了。

在Windows平台上,为了应用我们只要直接下载它的二进制包就可以了,通常就是叫做“Bochs-win64-2.6.11.exe”的文件。双击之后,按照提示轻松的就安装完成了,完全是迅雷不及掩耳的速度。这主要是由于这款软件小巧而精致的原因了。顺便说一下,之所以说这款软件好用,主要是因为在Windows上安装完成后,虚拟机是自带调试功能的。这样一来,我们在早期开发中遇到什么棘手的问题,就可以通过出错的指令来判断问题的具体位置,所以说这一点是这款虚拟机软件贴心让人感动的原因。

nasm汇编器的安装和配置

那么下面我们就讲讲和虚拟机是如何跟编译软件以及dd软件密切配合,从而实现开发编译运行环境自动化的。

首先让我们从简单的来说,对了说到这里,差点忘了,我们的汇编和C语言的编译器还都没有安装和配置了。

用到的汇编器是Nasm,它也是一款开源软件,同样的我们也是更关心它的安装和配置。开源的部分留给喜欢编译原理的朋友好了。Windows软件安装的雷同之处就在于,双击然后一路下一步就好了,这也是我偏向于选择Windows原因了,唯一需要我们注意的一点是软件的安装路径,这个路径关系到软件原始位置的查找,也就是在我写作这本书的时候,发现居然找不到软件的安装路径(主要是嫌桌面太乱,把一些常用的快捷方式删除了),因此,在确定路径的时候,颇费周章,搞了好半天。

在我的Windows上,nasm的默认安装路径居然是C:\Users\free2\AppData\Local\bin\,这可让我废了就牛二虎之力才找到它。起因就是自己没有在安装的时候注意安装路径。得到和复制好这个路径后,就可以按照下面的步骤粘贴到系统路径中了。

第1步点击设置

a38e26199381e86813120e26befc86e1.png

第2步点击系统

ac74fbc4a27ca00b1ea59ecde4298b29.png

第3步点击关于

13e5b463d87d8a010b63f194619ac152.png

第4步点击高级设置

4552af7dce8e45ecb3a7b4ae74351998.png

第5步点击环境变量

e220bcd95f176b5d67eb6ce7a08cd3d3.png

第6步点击Path

f1e1425733554066b2e986ebafb3faaa.png

通过新建一个路径的环境变量把“C:\Users\free2\AppData\Local\bin\NASM”添加到系统路径中去,这样做的好处是只要打开命令行,不管默认工作路径是什么,都可以运行我们的软件。这里为什么要这么细致的用贴图来说一下,设置路径环境变量的工作呢?还不是因为接下来的软件的设置都是依葫芦画瓢做出来的,因此,这里的费力当然是为了以后的省力,一劳永逸吗!

接下来用Windows旗标+R,并输入cmd

d3f760e9b903cba39d395753e468f6ee.png

确定后,出现了命令行窗口,输入nasm,确认一下我么们刚才的设置。

8d830f34f90b9f89f4eb6466ddfe598b.png

出现了nasm提示没有输入文件信息,说明安装和设置成功。如果是“'nasm' 不是内部或外部命令,也不是可运行的程序或批处理文件。”的提示,就是刚才的安装或者设置有问题。

mingw套件的安装和配置

Mingw是一款在windows上开发软件的工具集合,也是一款开源软件。下图是双击mingw-get-setup.exe程序弹出的窗口,我们要点击install。

511bba5dcb93cce01fd2bb45aa4faabc.png

下面这张图,唯一需要我们注意的是Installation Directory,我们可以根据喜好安排一个自己满意的路径。

9ecc562c45591b78066fd9d1264637b3.png

当我们按下continue后,如下图系统会自动下载mingw manager,它才是真正的安装程序,当然会是网络安装模式。

5546a7dfc6e28240a511223339abc0ee.png

mingw manager安装完成后,continue按钮才会让我们点击,则进入下图,我们已经标记好了要安装的软件,这个当然是根据实际需要来安装了。

b8368cdf4168b9b2ed1d0b4888ed6ce5.png

在installation菜单下选择apply changes,应用改变。

4be568deff339a334a66ec59a8ad0930.png

接下来点击apply

c0df87b46509a04840cd140267d35450.png

下图就是联网安装了。

8e82bb9f182f8e5b745b54443caa5af8.png

由于网络的问题,mingw的安装还是挺漫长的,而且还会出现一些包不能下载的情况。这时候我们只要点击确定就可以了,大概率不会影响我们的使用。安装完成后,我们应该到软件的bin目录下确认一下是否有gcc.exe、as.exe、ld.exe、objcopy.exe、mingw32-make.exe。这几个软件是我们开发时必要用到的。当然其他软件是否存在依赖关系,我不能确定。所以大家还是不要将哪些认为没有的套件删除。一个值得提醒的问题是,这个软件安装一次后,如果不想升级的话,以后直接复制此目录的所有文件就行了。对于mingw32-make.exe的文件名称太长了。我干脆复制一个,并改名为make.exe,这样以来我们将来的用到make命令时就不用输入那么长的一串字符了。

同样的,安装完成后也需要在windows的环境变量中设置适当的路径。这样才能在命令行的任何路径中使用。

bochs的安装和配置

Bochs虚拟机的安装不想费那么多的笔墨了。主要是安装过程太简单了,只要一路下一步就好了。不过,我们最好把dlx linux demo选上。

352578df57fb31c4b8590fd113dc2e56.png

这样可以免费的得到一份bochsrc.bxrc,这是bochs运行虚拟机的配置文件,我们只要稍作改动就能运行自己的虚拟机了。至于dlx linux真的没啥用,也就这样放着吧。哦,对了不要忘记设置windows的环境变量啊。

dd要放在哪里

在简单介绍工具集合时,我们已经提到了Dd。它是一款能够将文件写入磁盘或磁盘镜像文件扇区的软件。然而它小到只有一个可执行程序。因此,我们可以和上面任意一款软件的可执行文件放在一起,这样就不用单独设置环境变量了。比如,我就把他放在了nasm的目录中。

运行起第1个开发环境

上面这种基于bochs虚拟机的开发环境的所有软件就全部安装完成了,下面我们该测试一下好不好用了。这其实就是围绕命令行和bochsrc.bxrc文件来完成的。让我们从头梳理一下吧。

第1步:准备测试环境需要的所有文件,让我们做个清单吧。

顶级工作目录SnailOS_bochs

子目录bochs位于顶级目录中,其中的文件有:

a.img

b.img

BIOS-bochs-latest

bochsrc.bxrc

c.img

VGABIOS-lgpl-latest

x11-pc-us.map

子目录working位于顶级目录中,其中的文件有:

Makefile

Objcopy_move.cmd

Boot.asm

Q.cmd

为了将来的开发方便,我们新建了一个SnailOS_bochs的目录,并把它作为开发的顶级目录。

SnailOS_bochs中有两个子目录分别是bochs和working。我们的所有工作将在working中完成,而bochs是虚拟机运行起来必须的文件,这些文件我们一旦备齐,就基本上不会改动了。现在让我们一个一个的把它们找出来,从而当成我们开发环境的一部分。先说我自己杜撰的q.cmd文件吧。在working目录中新建一个q.cmd的文本文件,文件的内容如下:

 

%qcmd.cmd 创建者:至强 创建时间:2022年8月%

cmd.exe

 

这个文件简单的没法再简单了吧,就是起到在工作目录中快捷的运行命令行提示符的作用。双击我们就来到命令行,而且工作路径是当前目录。

再来看看Bochs目录中叫*.img的3个文件,它们都是由bochs工具箱中的软件bximage生成的。从名字上我们就可以知道它们分别是A盘、B盘、C盘的镜像文件。可见bximage是一款生成.img格式镜像文件的软件。至于怎么生成还是详见下图吧。

aeaf6c6e4e991904e774d24be14ae9c7.png

和下面的图配合起来看,大家就明明白白了吧。

3a719303848c08e8c8ccbf30019de8c9.png

值得一提的是,上面生成了a.img文件的最后几句英文。

Creating floppy image 'a.img' with 2880 sectors

 

The following line should appear in your bochsrc:

floppya: image="a.img", status=inserted

(The line is stored in your windows clipboard, use CTRL-V to paste)

对,它说a.img有2880个扇区,floppya......这行在bochs的配置文件中会出现,希望我们复制到剪切板,以备后用。

到此,A盘、B盘的已经生成了,下面在看看C盘的生成。

f8998b53685046eb63e0880915e2f4a1.png

同样的有几句英文,我们只是择了中间的一句。

Creating hard disk image 'c.img' with CHS=8322/16/63 (sector size = 512)

它告诉我们C盘柱面/磁头/扇区的个数,以及每个扇区的字节数。之所以择了这句,是因为在bochs的配置文件中,要用到这些的地方。顺便说一下,我们的硬盘大小是4096M,这个应该够用了吧。

生成好的a.img、b.img、c.img都要移动到bochs目录中。

BIOS-bochs-latest、VGABIOS-lgpl-latest、x11-pc-us.map是bochs中硬件相关的文件,前两个在bochs的安装目录下,后一个在keymaps目录下,复制过来就行了。从名字上可以看出来它们分别是BIOS、VGABIOS和键盘的二进制文件。

最后我们还要把bochsrc.bxrc文件也复制到bochs目录中, 它正是我们屡次提到的bohcs配置文件,最后我们要好好的做一番修改。

我们把修改后的文件放在了下面,并且在关键的地方给了一些注释。

Bochsrc.bxrc文件全文

 

###############################################################

# bochsrc.txt file for DLX Linux disk image.

###############################################################

## 在bochs的配置文件中"#"是注释语句,我们的注释用"##"。

 

# how much memory the emulated machine will have

## 这里是虚拟机的内存容量。

megs: 512

 

# filename of ROM images

## 看到了吧,用到我们的从bochs目录中复制的文件。

romimage: file=../bochs/BIOS-bochs-latest

vgaromimage: file=../bochs/VGABIOS-lgpl-latest

 

# what disk images will be used

## A盘和B盘的路径和状态设置。

floppya: 1_44=../bochs/a.img, status=inserted

floppyb: 1_44=../bochs/floppyb.img, status=inserted

 

# hard disk

## PC机的ide通道有2个,每个通道可以装2块硬盘,主通道的第1块硬盘io端口的地址

## 是0x1f0,第2块硬盘的io端口的地址0x3f0,所用的中断向量号是14。

## 主通道的类型、C盘的路径、以及柱面/磁头/扇区数(这个在创建硬盘的时候我们

## 复制了,看来有备无患真的不是白说的!)。

ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14

ata0-master: type=disk, path="../bochs/c.img", cylinders=8322, heads=16, spt=63

 

# choose the boot disk.

## 默认的引导设备

boot: c ##floppy

 

# default config interface is textconfig.

#config_interface: textconfig

#config_interface: wx

 

#display_library: x

# other choices: win32 sdl wx carbon amigaos beos macintosh nogui rfb term svga

 

# where do we send log messages?

# log: bochsout.txt

 

# disable the mouse, since DLX is text only

## 鼠标是否默认可用,0为不可用,1为可用。

mouse: enabled=0

 

# set up IPS value and clock sync

## 下面两项让我来猜一下,应该是CPU的频率和时钟的同步,我们不用改的。

cpu: ips=15000000

clock: sync=both

 

# enable key mapping, using US layout as default.

#

# NOTE: In Bochs 1.4, keyboard mapping is only 100% implemented on X windows.

# However, the key mapping tables are used in the paste function, so

# in the DLX Linux example I'm enabling keyboard_mapping so that paste

# will work. Cut&Paste is currently implemented on win32 and X windows only.

 

## 用到了吧,这个是我们从bochs安装目录中复制的键盘相关的二进制文件。

keyboard: keymap=../bochs/x11-pc-us.map

#keyboard: keymap=../keymaps/x11-pc-fr.map

#keyboard: keymap=../keymaps/x11-pc-de.map

#keyboard: keymap=../keymaps/x11-pc-es.map

通过上面的文件我们知道,这个文件没有什么难度,只要我们把上面的关键点都改好了就大功告成了。

经过一番折腾,终于又切换到讲working目录的文件了。还是从简单的开始吧。

 

%objcopy_move.cmd 创建者:至强 创建时间:2022年8月%

objcopy -I pe-i386 -O elf32-i386 kernel.pe

move kernel.pe kernel.elf32

 

Objcopy是mingw工具集中的可执行程序,它可以将windows系统的经过gcc编译生成的可执行文件,转化为elf格式文件。为什么要转化呢?第一个原因是elf格式分析的资料比较多,这样就方便我们将来解析elf文件。二是elf文件是multiboot2规范中无条件解析的文件,能够默认的被grub作为内核引导。

Move是windows中命令行中一个常驻内存的命令,用于给文件改名或者移动文件,我们就是用了改名的功能。也是objcopy的原因,它居然在改变文件格式的情况下保留原文件名称,因此我们要改名,以区分原文件和生成后的文件。当然目前我们还没有用到这个文件。不过既然这么简单就在这里说了吧。

 

我们要说的第二个文件是Makefile,相信大名顶顶的make都听过过吧,还是先看文件内容。

 

# Makefile 创建者:至强 创建时间:2022年8月

 

build: boot.asm

# 用nasm把boot.asm编译成纯二进制可执行文件boot.bin。

nasm -fbin -o boot.bin boot.asm

install: build

# 把boot.bin写入到硬盘映像文件的引导扇区,也就是第

# 1个扇区,但dd从0开始计算,所以"seek=0"。

dd if=boot.bin of=..\bochs\c.img seek=0 count=1

run: install

# 用bochsrc.bxrc作为配置文件快速启动bochs

bochs -q -f ..\bochs\bochsrc.bxrc

dbg: install

# 用bochsrc.bxrc作为配置文件快速启动bochsdbg,从名称上

# 就猜到了把这是运行调试模式。

bochsdbg -q -f ..\bochs\bochsrc.bxrc

clean:

# 删除产生的中间文件和垃圾文件

del *.bin *.o *.pe *.elf32 ..\bochs\c.img.lock

为了照顾初学,文件注释是多了些。这里还是要再说一些东西。在文件中像“#”是注释。“:”之前的我称之为自定义命令,而之后的是依赖关系。自定义命令下面的语句是在命令行提示符中输入“make run”等形式后,真正执行的命令集合,如这里的bochs -q -f ..\bochs\bochsrc.bxrc。还是“make run”这条,由于它依赖于install命令,因此会先执行install下面的至下一个自定义命令开始的若干条语句(这里暂时都是1条),而“install”依赖于“build”,所以又去执行“build”下面的语句,依次递归,直到最初的没有依赖的语句。一个小的关注点是,每条语句都是以tab键开头的,只是tab键是非显示字符,这个一定要关切呀。

 

boot.asm对于初学算是有点长了,好在依然是注释满满。

【boot.asm】

; boot.asm 创建者:至强 创建时间:2022年8月

; 告诉编译器,此处开始的代码要汇编成实模式16位

; 的指令。

bits 16

; 指令开始的标签,这里也可以没有此标签。

start16:

; 将段寄存器的值都设置位0x7c0,也就是段基地为0x7c00。

; 将堆栈指针也设置成段的首地址。

mov ax, 0x7c0

mov ds, ax

mov es, ax

mov ss, ax

mov sp, 0

 

; 清屏的过程调用。

call cls

 

; 简单打印字符串的过程调用。

push string

call put_s

add sp, 1 * 2

 

jmp $

 

; 打印一个字符的过程。

put_c: ; void put_c(char c)

push bp

mov bp, sp

push es

push di

 

mov ax, 0xb800

mov es, ax

 

mov di, [pos]

mov al, [bp + 2 * 2]

mov ah, 0xc

mov [es:di], ax

inc di

inc di

 

mov [pos], di

 

pop di

pop es

mov sp, bp

pop bp

ret

 

; 打印字符串的过程。

put_s: ; void put_s(char* s)

push bp

mov bp, sp

push bx

 

mov bx, [bp + 2 * 2]

 

.1:

mov ax, [bx]

or ax, ax

jz .2

push ax

call put_c

add sp, 1 * 2

inc bx

jmp .1

.2:

 

pop bx

mov sp, bp

pop bp

ret

 

; 清除屏幕的过程。

cls: ; void cls(void)

push bp

mov bp, sp

push es

push di

 

mov ax, 0xb800

mov es, ax

 

xor di, di

mov cx, 2000

mov al, ' '

mov ah, 0xf

.1:

mov [es:di], ax

inc di

inc di

loop .1

 

pop di

pop es

mov sp, bp

pop bp

ret

; 用于存储屏幕位置数值。

pos: dw 0

; 打印的字符串。

string: db ' Hello SnailOS...!', 0

; 告诉编译器预留出合适的空间到509字节处都写入数值0。

times 512 - 2 - ($ - $$) db 0

; 在510和511字节处分别写入魔数0x55和0xaa。地址通常是

; 从0开始计算。

magic: dw 0xaa55

 

8086是一个16位的处理器,它的地址总线确是20位。可访问的最大物理内存是1M。可是装载段基地的段寄存器确是16位的。那么怎么访问20位的地址呢?因此,设计者就开始套路了。它们刻意把段基地址弄成是16的整数倍,这样以来16位段基地址左移4位(等效于乘以16),就形成了一个20位的地址。所以段基地址可以从任何16的整数倍开始,而段的最大长度只能是64k。计算机开机自检后,CPU使用一条跳转指令,跳转到CMOS中的BIOS代码中去执行。BIOS也做一些重要的工作,最后将启动设备上的首扇区(被称为引导扇区)读入内存中。即是物理地址的0x7c00处,换算成段寄存器中的段基地址即是0x7c0。而且BIOS接下来就会跳转到此处继续执行。这个时候的代码段寄存器的值应该是0,也就是代码段的基地址是0。因为没有超过64k,所以这样是没有问题的。而这个引导扇区的512字节是我们自己定义的代码和数据,所以我们期待用数据段基地址来访问数据。因此,这里我们重置了ds、es、ss三个段寄存器,同时接下来我们要进行过程调用(就是C中的函数),过程调用中,必须使用堆栈,所以这里还设置了栈指针为该段的开始处。而堆栈是向下生长的,这样就不会和我们的程序相互覆盖数据。

在BIOS的诸多骚操作后,不但载入了引导扇区。还把显示模式设置的成了,80*25的字符模式,显存物理地址定义为0xb8000处。所以在显示字符和清理屏幕的函数中,我们都不得不使用段前缀,来访问这个超过64k的内存区域。关于函数调用、汇编以及C语言的问题现在讨论还为时过早,那几个函数大家也可以忽略,现在只知道功能就可以了。因此这里不说了,如果有兴趣,可以仔细的看看代码就好了。对了如果没有学过汇编语言的话,因该找一本intel汇编的书来学学,nasm正好是intel的汇编语法,啊,我们这个时代的程序员还是蛮幸运的。

最后这段程序还只是剩了一个魔数没有说了,不要在意它,这种玩意都是随意为之的,只是时间久了,大家都习惯了,也就不会改了。跟引导有关的扇区大都是这个结尾。

第一个运行环境就讲到这里了,是不是很臭很长,好啰嗦。好了,让我们看一下运行效果吧!

deb8a902f1e79be53a97bfd941354eae.png

这里就只能是静态的图片了,其实那个光标还在那里一闪一闪的,很是动人。

f3c592139a17c9f94a0526df4e9a6038.png

 

以virtual box为核心的开发环境

virtual box的安装与配置

Virtual box虚拟机同样是一款开源软件,我安装的宿主系统是windows10,安装的过程非常简单,一路下一步安装完成。但是到了运行的阶段就会提示问题。我先后xp、win7上也安装过这个软件。在win7、win10上安装都不难,但运行是先后出现过很多的问题。由于问题不定,而且已经在自己的系统上运行好了,所以无法追溯到原来的问题。这里只是给大家提个具体的建议,如果出现了运行问题,建议大家把问题复制下来,在搜索引擎中直接查问题,大多数情况下都有答案,而且解决的办法大都是修改注册表。同时安装和运行后也应该设置环境变量。

下图是virtual box在windows10成功运行的情况。

2cc1121958433138fd88208104c6647c.png

安装一个U启动软件

这个软件是能够生成启动引导ISO镜像的软件,似乎与我们开发风马牛不相及了。不过大家别急,它可是发挥了至关重要的作用呀!

它的安装极其简单,我们主要是用它生成iso镜像文件。

确定好正确的路径后,点击“ISO模式”,点击下面的“生成ISO”

f065da369724fe35aefe914b1232a17d.png

创建一个适合开发环境的虚拟机

新建一个虚拟机,如图

665e2aabdaddfda2399c384c81367686.png

创建虚拟机需要确定名称,选择安装路径、类型以及版本,如下图是我们的选择。然后就可以下一步。

f17e9081bb8f6a10351a0a169fbdfc7a.png

确定内存容量,这里我们要搞得大一些,否则ISO中的winpe可能无法运行。我选择了4G。

7ccfb83e3dca921c902f607431f36dc5.png

下图是询问我们是否创建虚拟硬盘。这里我们当然要创建了。

2ff828f0aac5e9ab5af61113f6252e60.png

接下来,我们要选择虚拟硬盘的格式,我们果断的选择VHD格式,因为他是windows7及其以上系统默认支持的。等会儿大伙就会知道了,选择这种格式的诸多好处。

ab69329b1f2e3ad6f23ba37275dcf9af.png

 

继续要做的是选择“固定大小”比较稳妥。

00024667a87017525d993165bfc98068.png

 

磁盘的容量根据需要来确定,我趋向至少是物理内存的2倍。最后点击“创建”,稍等,则虚拟机创建完成。

ba00b0ca544b8b2412c7c3376a35be53.png

 

创建完成后,我们应该观察一下存储那块。确保我们的控制器是IDE,对了硬盘容量怎么是1G,你不是说最好是内存的2倍吗,怎么是1G,哈哈,我是在演示吗!

c288631e708ec162af6672b83e0cf623.png

 

在虚拟机中折腾一番,完成环境创建

这次我们就一气呵成了,因为本来就不怎么复杂吗。

首先我们在存储——第二个IDE控制起主通道:点击[光驱] 没有盘片,选择盘片的ISO文件要根据自己的ISO镜像的具体路径。完成后启动虚拟机,则进入进入以下画面。

1dd7f06d4662d01af0e99edb84eabc06.png

 

通过键盘上的方向键,进入到DiskGenius硬盘分区工具

 

e53624e8f25de223ddcadf5bc2191577.png

 

 

在上图中,点击选择硬盘0-->选择新建分区,在建立新分区对话框中,分区类型为“主硬盘分区”,文件系统类型为FAT32,其他默认,然后确认。而后点击保存更改,并在接下来的“立即生效对话框”中选择“是”,在“格式化对话框”中选择“是”。则我们的第一阶段工作完成。

我们的第二阶段工作是使用diskpart(windows7以上系统自带)工具将虚拟硬盘挂载到windows宿主机上,然后将下列文件和工具集复制到虚拟硬盘上。

在系统上找到虚拟机文件的绝对路径,并复制下来。我的路径是C:\Users\free2\.VirtualBox\temp\temp.vhd

这里我们先完成挂载的过程,运行命令行,如下图。

79e4ac30cb1a1becca0b9cc0e6814fcf.png

 

成功挂载后我们便能够在,Windows系统的“此电脑”中看到新增的盘符。可以向其中复制文件。

735cbc9763a9eb898194e68164c16b85.png

 

我们要复制的就是前面提到的grub整个文件夹和一个gurb.cfg的配置文件。

3ba602b720ba205bc15ba379c58872c4.png

 

接下来我们返回到该虚拟磁盘的上层,右键菜单中选择“弹出”,卸载此硬盘。

然后,我们要再次启动虚拟机,进入winpe系统(我选择2003经典版),稍等启动完毕后进行grub的安装和配置。

68d92600c44deea4ba6a249e191f3cc8.png

 

安装成功的画面入下。

f83a3a0c811c30ac8d2f289c14a38a3b.png

 

 

在虚拟机的C盘上会多了一个boot目录,这就是我们安装的grub。

78b68add9e22f7db8b7636b35d15bfe8.png

 

这时,我们还需要把配置文件grub.cfg复制到\boot\grub\中去。

 

c3b602ffa800d7d665ca9255eba6c49a.png

 

 

关闭虚拟机后,移除虚拟光盘。

b87dc7746da5183cb92c81cfc150c8d6.png

 

重新启动虚拟机后就会后进入gurb的画面了。

c7cf4b27d09467619007413880593e31.png

 

 

现在展示一下,grub.cfg文件,同时把刚在安装grub过程中,用到的最重要的命令提供给大家。

#grub.cfg 创建者:至强 创建时间:2022年8月

 

timeout=10

defualt=0

 

menuentry "SnailOS" {

set root=hd0,1

multiboot2 /kernel

}

 

重要命令: grub-install //./physicaldirve0

 

到目前为止,我们在上面的画面中按下回车键,是不能进入任何系统的,它会提示我们没有内核文件/kernel。

因此,在这一节的最后,我们仍然坚持要实现一个“内核”,并再次把“Hello World”的风采呈现给大家。不过这一次是用grub2来引导内核,完全没有个头绪吗?好在作为笔者的我早就给大家准备好了剧本,就等着接着演这出好戏了。

这个剧本就是《Multiboot2 规范版本 2.0》。什么?“来到这里就要读一本规范,操作系统的开发简直太特么难了吧?”要真的是这样,不要说是大家了,笔者也早就放弃了。其实没有那么难了。这里我们仅仅是来个“断章取义”,只要是抓住重点就完全好了。这是大家先要去下图的网址参观一下。

ea9fc8f64db72322caf261095144ad2f.png

 

什么完全的E文,一脸懵逼了吧!好了不必惊慌,大多数浏览器都自带翻译软件,而且翻译的还不错哦。看到了吧,瞬间变脸那是妥妥的。

215f0abf9b7051857a1630eab4a000cd.png

 

 

客观的说multiboot2真的像老太太裹脚布又臭又长了,能够坚持从头看到尾的人真的凤毛麟角,哈哈,“古之圣人鲜矣!”。接下来我们该做些什么呢?

我们直接看示例好了,看看能不能找到些灵感。看到了吗?“4个例子”,瞧瞧这翻译的多么的尴尬呀!不过下面几行中有个“示例操作系统代码”却是很抢眼了。还是点进去看下吧。

看到了吧,multiboot2.h、boot.S、kernel.c三个文件,和上面的4个例子,简直驴唇对了马嘴的感觉。

不过boot.S倒是挺像我们第一个开发环境的boot.asm的,让我们凭直觉果断看进去吧!

88985615abbce5c568ac5f94905f579b.png

 

这次我们又切换回了英文,是不满心的欢喜又没了。而且感觉这个boot.S的语法怪怪的,似曾相识,又无可奈何!

07048d91401828f629665393953c51c5.png

 

是的boot.S使用的是AT&T的汇编语法,初学的同学真的是在这里又遇到了一头拦路虎呀!

好在笔者比较“勤奋”,居然把boot.s改成了intel汇编的格式。哈哈,到了这里也不买关子了。直接把实现“操作系统”的几个文件,展示个大家吧。这一波的文件比较多,但是好在都不难,只要耐心都是可以看懂的。

Boot.asm kernel.c global.h a.txt b.txt cd_.cmd Makefile mount_copy.cmd

首先让我们来看Makefile文件。

 

【Makefile】

#Makefile 创建者:至强 创建时间:2022年8月

#在第一个自定义命令前面的诸多等号构成的东西是称作"变量",

#还是称作"别称"好呢?总之,它在这两个方面的含义都是有的。

AS=nasm

CC=gcc

LD=ld

INCLUDE = -I ./kernel/

 

OBJ=./create/boot.o ./create/kernel.o

 

#除了多了上面的"变量"以外,根本就没有任何新意,如果不太明白,

#可以参考开发环境1的Makefile解释。

./create/kernel.elf: $(OBJ)

#这里的含义是在链接时如果遇到绝对地址的情况要加上0x00100000。

$(LD) -Ttext 0x00100000 -o $@ $(OBJ)

install: ./create/kernel.elf

mount_copy.cmd

run: install

start virtualboxvm --startvm "C:\Users\free2\.VirtualBox\temp\temp.vbox"

dbg: install

start virtualboxvm --startvm "C:\Users\free2\.VirtualBox\temp\temp.vbox" --debug-command-line

resume:

vboxmanage controlvm "C:\Users\free2\.VirtualBox\temp\temp.vbox" resume

clean:

del /q .\create\*

 

./create/boot.o: ./boot/boot.asm

$(AS) -felf -o $@ $^

./create/kernel.o: ./kernel/kernel.c

$(CC) $(INCLUDE) -c -o $@ $^

 

接下来的mount_copy.cmd文件似乎执行了一些匪夷所思的命令。

【mount_copy.cmd】

%mount_copy.cmd 创建者:至强 创建时间:2022年8月%

@echo off

copy .\create\kernel.elf .\

ping -n 1 127.0.0.1 > nul

 

objcopy -I pe-i386 -O elf32-i386 kernel.elf

ping -n 1 127.0.0.1 > nul

 

diskpart /s a.txt

ping -n 1 127.0.0.1 > nul

 

move kernel.elf d:\kernel

ping -n 1 127.0.0.1 > nul

 

diskpart /s b.txt

ping -n 1 127.0.0.1 > nul

 

它首先是将生成的内核文件kernel.elf复制到当前目录。我们生成的内核临时文件是放在create目录中的,这主要是防止虚拟机的根目录混乱不堪。然后我们竟然用了一个测试网络的命令,是的就是ping命令。其实这个命令可以起到延时和同步的效果。主要是为了防止复制还没有完成就运行了下面的命令。接下来的诸多此类命令,大家就应该懂了吧,objcopy将pe格式文件转换位elf32格式文件。用diskpart的自动模式挂载虚拟机硬盘,移动内核文件到D盘,更名为kernel,这与grub.cfg配置文件的内核文件相同。自动卸载虚拟机硬盘。虚拟机硬盘如果不从windows中卸载,virtual box会认为该硬盘被占用,因为没有可用引导设备,所以虚拟机就不能正常启动。

 

现在该轮到diskpart使用的a.txt和b.txt文件了。

【a.txt】

a.txt

select vdisk file="C:\Users\free2\.VirtualBox\temp\temp.vhd"

detach vdisk

【b.txt】

b.txt

select vdisk file="C:\Users\free2\.VirtualBox\temp\temp.vhd"

detach vdisk

a.txt就是在windows中挂载虚拟硬盘,b.txt就是卸载了。

 

然后我们再来看看cd_.cmd的批处理文件

【cd_.cmd】

%cd_.cmd 创建者:至强 创建时间:2022年8月%

@echo off

cd "C:\Users\free2\.VirtualBox\temp\"

 

在关闭了终端输出后,进入了虚拟机所在的目录。这主要是以下原因,在windows10上,由于权限的设置,如果想要自动化运行所用的命令的话,必须要全部获得管理员的权限。如果我们没有获得权限,直接运行“make run”,各个线程就难以达到同步,也就是出现还没有将内核复制到虚拟机硬盘的情况下,虚拟就开始运行的情况。

为了避免这些情况的发生,我们在运行windows10命令行的最开始,是通过点击鼠标右键,以管理员身份运行的qcmd.cmd批处理命令。如下图。而以管理员运行的qcmd.cmd,命令行窗口的默认路径是\windows\system32\,因此我们需要将cd_.cmd复制到\windows\system32\目录中,然后在进入到该目录后,运行cd_.cmd方便快捷地进入到我们的开发工作目录。

77af5a166b813811eba057a09377ae2c.png

 

看到了吗,已经在工作目录了。

c3b5f93a942b32e22710ea1e14ce573d.png

 

 

这时候我们“make run”,就会编译链接复制以及运行虚拟机的整个流程一气呵成,从而达到操作系统开发“所见即所得的”目标。

 

 

 

 

下面分别是boot.asm、global.h、kernel.c三个文件,这三个文件是真正的内核文件,在文件中已经解释的很清楚了。因此,直接列出文件的内容来。

【boot.asm】

; boot.asm 创建者:至强 创建时间:2022年8月

;编译成32位代码

bits 32

;标记下面的段位代码段

section .text

 

global _start, _stack

extern _kernel_main

 

_start:

;在代码段的开始,即跳过下面的数据定义,直接跳转到

;entry处执行。代码是一种特殊的数据,数据在符合代码

;定义的情况下就是代码。因此在汇编中,经常会出现,

;代码与数据混合存在的情况。

jmp entry

; 按照multiboot2规范的要求,此处因该是64字节边界

; 对齐,然而我们用了8字节,似乎也正常引导了。

align 8

; 这是multiboot2要求的引导头格式。

header_start:

; 下面是魔数,也就是固定值。

dd 0xe85250d6

; 体系结构,0表示32位保护模式,4为MIPS。

dd 0x0

; 引导头的长度。

dd header_end - header_start

; 校验和,校验和的值 = -(魔数 + 属性 + 引导头长度)

dd - (0xe85250d6 + 0x0 + (header_end - header_start))

 

; multiboot2 头的地址信息

; 根据multiboot2规范,每个标签都至少由3部分组成

; 1是标签类型,2是标签标志,3是标签长度。

; 其余标签依此类推。

add_tag_start:

dw 0x2 ; 这就是multiboot头地址的类型。

dw 0x0 ; 是头地址的标志。

dd add_tag_end - add_tag_start ; 头地址标签的长度。

dd header_start

dd _start

dd 0x0

dd 0x0

add_tag_end:

 

; 可执行程序的入口地址信息。

entry_add_tag_start:

dw 0x3

dw 0x1

dd entry_add_tag_end - entry_add_tag_start

dd entry

entry_add_tag_end:

align 8

 

; 帧缓冲的信息

framebuffer_tag_start:

; dw 0x5

; dw 0x1

; dd framebuffer_tag_end - framebuffer_tag_start

; dd 1024

; dd 768

; dd 32

framebuffer_tag_end:

align 8

; multiboot2 头的结尾信息。

dw 0x0

dw 0x0

dd 0x8

header_end:

align 8

 

; 这是经由grub2引导来的内核的汇编程序入口。

entry:

; 在进入c程序的内核时,是通过函数调用进入的

; 因此这里要设置栈指针,栈段(描述符)的基

; 地址由grub提前设置好,我们暂时不用管它。

mov esp, _stack

; 清空标志寄存器,以关闭所有中断。

push 0

popf

 

; 进入内核的函数,该函数可接收2个参数,因此

; 这里通过压栈的方式传递参数,根据规范,ebx

; 为multiboot2信息结构的地址,而eax为魔数值。

push ebx

push eax

; 调用真正的内核函数,从而进入c内核,当然如果

; 我们准备用汇编语言开发的话,在这里尽管写下

; 神奇的汇编代码就好了。

call _kernel_main

; 如果c函数没有问题的话,将永远不会返回到这里。

; 即使返回到这里,也意味着系统的宕机。

add esp, 2 * 4

 

jmp $

 

times 4096 - ($ - $$) db 0

_stack:

 

【global.h】

// global.h 创建者:至强创建时间:2022年8月

// 这个C语言的头文件真的没有什么好介绍的,

// 仅仅是声明了两个函数的原型。

// 下面的编译预处理的语句,几乎在每一个头文件

// 中都会出现,它的主要作用是让引用此文件的c语

// 源文件中只包含此头文件的1个副本,从而避免

// 多次重复引用。

#ifndef __KERNEL_H

#define __KERNEL_H

 

void put_c(char c, unsigned char colour);

void put_s(char* s, unsigned char colour);

 

#endif

 

【kerne.c】

// kernel.c 创建者:至强 创建时间:2022年8月

#include "global.h"

 

// 这个文件实在是没有什么好讲的,当然对于c语言的初学者

// 有些时候还是有点困惑,好在重要地方的注释已经足够了。

unsigned int pos;

 

void kernel_main(unsigned int magic, unsigned int addr) {

pos = 0;

put_s(" Hello SnailOS...! ", 0xc);

put_s(" Hello, World!......", 0x9);

while(1);

}

 

void put_c(char c, unsigned char colour) {

// 在默认文本模式下,物理地址0xb8000是显存的开始,

// 因此下面语句是把常量的物理地址赋值给变量video_base,

// 而在文本模式下低字节赋值ascii字符,高字节赋值8位

// 颜色值,在屏幕上就会显示该颜色的字符。

unsigned char* video_base = (unsigned char*)0xb8000;

video_base[pos++] = c;

video_base[pos++] = colour;

}

 

void put_s(char* s, unsigned char colour) {

// 字符串是以值0为结束字符的,这是约定,因此,显示

// 完整字符串就可以用循环的方式,显示在字符串结尾。

while(*s) {

put_c(*s++, colour);

}

}

 

还是请大家看看运行效果吧!“make run”后下图是进入了grub2。

 

d25e324fb7ab1b4f958b88d3069f2e9e.png

 

接下来“回车”就进入了咱们自己的操作系统。

33868fbbb388117b5993a3bb133a5f15.png

 

本章结束语

这一章是我们拼凑自己的操作系统至关重要的一环,编程的难度不大,却为我们准备了两种都很有战斗力的平台,选择哪一种平台作为今后继续战斗的基地,那就是大家仁者见仁智者见智的事情了。接下来的劳动才是我们真正体验快感的事情,我相信大家在今后,一定会更深刻地领会到什么是“痛并快乐着”的感觉。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

weixin_39410618

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值