操作系统实验日志
一.实验目的
本实验分为三个部分,第一个部分为安装必要的工具链,第二部分为编写裸机程序(独立式可执行程序),第三部分为构建最小内核。
二.实验过程
1.安装工具链
1.安装Rust
下载Rust,输入curl https://sh.rustup.rs -sSf | sh
选择安装版本 等待安装,保持网络通畅
证明安装成功
输入rustc --version,这里是查看当前rust的版本的意思,如果出现当前的版本号,表示安装成功
2.安装nightly版本
安装nightly版本,输入rustup install nightly
,并且安装成功
默认使用nightly版本,输入rustup default nightly
3.安装bootimage
输入cargo install bootimage --version “ˆ0.7.3”
安装出错,没有去掉双引号以及^不是英文符号
再次安装出错,在网上查询原因,刚开始还以为是SSL未连接,用了许多连接SLL的方法,最后还是没有安装成功。最后看到好像是因为rust的原因,依赖镜像加速。
1.进入配置文件
输入vi ~/.cargo/config
2.在文本框里面复制粘贴
[source.crates-io]
registry = "https://github.com/rust-lang/crates.io-index"
replace-with = 'ustc'
[source.ustc]
registry = "git://mirrors.ustc.edu.cn/crates.io-index"
最后安装成功
4.安装xbuild
输入cargo install cargo-xbuild
安装成功
5.安装rust-stc
输入rustup component add rust-sr
安装成功
6.安装llvm-tools-preview
输入rustup component add llvm-tools-preview
安装成功
7.安装QEMU
安装出错,没有那个文件或目录
换一种方式安装QEMU 输入sudo apt-get install qemu
还是无法下载
最后找寻原因,有可能是因为系统自带的软件包没有更新。找到Ubuntu自带的软件更新器,然后打开更新软件,选择最佳服务器,然后进行过程等待。
之后 就可以下载QEMU。
证明安装完成,在终端输入qemu,会弹出qemu窗口,如果没有弹出,可以先输入sudo ln -s /usr/bin/qemu-system-i386 /usr/bin/qemu将qemu与qemu-system-i386
进行链接即可
2.创建裸机程序
1.创建一个新的cargo项目,输入cargo new blog_os
创建成功
2.打开src文件夹中的main.rs文件,输入如下代码
3.使用cargo build编译,即输入cargo build
出现错误:报错,找不到.toml文件
解决方法:新建文件夹,全部转移到新文件夹中
出现错误1:出现这个错误的原因是,println!宏是标准库的一部分,而我们的项目不再依赖于标准库。我们选择不再打印字符串。这也能解释得通,因为println!将会向标准输出(standard output)打印字符,它依赖于特殊的文件描述符,而这是由操作系统提供的特性。
解决方法:所以我们可以移除这行代码,使用一个空的main函数再次尝试编译
出现错误2:编译器缺少一个panic处理函数
#[panic_handler]属性定义了一个函数,它会在一个panic发生时被调用。标准库中提供了自己的panic处理函数,但在no_std环境中,我们需要定义一个自己的panic处理函数
出现错误3:缺少语言项
在toml中设置panic的参数,即在toml文件中加入如上语句
出现错误4:
解决方法:我们的程序遗失了start函数,这是程序的进入点,所以我们的程序无法正常运行,所以我们需要重新写一个crt0库和定义他的入口点,实际上直接将main.rs函数修改如下即可
出现错误5:链接器错误
解决方法:首先我们要查看当前的目标三元组,即输入rustc --version--verbose
添加thumbv7em,即输入rustup target add thumbv7em-none-eabihf
,这行命令将为目标下载一个标准库和core库,之后就能为这个目标构建独立式可执行程序
构建独立式可执行程序,并传递–target参数,即输入cargo build --target thumbv7em-none-eabihf
最后完成现象
3.实现最小内核
1.构建目标配置清单文件(.json文件)
在操作系统(xx_os)文件夹下面新建一个文件,然后命名为x86_64-blog_os.json,
里面内容如下
{ "llvm-target": "x86_64-unknown-none",
"data-layout": "e-m:e-i64:64-f80:128-n8:16:32:64-S128",
"arch": "x86_64",
"target-endian": "little",
"target-pointer-width": "64",
"target-c-int-width": "32",
"os": "none",
"executables": true,
"linker-flavor": "ld.lld",
"linker": "rust-lld",
"panic-strategy": "abort",
"disable-redzone": true,
"features": "-mmx,-sse,+soft-float"}
2.编写内核(main.rs程序)
直接将main.rs文件修改如下即可:
3.将json文件加入–target选项,并尝试编译我们的内核,即输入cargo build --target x86_64-blog_os.json
发现错误:rust编译器找不到core或compiler_builtins包
解决错误:安装cargo xbuild库,即输入cargo install cargo-xbuild
发现错误:报错,cargo安装错误
解决错误:未安装源代码,输入rustup component add rust-src
,将rust-src进行更新
4.使用xbuild重新编译后成功
设置默认目标
为了避免每次使用cargo xbuild时传递–target参数,我们可以覆写默认的编译目标。我们创建一个名为.cargo/config的cargo配置文件,并添加内容
配置文件:在主文件夹按下Ctrl+H显示隐藏文件,下面找到名为.cargo的文件夹,打开后创建空白新文件,并命名为config,然后添加代码
输入cargo xbuild报错,尝试着将x86_64-han_os.json文件移动到主目录下进行测试,但是又出现如下问题
出现这个错误的原因是config文件中写入的内容不正确,使得x86_64-blog_os.json
无法被找到,所以说在编写config的时候应该加入x86_64-blog_os.json
的文件路径,如下图所示:
修改后再进行测试,发现结果正确
向屏幕打印字符
首先对main文件和cargo.toml进行修改,如下所示:
在这段代码中,我们预先定义了一个字节字符串(byte string)类型的静态变量(static variable),名为HELLO。我们首先将整数0xb8000转换(cast)为一个裸指针(raw pointer)。这之后,我们迭代HELLO的每个字节,使用enumerate获得一个额外的序号变量i。在for语句的循环体中,我们使用offset偏移裸指针,解引用它,来将字符串的每个字节和对应的颜色字节——0xb代表淡青色——写入内存位置。
6、启动内核
我们需要首先创建引导映像,要将可执行程序转换为可引导的映像(bootable disk image),我们需要把它和引导程序链接。这里,引导程序将负责初始化CPU并加载我们的内核。
编写引导程序并不容易,所以我们不编写自己的引导程序,而是使用已有的bootloader包[5];无需依赖于C语言,这个包基于Rust代码和内联汇编,实现了一个五脏俱全的BIOS引导程序。为了用它启动我们的内核,我们需要将它添加为一个依赖项,在Cargo.toml中添加下面的代码:# in Cargo.toml [dependencies] bootloader = “0.6.0”,如下图所示:
只添加引导程序为依赖项,并不足以创建一个可引导的磁盘映像;我们还需要内核编译完成之后,将内核和引导程序组合在一起。在这里我们需要使用bootimage工具,它将会在内核编译完毕后,将它和引导程序组合在一起,最终创建一个能够引导的磁盘映像。
在利用cargo bootimage指令进行编译的的时候出现如下所示的问题:
上述问题描述的是LLVM-style的问题,出现的原因是在cargo.toml文件中;我的修改方法是将cargo.toml中的bootloader改为0.9.11进行尝试,发现上面的问题消失了
最后成功完成编译
事实上,在这行命令背后,bootimage工具执行了三个步骤:编译我们的内核为一个ELF(Executable and Linkable Format)文件;编译引导程序为独立的可执行文件;将内核ELF文件按字节拼接(append by bytes)到引导程序的末端。
当机器启动时,引导程序将会读取并解析拼接在其后的ELF文件。这之后,它将把程序片段映射到分页表(page table)中的虚拟地址(virtual address),清零BSS段(BSS segment),还将创建一个栈。最终它将读取入口点地址(entry point address)——我们程序中_start函数的位置——并跳转到这个位置。
会在HOME文件夹下面生成一个bin文件
启动内核,输入
qemu-system-x86_64 -drive format=raw,file=bootimage-blog_os.bin
在哪个文件夹下输入?
在HOME/LHUI_OS/TARGET/X86_64-BLOG_OS/DEBUG文件夹下面,即bin文件所在的文件夹下打开终端并输入指令,注意需要按照生成的bin文件的文件名来修改输入的命令,如我这里就修改为了lhui_os
启动成功后如图,输出hello world语句
三.实验心得
这个实验是我花的时间最长的实验,第一是因为这个实验是我们最新接触的完全陌生的实验,第二个是因为这个实验本身是有一定的难度。这个实验做完以后,发现自身学会了许多的关于操作系统的知识以及会复习到关于自制操作系统30天的的一些知识。