操作系统实验日志——实现最小核

一、实验目的

本次实验主要分为三个部分:
第一部分安装必要的工具链;第二部分编写裸机程序(独立式可执行程 序);第三部分构建最小的“内核”系统。
由于我们的目标是编写一个操作系统,所以我们需要创建一个独立于操作系统的可执行程序。这意味着所有依赖于操作系统的库我们都不能使用。但是,不依赖与操作系统的 rust 的语言特性我们还是可以继续使用的,这使得 rust 依旧可以作为一个功能强大的高级语言,帮助我们编写操作系统。

二、实验过程

【安装工具链】
(一)安装Rust
1、安装Rust curl https://sh.rustup.rs -sSf | sh
输入命令行之后,提示我“curl”尚未安装,于是按照提示,使用命令sudo apt install curl进行安装,然后再次输入之前的指令,进行安装即可
在这里插入图片描述

这时候会发现他停在选择界面,这里有三个选项可以选择。这是需要我们选择安装版本,直接输入1就好。继续等待就好
在这里插入图片描述

安装完成之后不知道自己是否安装成功,此时我们输入指令rustc --version来检查一下。这条指令的意思是检查当前rust版本,如果出现了版本号,代表我们成功了。
在这里插入图片描述

但是…….
我按照他给出的指令执行了
在这里插入图片描述

完成之后,我们再来检查一下是否安装成功
在这里插入图片描述

如愿出现了版本号,安装成功
2、安装nightly版本 rustup install nightly
在这里插入图片描述

但是现在我们却发现,未找到指令,求助了一下同学,可能是路径配置没生效,我们需要手动保存生效,于是输入source ~/.profile指令,让他生效
3、默认使用nightly版本 rustup default nightly
在这里插入图片描述

保持网络通常,很快也就默认完成了。
4、安装bootimage,xbuild 和 rust-src等
安装bootimage cargo install bootimage --version “ˆ0.7.3”
在这里插入图片描述

发现有报错,于是我尝试删除“”和^再试一遍指令cargo install bootimage --version 0.7.3,这次就成功了
在这里插入图片描述

安装xbuild cargo install cargo-xbuild
在这里插入图片描述

然后我尝试着换了一个镜像源,一开始选择的是mirros.aliyun.com但是发现还是报错,不能下载,然后我又换了一个mirrors。.tuna.tsinghua.edu.cn这次就成功了
在这里插入图片描述

安装tust-src rustup component add rust-src
在这里插入图片描述

安装llvm-tools-preview rustup component add llvm-tools-preview
在这里插入图片描述

(二)安装其他工具qemu
/usr/bin/ruby-e“$(curl-fsSLhttps://raw.githubusercontent.com/Homebrew/install/master/install)” brew install qemu
在这里插入图片描述

这个方法在我的机子上执行了很久很久,一直未得到解决,无奈换了一个方法。
换一条命令执行sudo apt-get install qemu
在这里插入图片描述

安装完成,但是为了验证他安装完成我们可以输出qemu,会弹出窗
在这里插入图片描述

我按照提示尝试执行sudo apt install ,但是他还是报错了
在这里插入图片描述

然后我查询看一下,需要把<>改为单引号,然后此时他给出的报错是:无法定位软件包deb name。我查询了
在这里插入图片描述

然后尝试输入sudo ln -s /usr/bin/qemu-system-i386 /usr/bin/qemu将qemu与qemu-system-i386进行链接,但是还是报错,原因是已经存在,没办法创建链接。
反复试了好多种方法,最后发现是和aqemu有关,于是我尝试输入aqemu查看了一下,发现确实如此。
在这里插入图片描述

然后我按照他的提示输入sudo apt install aqemu,然后再输入qemu火车,此时终于弹出窗口,qemu安装成功。
在这里插入图片描述

(三)安装Vscode编辑器,并在Vscode中安装Rust插件
安装Vscode
输入指令sudo apt-get install ubuntu-make
在这里插入图片描述

输入指令umake ide visual-studio-code,并且这条指令下面出现的第一句是安装路径,需要记录一下
在这里插入图片描述

进入安装路径cd /home/aviva/.local/share/umake/ide/visual-code
在这里插入图片描述

执行./code,弹出窗口

在这里插入图片描述
在这里插入图片描述

接着自己再安装一些插件,完善一下就好了
【创建裸机程序】
(一) 创建新的cargo项目
输入指令cargo new xmd_os
在这里插入图片描述

我把项目命名为xmd_os。即使不输入–bin –edition 2018,cargo也会默认为我们添加了–bin选项,说明我们将要创建一个可执行文件(而不是一个库);cargo还为我们添加了–edition 2018标签,指明项目的包要使用Rust的2018版次(2018 edition)。当我们执行这行指令的时候,cargo为我们创建的目录结构如下:
在这里插入图片描述

其中,Cargo.toml文件包含了包的配置(configuration),比如包的名称、作者、semver版本和项目依赖项;src/main.rs文件包含包的根模块(root module)和main函数。我们可以使用cargo build来编译这个包,然后在target/debug文件夹内找到编译好的blog_os二进制文件。
(二) No_std属性
为了禁用我们的包隐式地与标准库链接,我们尝试添加no_std属性:
在这里插入图片描述

输入命令cargo build进行编译,出现了下图报错
在这里插入图片描述

找不到文件夹,这时候我们在新建的文件夹下执行:
在这里插入图片描述

出现这个错误的原因是,println!宏是标准库的一部分,而我们的项目不再依赖于标准库。我们选择不再打印字符串。这也能解释得通,因为println!将会向标准输出打印字符,它依赖于特殊的文件描述符,而这是由操作系统提供的特性。所以我们可以移除这行代码,使用一个空的main函数再次尝试编译:
在这里插入图片描述
在这里插入图片描述

此时是因为编译器缺少一个panic处理函数和一个语言项,所以此时需要我们去实现panic处理函数:
#[panic_handler]属性定义了一个函数,它会在一个panic发生时被调用。标准库中提供了自己的panic处理函数,但在no_std环境中,我们需要定义一个自己的panic处理函数:
在这里插入图片描述

类型为PanicInfo的参数包含了panic发生的文件名、代码行数和可选的错误信息。这个函数从不返回,所以他被标记为发散函数(diverging function)。发散函数的返回类型称作Never类型(“never” type),记为!。对这个函数,我们目前能做的事情很少,所以我们只需编写一个无限循环loop {}。我们再次编译来看看:
在这里插入图片描述

此时报错的,是语言项报错。我们需要在tool中设置panic参数,最简单的方式是把下面的几行设置代码加入我们的Cargo.toml:
在这里插入图片描述

我们再次执行发现start错误
在这里插入图片描述

我们的独立式可执行程序并不能访问Rust运行时或crt0库,所以我们需要定义自己的入口点。实现一个start语言项并不能帮助我们,因为这之后程序依然要求crt0库。所以,我们要做的是,直接重写整个crt0库和它定义的入口点。要告诉Rust编译器我们不使用预定义的入口点,我们可以添加#![no_main]属性。
在这里插入图片描述

我们可以移除main函数。原因很显然,既然没有底层已有的运行时调用它,main函数也失去了存在的必要性。为了重写操作系统的入口点,我们转而编写一个_start函数
紧接着,我们进行编译。出现了非常多的报错。
在这里插入图片描述

此时按照教程我们要查看当前系统的目标三元组,我们可以运行rustc --version –verbose
在这里插入图片描述

上面这段输出来自一个x86_64平台下的Linux系统。我们能看到,host字段的值为三元组x86_64-unknown-linux-gnu,它包含了CPU架构x86_64、供应商unknown、操作系统linux和二进制接口gnu
紧接着我们添加thumbv7em,即输入rustup target add thumbv7em-none-eabihf,这行命令将为目标下载一个标准库和core库,之后就能为这个目标构建独立式可执行程序
在这里插入图片描述

这行命令将为目标下载一个标准库和core库。这之后,我们就能为这个目标构建独立式可执行程序了。构建独立式可执行程序,并传递–target参数,即输入
cargo build --target thumbv7em-none-eabihf
在这里插入图片描述

(三) 最终代码以及运算结果
1、最终的独立式可执行程序
mian.rs
在这里插入图片描述

Cargo.toml
在这里插入图片描述

2、程序运行结果 cargo build --target thumbv7em-none-eabihf
在这里插入图片描述

【实现最小核】
(一) 目标配置清单
首先在xmd_os文件夹下面新建一个新的文件,用于描述x86_64-unknown-linux-gnu目标系统的配置清单(一开始我忘记配置x86_64-unknown-linux-gnu文件,报错一直找不到为什么)
在这里插入图片描述
在这里插入图片描述

将把内核编译到x86_64架构。现在,我们来创建一个名为x86_64-xmd_os.json的文件里面包含这样的内容:
在这里插入图片描述

这样就完成了构建目标配置清单.json文件
(二) 编译内核
要编译我们的内核,我们将使用Linux系统的编写风格(这可能是LLVM的默认风格)。这意味着,我们需要把main.rs中编写的入口点重命名为_start:
在这里插入图片描述

通过把JSON文件名传入–target选项,我们现在可以开始编译我们的内核。 cargo build --target x86_64-xmd_os.json
在这里插入图片描述

报错信息告诉我们rust编译器找不到core或compiler_builtins包,我们需要做到的是安装cargo xbuild库,也就是输入cargo install cargo-xbuild
在这里插入图片描述

现在我们可以使用xbuild代替build重新编译:
在这里插入图片描述

cargo xbuild为我们自定义的目标交叉编译了core、compiler_builtin和alloc三个部件。这些部件使用了大量的不稳定特性(unstable features),所以只能在nightly版本的Rust编译器中工作。这之后,cargo xbuild成功地编译了我们的blog_os包。
(三) 设置默认目标
为了避免每次使用cargo xbuild时传递–target参数,我们可以覆写默认的编译目标。我们创建一个名为.cargo/config的cargo配置文件,添加下面的内容:
1、 首先我们需要创建的这个文件在哪个位置?
我们应该在自己的文件夹下面新建一个cargo文件夹,然后再新建空白文件
在这里插入图片描述
在这里插入图片描述

这里的配置告诉cargo在没有显式声明目标的情况下,使用我们提供的x86_64-blog_os.json作为目标配置。
2、 编译内核,输入cargo build,发现报错
在这里插入图片描述

3、 我们首先需要将json文件拿出来,放到主文件夹下面,又在文件里面添加了一些内容,然后执行命令cargo xbuild
在这里插入图片描述

在这里插入图片描述

(四) 向屏幕打印字符
做到这一步我们需要修改main文件和toml文件,以下是修改情况
在这里插入图片描述
在这里插入图片描述

使用bootimage工具——它将会在内核编译完毕后,将它和引导程序组合在一起,最终创建一个能够引导的磁盘映像。使用cargo install bootimage --version ^0.7.3命令来安装这款工具:
在这里插入图片描述

为了运行bootimage以及编译引导程序,我们需要安装rustup模块llvm-tools-preview——使用rustup component add llvm-tools-preview来安装这个工具。
在这里插入图片描述

成功安装bootimage后,创建一个可引导的磁盘映像就变得相当容易。输入命令cargo bootimage:
在这里插入图片描述

在这行命令背后,bootimage工具执行了三个步骤:
。编译我们的内核为一个ELF(Executable and Linkable Format)文件;
。编译引导程序为独立的可执行文件;
。将内核ELF文件按字节拼接(append by bytes)到引导程序的末端。
当机器启动时,引导程序将会读取并解析拼接在其后的ELF文件。这之后,它将把程序片段映射到分页表(page table)中的虚拟地址(virtual address),清零BSS段(BSS segment),还将创建一个栈。最终它将读取入口点地址(entry point address)——我们程序中_start函数的位置——并跳转到这个位置。
【在QEMU中启动内核】
在target/x86_64-md_os/debug目录内找到我们的映像文件bootimage-md_os.bin
执行命令qemu-system-x86_64 -drive format=raw,file=bootimage-md_os.bin
在这里插入图片描述

三、遇到的错误及解决方法

由于遇到的问题什么都有,并且每一次安装还都不太一样,所以我这里主要讲两个我遇到的最大耗时最久的问题
【QEMU】
本次实验来说,耗时最久的竟然是QEMU的安装,也查阅了很多资料,请教了很多同学,但都未得到解决,最后不得不抱着试一试的态度更换为64位ubuntu。其中我怀疑是最开始我用的32Ubuntu版本太老了。(我查了一下自己以前装的分别32位和64位的ubuntu)
在这里插入图片描述
在这里插入图片描述

接着从头来说自己在32位以及64中遇到的问题吧,首先
我是在试了老师给出的命令行不行之后,在网上查阅了方法进行下去,按照那个顺序,我大概会遇到三个错误。
1、第一个错误
在这里插入图片描述

解决:根据安装提示,如果缺少哪个包,使用命令“apt-cache search ??”查找相应包安装)
在这里插入图片描述

然后执行apt-get install zlib1g zlib1g-dev 就可以解决了
在这里插入图片描述

2、第二个错误
在这里插入图片描述

我按照解决第一个错误的方法,试着去解决它,但是发现查找安装包是没问题的,但是要执行apt install libglib2.0-dev就会开始报错。并且第二个错误,我试了很多方法都过不去,以下是我分别尝试不同的方法遇到的报错(还有很多想要解决报错的步骤,就不一一截图,主要是想通过以下两个方式解决)遇到的问题就是装qemu缺glib,装glib缺gettext,反正就是装啥缺啥,装啥就会有一堆报错
在这里插入图片描述

在这里插入图片描述

最后实在没办法,我换成了64位的Ubuntu,虽然也遇到了一定错误,但是很快也很容易就可以解决了。放一张最后成功的截图。
在这里插入图片描述

以上是某一次做的过程中遇到的问题,后来还遇到了别的问题,只举一例耗时比较久的一个。
命令执行sudo apt-get install qemu
在这里插入图片描述

安装完成,但是为了验证他安装完成我们可以输出qemu,会弹出窗
我按照提示尝试执行sudo apt install ,但是他还是报错了
在这里插入图片描述

然后我查询看一下,需要把<>改为单引号,然后此时他给出的报错是:无法定位软件包deb name。我查询了
在这里插入图片描述
在这里插入图片描述

然后尝试输入sudo ln -s /usr/bin/qemu-system-i386 /usr/bin/qemu将qemu与qemu-system-i386进行链接,但是还是报错,原因是已经存在,没办法创建链接。
反复试了好多种方法,最后发现是和aqemu有关,于是我尝试输入aqemu查看了一下,发现确实如此。
在这里插入图片描述

然后我按照他的提示输入sudo apt install aqemu,然后再输入qemu火车,此时终于弹出窗口,qemu安装成功。
在这里插入图片描述

【设置配置目标】
为了避免每次使用cargo xbuild时传递–target参数,我们可以覆写默认的编译目标。我们创建一个名为.cargo/config的cargo配置文件,添加下面的内容:
首先我们需要创建的这个文件在哪个位置?
这是最开始网上找到的错误位置
按下Ctrl+H显示隐藏文件,在HOME文件夹(最开始的文件夹)下面找到名为.cargo的文件夹,打开后创建空白新文件,并命名为config,然后添加代码
在这里插入图片描述
在这里插入图片描述

实际上我们应该在自己的文件夹下面新建一个cargo文件夹,然后再新建空白文件
在这里插入图片描述
在这里插入图片描述

这里的配置告诉cargo在没有显式声明目标的情况下,使用我们提供的x86_64-blog_os.json作为目标配置。
这一步可把我害惨了,以至于重从头开始做实验。所以最后一遍重做实验跳过了很多内容,但是截图用的是之前较为全面的过程。所以在此用之前的截图,为了更方便的梳理过程。

四、实验心得体会

这次实验其实并不难,没有什么技术含量,最麻烦的就是安装一些环境。但很不巧的是,我遇到了一堆事情。做了好久,心情不太美妙。
中途一直怀疑自己rust没有删干净会有报错,就又重装了ubuntu,并且顺手换了一个20.04版本。有一说一,20.02版本Ubuntu真好看!!
实验做完啦,下次见面~

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值