Rust开发操作系统系列:从零制作x86_64位系统
在发表这个文章之前,我曾发布过另一篇文章:Rust开发操作系统系列:全新Hello World系统。
那篇文章我发布在云栖社区以及我自己的博客:青藤木子上,但是这是我第一次认真的写一篇文章,虽然看的人不多,也没几个人回复我,文章里也有很多的问题,目前你可以在我的博客上找到最新的修订版本,感谢转载和分享,也请您在转发文章时添加上原文章地址。也希望有更多人回复我、批评我、分享一些我不知道的知识。
这个系统可以干什么??
- [ ] 内存分页
- [ ] 线程
- [ ] 中断
- [x] 一个打印(print)功能
- [x] 在qemu上能够运行
- [x] VGA驱动
注意️
- 本人是在Mac OSX 上工作的,因此作者目前不会在其他平台上出教程,不过您有需要的话,请留言告知我
- 在使用Rust的时候请安装每夜版(nightly),这样方便同步,使用稳定版或beta版时将无法编译!
- 资料我将打包成zip,您可以自行下载固件编译运行。
- 目前来说这个自制的系统还无法直接在裸机上运行,而编译固件时编译的是bin固件。
- 如果您遇到了什么问题,可以下载源码查看:这里这里
编译环境安装
Rust安装是及其简单的,而且之前我的文章里也提到过安装Rust,如果您没有跟着那篇文章尝试过编译arm架构的最微型系统,那么建议您去try一下!
安装Rust
$ curl https://sh.rustup.rs -sSf | sh
如果您安装了Rust但没有nightly版,可以使用这个命令:
$ rustup install nightly
设置nightly为默认
$ rustup default nightly
安装拓展工具
$ cargo install bootimage
$ cargo install cargo-xbuild
$ rustup component add rust-src --toolchain=nightly
$ /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
$ brew install qemu
注意:qemu需要homebrew来安装,在中国安装homebrew可能是最麻烦的事,您可以去百度寻找解决方案或自行挂 梯子
开始书写代码
首先用cargo
来创建项目
$ cargo new apps
打开apps文件,然后创建一个叫做apps.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": "apps",
"linker": "rust-lld",
"linker-flavor": "ld.lld",
"executables": true,
"features": "-mmx,-sse,+soft-float",
"disable-redzone": true,
"panic-strategy": "abort"
}
接下来就是修改Cargo.toml
,就像这样:
[dependencies]
bootloader_precompiled = "0.3.0"
mars_vga = "0.0.1"
[profile.dev]
panic = "abort"
[profile.release]
panic = "abort"
[package.metadata.bootimage]
default-target = "apps.json"
然后我们打开src/main.rs,改成这样:
#![feature(core_intrinsics)]
#![no_std]
#![no_main]
// 使用 #[macro_use] 来表明使用 vga crate 的宏命令:print! 和 println!
#[macro_use]
extern crate mars_vga;
extern crate bootloader_precompiled;
use core::intrinsics;
use core::panic::PanicInfo;
#[panic_handler]
#[no_mangle]
fn panic(_info: &PanicInfo) -> ! {
unsafe { intrinsics::abort() }
}
// 系统入口处
#[no_mangle]
pub fn _start() -> ! {
println!("hello world");
loop {}
}
当然您可能会说我看不懂,你就这么让我这样做,我怎么能懂?
没问题的,让我们先把系统写好后再慢慢跟您讲。
运行
打开终端,然后跳转到apps文件夹里,执行这些命令:
$ bootimage build
$ bootimage run
经过长久(如果下载时间过长,建议更换dns,比如这个: 1.0.0.1或1.1.1.1)的编译后终于运行了!
解释原理
现在回过头看您的代码,是否有注意到这个crate吗:mars_vga
?,这是我借鉴别人的资料写的一个crate(如果您不知道什么是crate,可以在https://kaisery.github.io/trpl-zh-cn/这个中文教程里找到,这是一个Rust教程)
这个crate里我添加了宏函数,即println!
和print!
,这样您就可以直接打印出一串字了,但不支持中文。这是一个很好的方法,也是Rust独具一格的优点,即您可以将一些可以分开的方法打包成crate然后上传到crate.io里,当需要添加到项目里时直接在Cargo.toml
这个文件里添加crate
就可以了,如果您对这个mars_vga
感兴趣,可以用Idea IDE工具打开这个项目,然后就可以查看这个crate
的源码了
我们创建了一个apps.json
文件,这个是bootimage
工具编译时需要的东西,有了bootimage
工具我们就可以实现交叉编译(这个平台编译另一个平台的东西)。
#![feature(core_intrinsics)]
#![no_std]
#![no_main]
// 使用 #[macro_use] 来表明使用 vga crate 的宏命令:print! 和 println!
#[macro_use]
extern crate mars_vga;
extern crate bootloader_precompiled;
use core::intrinsics;
use core::panic::PanicInfo;
#[panic_handler]
#[no_mangle]
fn panic(_info: &PanicInfo) -> ! {
unsafe { intrinsics::abort() }
}
// 系统入口处
#[no_mangle]
pub fn _start() -> ! {
println!("hello world");
loop {}
}
![no_std]#
用来告诉Rust编译器:我们不使用Rust标准库,在系统开发中,内存、线程、文件系统我们需要自己写,Rust标准库不适用,我们只使用Rust的核心库(core)就可以了![no_main]
用来告诉Rust:我们没有main方法,我们在做系统。因此Rust允许我们自己创建main方法。#[macro_use]
用来告诉Rust:我想使用我自己建的宏函数。这个参数让Rust允许使用我们自建的宏函数。#[no_mangle]
用来告诉Rust:我想定义一个方法,它的名字与标准库里一个叫做painc
方法一样。
#[panic_handler]
#[no_mangle]
fn panic(_info: &PanicInfo) -> ! {
unsafe { intrinsics::abort() }
}
这里是异常处理方法,因为这个系统还没有更高级的东西,因此这个方法只有终止的功能
// 系统入口处
#[no_mangle]
pub fn _start() -> ! {
println!("hello world");
loop {}
}
这是我们定义了_start()
方法,为什么它不叫main
呢?因为main
仅仅是内核启动点,而最先启动的应该是_boot
。那为什么会添加一个-> !
?这是因为系统一旦启动,而且永远也不返回参数,系统也永远不会执行完就停止,所以我们在这个方法里添加了loop{}
还有吗???
做一个系统就这么点代码吗?当然不是,你看到的只是这几十行代码,而其他代码都是被封装成crate
了。那些为计算机科学作出贡献的人,不断的、夜以继日的帮助着我们,我们可能只写了几十行,但在这几十行代码的背后,就有那么一群人写了几千行,尽了最大了努力来让我们写出高效美丽的代码!感谢这群人、这群“疯子”!
关于这件事
有人可能遇到过这种事情:好声好气告诉别人不要乱扔垃圾,结果被人骂“读书读傻了”,可能做错了一点点事情,也被骂“读书读傻了”
如果这个世上有很多的这样的人,想象一下这个世界会发生怎样的变化?世界很残酷,但是我们仍然关爱老人,以前肉弱强食,但是现在我们关爱残疾、关爱病人、帮助着在这个世界无法自足的人们。我们有着自己选择的权利,有着一颗炙热的心,每个人有不同的活法,但请做一个道德的人,如果这都无法做到的话,我也会不客气的。