写在前面
本随笔是非常菜的菜鸡写的。如有问题请及时提出。
可以联系:1160712160@qq.com
GitHhub:https://github.com/WindDevil (目前啥也没有
批处理操作系统的启动和运行流程
要想把本章实现的那些模块全部都串联在一起以实现运行一个批处理操作系统,回顾本章内容,思考批处理操作系统的运行流程.
可以看到本章完成的内容大概如图所示:
可以看到在内核层,最重要的就是实现了batch
来加载程序和切换程序,以及trap
用来处理用户层的请求.
因此,我们只需要在main.rs
中添加这两个模块的初始化即可.
编写main.rs
主要是三部分:
- 引入上述编写模块
- 嵌入
link_app.S
- 引入
batch
,trap
,syscall
- 嵌入
- 初始化模块
- 开始运行用户态APP
需要添加的内容就这么多:
pub mod batch;
pub mod syscall;
pub mod trap;global_asm!(include_str!("link_app.S"));
pub fn rust_main() -> ! {trap::init();batch::init();batch::run_next_app();
}
最终实现的main.rs
:
//! The main module and entrypoint
//!
//! Various facilities of the kernels are implemented as submodules. The most
//! important ones are:
//!
//! - [`trap`]: Handles all cases of switching from userspace to the kernel
//! - [`syscall`]: System call handling and implementation
//!
//! The operating system also starts in this module. Kernel code starts
//! executing from `entry.asm`, after which [`rust_main()`] is called to
//! initialize various pieces of functionality. (See its source code for
//! details.)
//!
//! We then call [`batch::run_next_app()`] and for the first time go to
//! userspace.#![deny(missing_docs)]
#![deny(warnings)]
#![no_std]
#![no_main]
#![feature(panic_info_message)]use core::arch::global_asm;use log::*;
#[macro_use]
mod console;
pub mod batch;
mod lang_items;
mod logging;
mod sbi;
mod sync;
pub mod syscall;
pub mod trap;global_asm!(include_str!("entry.asm"));
global_asm!(include_str!("link_app.S"));/// clear BSS segment
fn clear_bss() {extern "C" {fn sbss();fn ebss();}unsafe {core::slice::from_raw_parts_mut(sbss as usize as *mut u8, ebss as usize - sbss as usize).fill(0);}
}/// the rust entry-point of os
#[no_mangle]
pub fn rust_main() -> ! {extern "C" {fn stext(); // begin addr of text segmentfn etext(); // end addr of text segmentfn srodata(); // start addr of Read-Only data segmentfn erodata(); // end addr of Read-Only data ssegmentfn sdata(); // start addr of data segmentfn edata(); // end addr of data segmentfn sbss(); // start addr of BSS segmentfn ebss(); // end addr of BSS segmentfn boot_stack_lower_bound(); // stack lower boundfn boot_stack_top(); // stack top}clear_bss();logging::init();println!("[kernel] Hello, world!");trace!("[kernel] .text [{:#x}, {:#x})",stext as usize,etext as usize);debug!("[kernel] .rodata [{:#x}, {:#x})",srodata as usize, erodata as usize);info!("[kernel] .data [{:#x}, {:#x})",sdata as usize, edata as usize);warn!("[kernel] boot_stack top=bottom={:#x}, lower_bound={:#x}",boot_stack_top as usize, boot_stack_lower_bound as usize);error!("[kernel] .bss [{:#x}, {:#x})", sbss as usize, ebss as usize);trap::init();batch::init();batch::run_next_app();
}
编译运行
使用第一章就编写好的Makefile
文件实现一键编译运行:
cd os
make run
第一次编译运行:
error: expected expression, found keyword `extern`--> src/batch.rs:94:13|
94 | extern "C" | ^^^^^^ expected expressionerror: cannot find macro `asm` in this scope--> src/batch.rs:84:9|
84 | asm!("fence.i")| ^^^|
help: consider importing this macro|
1 + use core::arch::asm;|error: cannot find macro `global_asm` in this scope--> src/trap/mod.rs:3:1|
3 | global_asm!(include_str!("trap.S"));| ^^^^^^^^^^|
help: consider importing one of these items|
3 + use core::arch::global_asm;|
3 + use crate::global_asm;|error[E0412]: cannot find type `TrapContext` in this scope--> src/batch.rs:34:36|
34 | pub fn push_context(&self, cx: TrapContext) -> &'static mut TrapContext {| ^^^^^^^^^^^ not found in this scopeerror[E0412]: cannot find type `TrapContext` in this scope--> src/batch.rs:34:65|
34 | pub fn push_context(&self, cx: TrapContext) -> &'static mut TrapContext {| ^^^^^^^^^^^ not found in this scopeerror[E0412]: cannot find type `TrapContext` in this scope--> src/batch.rs:35:60|
35 | let cx_ptr = (self.get_sp() - core::mem::size_of::<TrapContext>()) as *mut TrapContext;| ^^^^^^^^^^^ not found in this scope|
help: you might be missing a type parameter|
30 | impl<TrapContext> KernelStack {| +++++++++++++error[E0412]: cannot find type `TrapContext` in this scope--> src/batch.rs:35:84|
35 | let cx_ptr = (self.get_sp() - core::mem::size_of::<TrapContext>()) as *mut TrapContext;| ^^^^^^^^^^^ not found in this scopeerror[E0412]: cannot find type `RefCell` in this scope--> src/sync/up.rs:5:12|
5 | inner: RefCell<T>,| ^^^^^^^ not found in this scope|
help: consider importing this struct|
3 + use core::cell::RefCell;|error[E0433]: failed to resolve: use of undeclared type `RefCell`--> src/sync/up.rs:14:23|
14 | Self { inner: RefCell::new(value) }| ^^^^^^^ use of undeclared type `RefCell`|
help: consider importing this struct|
3 + use core::cell::RefCell;|error[E0412]: cannot find type `RefMut` in this scope--> src/sync/up.rs:17:39|
17 | pub fn exclusive_access(&self) -> RefMut<'_, T> {| ^^^^^^ not found in this scope|
help: consider importing this struct|
3 + use core::cell::RefMut;|error[E0412]: cannot find type `TrapContext` in this scope--> src/trap/mod.rs:13:30|
13 | pub fn trap_handler(cx: &mut TrapContext) -> &mut TrapContext {| ^^^^^^^^^^^ not found in this scopeerror[E0412]: cannot find type `TrapContext` in this scope--> src/trap/mod.rs:13:51|
13 | pub fn trap_handler(cx: &mut TrapContext) -> &mut TrapContext {| ^^^^^^^^^^^ not found in this scopeerror[E0425]: cannot find function `syscall` in this scope--> src/trap/mod.rs:19:24|
19 | cx.x[10] = syscall(cx.x[17], [cx.x[10], cx.x[11], cx.x[12]]) as usize;| ^^^^^^^ not found in this scope|
help: consider importing this function|
3 + use crate::syscall::syscall;|error[E0425]: cannot find function `run_next_app` in this scope--> src/trap/mod.rs:24:13|
24 | run_next_app();| ^^^^^^^^^^^^ not found in this scope|
help: consider importing this function|
3 + use crate::batch::run_next_app;|error[E0425]: cannot find function `run_next_app` in this scope--> src/trap/mod.rs:28:13|
28 | run_next_app();| ^^^^^^^^^^^^ not found in this scope|
help: consider importing this function|
3 + use crate::batch::run_next_app;|error[E0425]: cannot find function `init` in module `batch`--> src/main.rs:88:12|
88 | batch::init();| ^^^^ not found in `batch`|
help: consider importing one of these items|
23 + use crate::logging::init;|
23 + use crate::trap::init;|
help: if you import `init`, refer to it directly|
88 - batch::init();
88 + init();|error[E0308]: mismatched types--> src/batch.rs:80:41|
80 | core::slice::from_raw_parts_mut(APP_BASE_ADDRESS as *const u8, APP_SIZE_LIMIT).fill(0);| ------------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ types differ in mutability| || arguments to this function are incorrect|= note: expected raw pointer `*mut _`found raw pointer `*const u8`
note: function defined here--> /home/winddevil/.rustup/toolchains/nightly-2024-05-01-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/slice/raw.rs:147:21|
147 | pub const unsafe fn from_raw_parts_mut<'a, T>(data: *mut T, len: usize) -> &'a mut [T] {| ^^^^^^^^^^^^^^^^^^error[E0599]: the method `get` exists for struct `Lazy<UPSafeCell<AppManager>>`, but its trait bounds were not satisfied--> src/batch.rs:88:1|
88 | / lazy_static!
89 | | {
90 | | static ref APP_MANAGER: UPSafeCell<AppManager> = unsafe
91 | | {
... |
110 | | };
111 | | }| |_^ method cannot be called on `Lazy<UPSafeCell<AppManager>>` due to unsatisfied trait bounds|::: src/sync/up.rs:3:1|
3 | pub struct UPSafeCell<T> {| ------------------------ doesn't satisfy `UPSafeCell<AppManager>: Sized`|= note: the following trait bounds were not satisfied:`{type error}: Sized`which is required by `UPSafeCell<AppManager>: Sized`= note: this error originates in the macro `__lazy_static_internal` which comes from the expansion of the macro `lazy_static` (in Nightly builds, run with -Z macro-backtrace for more info)error[E0433]: failed to resolve: use of undeclared type `TrapContext`--> src/batch.rs:126:13|
126 | TrapContext::app_init_context(APP_BASE_ADDRESS, USER_STACK.get_sp())| ^^^^^^^^^^^ use of undeclared type `TrapContext`error[E0425]: cannot find function `sys_write` in this scope--> src/syscall/mod.rs:5:26|
5 | SYSCALL_WRITE => sys_write(args[0], args[1] as *const u8, args[2]),| ^^^^^^^^^ not found in this scopeerror[E0425]: cannot find function `sys_exit` in this scope--> src/syscall/mod.rs:6:25|
6 | SYSCALL_EXIT => sys_exit(args[0] as i32),| ^^^^^^^^ not found in this scopeerror[E0433]: failed to resolve: use of undeclared crate or module `stvec`--> src/trap/mod.rs:8:9|
8 | stvec::write(__alltraps as usize, TrapMode::Direct);| ^^^^^ use of undeclared crate or module `stvec`error[E0433]: failed to resolve: use of undeclared type `TrapMode`--> src/trap/mod.rs:8:43|
8 | stvec::write(__alltraps as usize, TrapMode::Direct);| ^^^^^^^^ use of undeclared type `TrapMode`error[E0433]: failed to resolve: use of undeclared crate or module `scause`--> src/trap/mod.rs:14:18|
14 | let scause = scause::read();| ^^^^^^ use of undeclared crate or module `scause`error[E0433]: failed to resolve: use of undeclared crate or module `stval`--> src/trap/mod.rs:15:17|
15 | let stval = stval::read();| ^^^^^ use of undeclared crate or module `stval`error: unused variable: `metadata`--> src/logging.rs:9:23|
9 | fn enabled(&self, metadata: &Metadata) -> bool | ^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_metadata`|
note: the lint level is defined here--> src/main.rs:18:9|
18 | #![deny(warnings)]| ^^^^^^^^= note: `#[deny(unused_variables)]` implied by `#[deny(warnings)]`error[E0433]: failed to resolve: use of undeclared type `Exception`--> src/trap/mod.rs:26:25|
26 | Trap::Exception(Exception::IllegalInstruction) => {| ^^^^^^^^^ use of undeclared type `Exception`error[E0433]: failed to resolve: use of undeclared type `Trap`--> src/trap/mod.rs:26:9|
26 | Trap::Exception(Exception::IllegalInstruction) => {| ^^^^ use of undeclared type `Trap`error[E0433]: failed to resolve: use of undeclared type `Exception`--> src/trap/mod.rs:22:25|
22 | Trap::Exception(Exception::StorePageFault) => {| ^^^^^^^^^ use of undeclared type `Exception`error[E0433]: failed to resolve: use of undeclared type `Trap`--> src/trap/mod.rs:22:9|
22 | Trap::Exception(Exception::StorePageFault) => {| ^^^^ use of undeclared type `Trap`error[E0433]: failed to resolve: use of undeclared type `Exception`--> src/trap/mod.rs:21:25|
21 | Trap::Exception(Exception::StoreFault) || ^^^^^^^^^ use of undeclared type `Exception`error[E0433]: failed to resolve: use of undeclared type `Trap`--> src/trap/mod.rs:17:9|
17 | Trap::Exception(Exception::UserEnvCall) => {| ^^^^ use of undeclared type `Trap`error[E0433]: failed to resolve: use of undeclared type `Exception`--> src/trap/mod.rs:17:25|
17 | Trap::Exception(Exception::UserEnvCall) => {| ^^^^^^^^^ use of undeclared type `Exception`error[E0433]: failed to resolve: use of undeclared type `Trap`--> src/trap/mod.rs:21:9|
21 | Trap::Exception(Exception::StoreFault) || ^^^^ use of undeclared type `Trap`Some errors have detailed explanations: E0308, E0412, E0425, E0433, E0599.
For more information about an error, try `rustc --explain E0308`.
error: could not compile `os` (bin "os") due to 34 previous errors
make: *** [Makefile:42: kernel] Error 101
看到大段的报错不要着急,首先先看容易解决,能够解决的.
首先是在batch.rs
里加入use core::arch::asm;
:
error: cannot find macro `asm` in this scope--> src/batch.rs:84:9|
84 | asm!("fence.i")| ^^^|
help: consider importing this macro|
1 + use core::arch::asm;|
同样地,在src/trap/mod.rs
里边加入use core::arch::global_asm;
:
error: cannot find macro `global_asm` in this scope--> src/trap/mod.rs:3:1|
3 | global_asm!(include_str!("trap.S"));| ^^^^^^^^^^|
help: consider importing one of these items|
3 + use core::arch::global_asm;|
3 + use crate::global_asm;|
在batch.rs
加入use crate::trap::TrapContext;
,这时候我们发现实际上在src/trap/mod.rs
里也没有声明TrapContext
则在里边声明mod context;
:
error[E0412]: cannot find type `TrapContext` in this scope--> src/batch.rs:34:36|
34 | pub fn push_context(&self, cx: TrapContext) -> &'static mut TrapContext {| ^^^^^^^^^^^ not found in this scope
后续有很多找不到TrapContext
的问题,可能都会解决.
在src/sync/up.rs
里加入use core::cell::{RefCell, RefMut};
:
error[E0412]: cannot find type `RefCell` in this scope--> src/sync/up.rs:5:12|
5 | inner: RefCell<T>,| ^^^^^^^ not found in this scope|
help: consider importing this struct|
3 + use core::cell::RefCell;|
error[E0412]: cannot find type `RefMut` in this scope--> src/sync/up.rs:17:39|
17 | pub fn exclusive_access(&self) -> RefMut<'_, T> {| ^^^^^^ not found in this scope|
help: consider importing this struct|
3 + use core::cell::RefMut;|
这里还有一个比较难搞的依赖问题,如果这个module
不是自己实现的,那么一般考虑外部依赖问题,
error[E0433]: failed to resolve: use of undeclared crate or module `riscv`--> src/trap/context.rs:2:5|
2 | use riscv::register::sstatus::{self, Sstatus, SPP};| ^^^^^ use of undeclared crate or module `riscv`
在Cargo.toml
加入riscv = { git = "https://github.com/rcore-os/riscv", features = ["inline-asm"] }
同理,把所有的这种依赖性问题都解决, 不一定 是对应着这个报错列表来,而是可以选择根据rust-analyzer
自动报错的内容,顺便改一下.
再次编译一下,发现有很多类似的报错:
error: missing documentation for an associated function
这意味着你在编译一个 Rust 项目时启用了某个 lint (编译时检查规则),该 lint 要求所有关联函数都必须有文档注释.
那么我们只需要给这些函数加上注释就行了.
还有一个新的问题:
error: unused variable: `metadata`--> src/logging.rs:9:23|
9 | fn enabled(&self, metadata: &Metadata) -> bool | ^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_metadata`|
因为这个metadata
在enbaled
函数中没有被调用,因此需要在其前面加一个下划线_
,从而声明这个参数是故意不被调用的.
另外.trap.S
需要被链接到.text
部分,并且需要声明__alltraps
和__restore
,因此需要加入这个.
.section .text.globl __alltraps.globl __restore
最终得到的trap.S
为:
.altmacro
.macro SAVE_GP nsd x\n, \n*8(sp)
.endm
.macro LOAD_GP nld x\n, \n*8(sp)
.endm.section .text.globl __alltraps.globl __restore.align 2
__alltraps:csrrw sp, sscratch, sp# now sp->kernel stack, sscratch->user stack# allocate a TrapContext on kernel stackaddi sp, sp, -34*8# save general-purpose registerssd x1, 1*8(sp)# skip sp(x2), we will save it latersd x3, 3*8(sp)# skip tp(x4), application does not use it# save x5~x31.set n, 5.rept 27SAVE_GP %n.set n, n+1.endr# we can use t0/t1/t2 freely, because they were saved on kernel stackcsrr t0, sstatuscsrr t1, sepcsd t0, 32*8(sp)sd t1, 33*8(sp)# read user stack from sscratch and save it on the kernel stackcsrr t2, sscratchsd t2, 2*8(sp)# set input argument of trap_handler(cx: &mut TrapContext)mv a0, spcall trap_handler__restore:# case1: start running app by __restore# case2: back to U after handling trapmv sp, a0# now sp->kernel stack(after allocated), sscratch->user stack# restore sstatus/sepcld t0, 32*8(sp)ld t1, 33*8(sp)ld t2, 2*8(sp)csrw sstatus, t0csrw sepc, t1csrw sscratch, t2# restore general-purpuse registers except sp/tpld x1, 1*8(sp)ld x3, 3*8(sp).set n, 5.rept 27LOAD_GP %n.set n, n+1.endr# release TrapContext on kernel stackaddi sp, sp, 34*8# now sp->kernel stack, sscratch->user stackcsrrw sp, sscratch, spsret
最后运行结果是:
[rustsbi] RustSBI version 0.3.1, adapting to RISC-V SBI v1.0.0
.______ __ __ _______.___________. _______..______ __
| _ \ | | | | / | | / || _ \ | |
| |_) | | | | | | (----`---| |----`| (----`| |_) || |
| / | | | | \ \ | | \ \ | _ < | |
| |\ \----.| `--' |.----) | | | .----) | | |_) || |
| _| `._____| \______/ |_______/ |__| |_______/ |______/ |__|
[rustsbi] Implementation : RustSBI-QEMU Version 0.2.0-alpha.2
[rustsbi] Platform Name : riscv-virtio,qemu
[rustsbi] Platform SMP : 1
[rustsbi] Platform Memory : 0x80000000..0x88000000
[rustsbi] Boot HART : 0
[rustsbi] Device Tree Region : 0x87000000..0x87000f02
[rustsbi] Firmware Address : 0x80000000
[rustsbi] Supervisor Address : 0x80200000
[rustsbi] pmp01: 0x00000000..0x80000000 (-wr)
[rustsbi] pmp02: 0x80000000..0x80200000 (---)
[rustsbi] pmp03: 0x80200000..0x88000000 (xwr)
[rustsbi] pmp04: 0x88000000..0x00000000 (-wr)
[kernel] Hello, world!
[kernel] num_app = 5
[kernel] app_0 [0x8020a038, 0x8020b360)
[kernel] app_1 [0x8020b360, 0x8020c730)
[kernel] app_2 [0x8020c730, 0x8020dcd8)
[kernel] app_3 [0x8020dcd8, 0x8020f090)
[kernel] app_4 [0x8020f090, 0x80210440)
[kernel] Loading app_0
Hello, world!
[kernel] Application exited with code 0
[kernel] Loading app_1
Into Test store_fault, we will insert an invalid store operation...
Kernel should kill this application!
[kernel] PageFault in application, kernel killed it.
[kernel] Loading app_2
3^10000=5079(MOD 10007)
3^20000=8202(MOD 10007)
3^30000=8824(MOD 10007)
3^40000=5750(MOD 10007)
3^50000=3824(MOD 10007)
3^60000=8516(MOD 10007)
3^70000=2510(MOD 10007)
3^80000=9379(MOD 10007)
3^90000=2621(MOD 10007)
3^100000=2749(MOD 10007)
Test power OK!
[kernel] Application exited with code 0
[kernel] Loading app_3
Try to execute privileged instruction in U Mode
Kernel should kill this application!
[kernel] IllegalInstruction in application, kernel killed it.
[kernel] Loading app_4
Try to access privileged CSR in U Mode
Kernel should kill this application!
[kernel] IllegalInstruction in application, kernel killed it.
All applications completed!
可以看到启动了批处理系统之后,一个个APP运行,然后会想起用户层lib.rs
中为每个app写得启动部分:
#[no_mangle]
#[link_section = ".text.entry"]
pub extern "C" fn _start() -> ! {clear_bss();exit(main());panic!("unreachable after sys_exit!");
}
每次运行之后,
- 因为触发了异常而退出
- 直接由
exit(main());
退出
都会陷入trap
,然后在trap_handler
里处理,只要不出现没有预期到的Expectation
都会调用run_next_app
,因此所有的app按顺序运行.
最后完美结束了这一章,我真是一条懒狗,怎么什么坑都要踩一遍.