Merge pull request #29 from HUST-OS/main

merge main to clean_up_the_code
This commit is contained in:
Chunchi Che 2021-04-25 00:05:39 +08:00 committed by GitHub
commit 114857add4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 361 additions and 315 deletions

View File

@ -6,19 +6,7 @@ mod user_syscall;
pub use user_syscall::user_trap_handler;
use config::*;
use crate::{
hart::KernelHartInfo,
memory::{
AddressSpaceId,
Satp,
VirtualPageNumber,
VirtualAddress,
PhysicalPageNumber,
KERNEL_MAP_OFFSET
}
};
use crate::memory::{AddressSpaceId, Satp, VirtualPageNumber, VirtualAddress,};
use bit_field::BitField;
pub enum SyscallResult {
@ -34,10 +22,10 @@ impl SyscallResult {
}
}
pub fn syscall(param: [usize; 6], func: usize, module: usize) -> SyscallResult {
pub fn syscall(param: [usize; 6], user_satp: usize, func: usize, module: usize) -> SyscallResult {
match module {
MODULE_PROCESS => do_process(param, func),
MODULE_TEST_INTERFACE => do_test_interfase(param, func),
MODULE_PROCESS => do_process(param, user_satp, func),
MODULE_TEST_INTERFACE => do_test_interface(param, user_satp, func),
MODULE_TASK => do_task(param, func),
_ => panic!("Unknown module {:x}", module),
}
@ -51,41 +39,44 @@ fn switch_next_task(param: [usize; 6], func: usize) -> SyscallResult {
todo!()
}
fn do_process(param: [usize; 6], func: usize) -> SyscallResult {
fn do_process(param: [usize; 6], user_satp: usize, func: usize) -> SyscallResult {
match func {
FUNC_PROCESS_EXIT => SyscallResult::Terminate(param[0] as i32),
FUNC_PROCESS_PANIC => panic!("User panic!"),
FUNC_PROCESS_PANIC => { //[line as usize, col as usize, f_buf, f_len, m_buf, m_len]
let [line, col, f_buf, f_len, m_buf, m_len] = param;
let user_satp = crate::memory::Satp::new(user_satp);
let file_name = if f_buf == 0 {
None
} else {
let slice = unsafe { get_user_buf(user_satp, f_buf, f_len) };
Some(core::str::from_utf8(slice).unwrap())
};
let msg = if m_buf == 0 {
None
} else {
let slice = unsafe { get_user_buf(user_satp, m_buf, m_len) };
Some(core::str::from_utf8(slice).unwrap())
};
let file_name = file_name.unwrap_or("<no file>");
let msg = msg.unwrap_or("<no message>");
println!("[Kernel] User process panicked at '{}', {}:{}:{}", msg, file_name, line, col);
SyscallResult::Terminate(-1)
},
_ => panic!("Unknown syscall process, func: {}, param: {:?}", func, param)
}
}
fn do_test_interfase(param: [usize; 6], func: usize) -> SyscallResult {
fn do_test_interface(param: [usize; 6], user_satp: usize, func: usize) -> SyscallResult {
match func {
FUNC_TEST_WRITE => {
let (asid, _fd, buf_ptr, buf_len) =
(param[0], param[1], param[2], param[3]); // 地址空间参数,文件描述符,缓冲区指针,缓冲区长度
// println!("[kernel] enter do_test_write with asid: {}, buf_ptr: {:#x}, buf_len: {}", asid, buf_ptr, buf_len);
let user_asid = unsafe { AddressSpaceId::from_raw(asid) };
if let Some(user_satp) = KernelHartInfo::get_satp(user_asid) {
let offset = buf_ptr.get_bits(0..12); // Sv39 里面虚拟地址偏移量为低 12 位
let vpn = VirtualPageNumber::floor(VirtualAddress(buf_ptr));
let ppn = user_satp.translate(vpn).unwrap();
unsafe {
let ptr = (ppn
.start_address()
.0
.wrapping_add(KERNEL_MAP_OFFSET)
.wrapping_add(offset) as *const u8)
.as_ref()
.unwrap();
let slice = core::slice::from_raw_parts(ptr, buf_len);
let str = core::str::from_utf8(slice).unwrap();
print!("{}", str);
SyscallResult::Procceed {code: 0, extra: buf_len}
}
} else {
panic!("User asid not found!")
let (_iface, buf_ptr, buf_len) =
(param[0], param[1], param[2]); // 调试接口编号,缓冲区指针,缓冲区长度
let user_satp = crate::memory::Satp::new(user_satp);
let slice = unsafe { get_user_buf(user_satp, buf_ptr, buf_len) };
for &byte in slice {
crate::sbi::console_putchar(byte as usize);
}
SyscallResult::Procceed { code: 0, extra: buf_len }
},
_ => panic!("Unknown syscall test, func: {}, param: {:?}", func, param)
}
@ -94,3 +85,13 @@ fn do_test_interfase(param: [usize; 6], func: usize) -> SyscallResult {
fn do_task(param: [usize; 6], func: usize) -> SyscallResult {
todo!()
}
unsafe fn get_user_buf<'a>(user_satp: Satp, buf_ptr: usize, buf_len: usize) -> &'a [u8] {
let offset = buf_ptr.get_bits(0..12); // Sv39 里面虚拟地址偏移量为低 12 位
let vpn = VirtualPageNumber::floor(VirtualAddress(buf_ptr));
let ppn = user_satp.translate(vpn).expect("no page fault");
let va = ppn.start_address().virtual_address_linear()
.0.wrapping_add(offset);
let ptr = (va as *const u8).as_ref().expect("non-null pointer");
core::slice::from_raw_parts(ptr, buf_len)
}

View File

@ -12,8 +12,8 @@ pub extern "C" fn user_trap_handler() {
unsafe {
asm!("mv {}, t2", out(reg) user_satp, options(nomem, nostack));
}
let user_satp = Satp::new(user_satp);
let swap_cx = unsafe { get_swap_cx(&user_satp) };
let user_satp_2 = Satp::new(user_satp);
let swap_cx = unsafe { get_swap_cx(&user_satp_2) };
// 从 SwapContext 中读东西
let a0 = swap_cx.x[9];
let a1 = swap_cx.x[10];
@ -34,18 +34,17 @@ pub extern "C" fn user_trap_handler() {
crate::sbi::shutdown();
},
Trap::Exception(scause::Exception::UserEnvCall) => {
let func = a6;
let param = [a0, a1, a2, a3, a4, a5];
match syscall(param, func, a7) {
match syscall(param, user_satp, a6, a7) {
SyscallResult::Procceed { code, extra} => {
swap_cx.x[9] = code;
swap_cx.x[10] = extra;
swap_cx.epc = swap_cx.epc.wrapping_add(4);
trap::switch_to_user(swap_cx, user_satp.inner())
trap::switch_to_user(swap_cx, user_satp)
},
SyscallResult::Retry => {
// 不跳过指令,继续运行
trap::switch_to_user(swap_cx, user_satp.inner())
trap::switch_to_user(swap_cx, user_satp)
},
SyscallResult::NextASID{ satp } => {
// 需要转到目标地址空间去运行

View File

@ -1,4 +1,4 @@
use crate::task::{TaskResult, SharedTaskHandle, KernelTask};
use crate::task::{TaskResult, KernelTask};
use woke::waker_ref;
use alloc::sync::Arc;
use core::{mem, task::{Poll, Context}};

View File

@ -265,9 +265,9 @@ fn breakpoint(trap_frame: &mut TrapFrame) -> *mut TrapFrame {
}
fn syscall(trap_frame: &mut TrapFrame) -> *mut TrapFrame {
println!("Syscall at {:#08x}", trap_frame.sepc);
println!("Syscall at {:#08x}; note that user_satp /*todo*/", trap_frame.sepc);
let param = [trap_frame.x[10], trap_frame.x[11], 0, 0, 0, 0]; // a0, a1
match do_syscall(param, trap_frame.x[16], trap_frame.x[17]) { // a6, a7
match do_syscall(param, 0/* todo */, trap_frame.x[16], trap_frame.x[17]) { // a6, a7
SyscallResult::Procceed { code, extra } => {
trap_frame.x[10] = code; // a0
trap_frame.x[11] = extra; // a1

View File

@ -0,0 +1,20 @@
#![no_std]
#![no_main]
#![feature(asm)]
#![feature(llvm_asm)]
extern crate alloc;
#[macro_use]
extern crate tornado_user;
use alloc::vec;
// 同步函数的例子没有调用execute_async_main
#[no_mangle]
fn main() -> i32 {
println!("[user] enter main!");
let mut test_v = vec![1, 2, 3, 4, 5];
test_v.iter_mut().for_each(|x| *x += 1);
assert_eq!(test_v, vec![2, 3, 4, 5, 6]);
println!("[User] alloc-test: success!");
0
}

View File

@ -6,38 +6,28 @@
extern crate alloc;
#[macro_use]
extern crate tornado_user;
use alloc::vec;
use core::future::Future;
use core::task::{Context, Poll};
use core::pin::Pin;
use tornado_user::{
SHARED_PAYLOAD_BASE,
shared,
task,
exit,
};
#[no_mangle]
fn main() -> ! {
let mut test_v = vec![1, 2, 3, 4, 5];
test_v.iter_mut().for_each(|x| *x += 1);
assert_eq!(test_v, vec![2, 3, 4, 5, 6]);
let shared_payload = unsafe { shared::SharedPayload::new(SHARED_PAYLOAD_BASE) };
let task = task::UserTask::new(FibonacciFuture::new(6));
unsafe {
/* todo: hart_id, asid */
shared_payload.add_task(0, tornado_user::shared::AddressSpaceId::from_raw(tornado_user::ADDRESS_SPACE_ID), task.task_repr());
}
shared::run_until_idle(
|| unsafe { shared_payload.peek_task(shared::user_should_switch) },
|task_repr| unsafe { shared_payload.delete_task(task_repr) }
);
// 用户态退出的系统调用
exit(0);
unreachable!()
async fn async_main() -> i32 {
// todo: 唤醒逻辑
tornado_user::spawn(async {
let ans = FibonacciFuture::new(5).await;
println!("[User] Fibonacci[5] = {}", ans);
});
let ans = FibonacciFuture::new(6).await;
println!("[User] Fibonacci[6] = {}", ans);
0
}
// 异步main函数由entry调用execute_async_main
#[no_mangle]
fn main() -> i32 {
tornado_user::execute_async_main(async_main())
}
struct FibonacciFuture {
a: usize,
b: usize,
@ -57,17 +47,17 @@ impl FibonacciFuture {
}
impl Future for FibonacciFuture {
type Output = ();
type Output = usize;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
if self.i == self.cnt {
println!("Fibonacci result: {}", self.a);
Poll::Ready(())
println!("Fibonacci {} result: {}", self.cnt, self.a);
Poll::Ready(self.a)
} else {
let t = self.a;
self.a += self.b;
self.b = t;
self.i += 1;
println!("Fibonacci: i = {}, a = {}, b = {}", self.i, self.a, self.b);
println!("Fibonacci {}: i = {}, a = {}, b = {}", self.cnt, self.i, self.a, self.b);
cx.waker().wake_by_ref();
Poll::Pending
}

View File

@ -0,0 +1,27 @@
use core::fmt::{self, Write};
use super::test_write;
struct Stdout;
impl Write for Stdout {
fn write_str(&mut self, s: &str) -> fmt::Result {
test_write(s.as_bytes());
Ok(())
}
}
pub fn print(args: fmt::Arguments) {
Stdout.write_fmt(args).unwrap();
}
#[macro_export]
macro_rules! print {
($fmt: literal $(, $($arg: tt)+)?) => {
$crate::console::print(format_args!($fmt $(, $($arg)+)?));
}
}
#[macro_export]
macro_rules! println {
($fmt: literal $(, $($arg: tt)+)?) => {
$crate::console::print(format_args!(concat!($fmt, "\n") $(, $($arg)+)?));
}
}

View File

@ -7,65 +7,108 @@
extern crate alloc;
#[macro_use]
pub mod console;
pub mod shared;
pub mod task;
use buddy_system_allocator::LockedHeap;
use core::future::Future;
const USER_HEAP_SIZE: usize = 32768;
pub static mut ADDRESS_SPACE_ID: usize = 0;
pub static mut SHARED_PAYLOAD_BASE: usize = 0;
const USER_HEAP_SIZE: usize = 64 * 1024;
static mut HEAP_SPACE: [u8; USER_HEAP_SIZE] = [0; USER_HEAP_SIZE];
static mut SHARED_PAYLOAD_BASE: usize = 0;
static mut ADDRESS_SPACE_ID: usize = 0;
#[global_allocator]
static HEAP: LockedHeap = LockedHeap::empty();
#[cfg_attr(not(test), panic_handler)]
pub fn panic_handler(_panic_info: &core::panic::PanicInfo) -> ! {
sys_panic();
pub fn panic_handler(panic_info: &core::panic::PanicInfo) -> ! {
let err = panic_info.message().unwrap().as_str();
if let Some(location) = panic_info.location() {
syscall::sys_panic(Some(location.file()), location.line(), location.column(), err);
} else {
syscall::sys_panic(None, 0, 0, err);
}
unreachable!()
}
#[cfg_attr(not(test), alloc_error_handler)]
pub fn handle_alloc_error(_layout: core::alloc::Layout) -> ! {
sys_panic();
unreachable!()
pub fn handle_alloc_error(layout: core::alloc::Layout) -> ! {
println!("[User] user alloc error, layout = {:?}", layout);
panic!("user alloc error: {:?}", layout)
}
#[no_mangle]
#[link_section = ".text.entry"]
pub extern "C" fn _start() -> ! {
let mut ret: usize;
let mut address_space_id: usize;
let mut shared_payload_base: usize;
unsafe {
// 从 gp 寄存器里面取出 shared_raw_table 的地址
asm!("mv {}, gp", out(reg) ret, options(nomem, nostack));
SHARED_PAYLOAD_BASE = ret;
asm!("mv {}, gp", out(reg) shared_payload_base, options(nomem, nostack));
SHARED_PAYLOAD_BASE = shared_payload_base;
// 从 tp 寄存器里面取出该用户态的地址空间编号
asm!("mv {}, tp", out(reg) ret, options(nomem, nostack));
ADDRESS_SPACE_ID = ret;
extern "C" {
fn sbss(); fn ebss();
}
asm!("mv {}, tp", out(reg) address_space_id, options(nomem, nostack));
ADDRESS_SPACE_ID = address_space_id;
}
extern "C" {
fn sbss(); fn ebss();
}
unsafe {
r0::zero_bss(&mut sbss as *mut _ as *mut u32, &mut ebss as *mut _ as *mut u32);
HEAP.lock().init(HEAP_SPACE.as_ptr() as usize, USER_HEAP_SIZE);
}
main()
let exit_code = main();
exit(exit_code);
unreachable!()
}
#[linkage = "weak"]
#[link_section = ".text"] // 必须指定否则llvm好像会把名字为“entry”的函数链接到最开始……
#[no_mangle]
fn main() -> ! {
fn main() -> i32 {
println!("[User] No main function found; user exit");
panic!("Can not find main!");
}
/// 运行一个异步的main函数在用户的entry函数里调用
/// 应该作为标准库的一部分,这里使用一个库函数来模拟有标准库的情况
pub fn execute_async_main(main: impl Future<Output = i32> + Send + Sync + 'static) -> i32 {
let shared_payload = unsafe { shared::SharedPayload::new(SHARED_PAYLOAD_BASE) };
let asid = unsafe { shared::AddressSpaceId::from_raw(ADDRESS_SPACE_ID) };
static mut EXIT_CODE: i32 = 0;
let main_task = task::UserTask::new(async move {
unsafe { EXIT_CODE = main.await };
});
unsafe {
shared_payload.add_task(0/* todo */, asid, main_task.task_repr());
}
shared::run_until_ready(
|| unsafe { shared_payload.peek_task(shared::user_should_switch) },
|task_repr| unsafe { shared_payload.delete_task(task_repr) }
);
unsafe { EXIT_CODE }
}
/// 生成一个新的任务
pub fn spawn(future: impl Future<Output = ()> + Send + Sync + 'static) {
let shared_payload = unsafe { shared::SharedPayload::new(SHARED_PAYLOAD_BASE) };
let asid = unsafe { shared::AddressSpaceId::from_raw(ADDRESS_SPACE_ID) };
let task = task::UserTask::new(future);
unsafe {
shared_payload.add_task(0/* todo */, asid, task.task_repr());
}
}
use syscall::*;
pub fn exit(exit_code: i32) -> SyscallResult { sys_exit(exit_code) }
pub fn do_yield(next_asid: usize) -> SyscallResult { sys_yield(next_asid) }
pub fn test_write(buf: &[u8]) -> SyscallResult { unsafe { sys_test_write(ADDRESS_SPACE_ID, buf) }}
pub fn test_write(buf: &[u8]) -> SyscallResult { sys_test_write(buf) }
mod syscall {
const MODULE_PROCESS: usize = 0x114514;
const MODULE_TEST_INTERFACE: usize = 0x233666;
@ -186,51 +229,23 @@ mod syscall {
}
pub fn sys_exit(exit_code: i32) -> SyscallResult {
syscall_1(MODULE_PROCESS, FUNC_PROCESS_EXIT, exit_code as usize) // 暂时放着,写法不规范
syscall_1(MODULE_PROCESS, FUNC_PROCESS_EXIT, exit_code as usize)
}
pub fn sys_panic() -> SyscallResult {
syscall_0(MODULE_PROCESS, FUNC_PROCESS_PANIC)
pub fn sys_panic(file_name: Option<&str>, line: u32, col: u32, msg: Option<&str>) -> SyscallResult {
let (f_buf, f_len) = file_name.map(|s| (s.as_ptr() as usize, s.len())).unwrap_or((0, 0));
let (m_buf, m_len) = msg.map(|s| (s.as_ptr() as usize, s.len())).unwrap_or((0, 0));
syscall_6(
MODULE_PROCESS, FUNC_PROCESS_PANIC,
[line as usize, col as usize, f_buf, f_len, m_buf, m_len]
)
}
pub fn sys_yield(next_asid: usize) -> SyscallResult {
todo!()
}
pub fn sys_test_write(asid: usize, buf: &[u8]) -> SyscallResult {
syscall_4(MODULE_TEST_INTERFACE, FUNC_TEST_WRITE, [asid, 0, buf.as_ptr() as usize, buf.len()])
}
}
#[macro_use]
pub mod console {
use core::fmt::{self, Write};
use super::test_write;
struct Stdout;
impl Write for Stdout {
fn write_str(&mut self, s: &str) -> fmt::Result {
test_write(s.as_bytes());
Ok(())
}
}
pub fn print(args: fmt::Arguments) {
Stdout.write_fmt(args).unwrap();
}
#[macro_export]
macro_rules! print {
($fmt: literal $(, $($arg: tt)+)?) => {
$crate::console::print(format_args!($fmt $(, $($arg)+)?));
}
}
#[macro_export]
macro_rules! println {
($fmt: literal $(, $($arg: tt)+)?) => {
$crate::console::print(format_args!(concat!($fmt, "\n") $(, $($arg)+)?));
}
pub fn sys_test_write(buf: &[u8]) -> SyscallResult {
syscall_3(MODULE_TEST_INTERFACE, FUNC_TEST_WRITE, [0, buf.as_ptr() as usize, buf.len()])
}
}

View File

@ -35,7 +35,7 @@ pub extern "C" fn user_should_switch(_handle: &SharedTaskHandle) -> bool {
}
// 该执行器目前是测试使用,当轮询到一个完成的任务就退出了
pub fn run_until_idle(
pub fn run_until_ready(
peek_task: impl Fn() -> TaskResult,
delete_task: impl Fn(usize) -> bool,
) {
@ -43,15 +43,11 @@ pub fn run_until_idle(
let task = peek_task();
println!(">>> user executor: next task = {:x?}", task);
match task {
TaskResult::Task(task_repr) => {
// 在相同的(内核)地址空间里面
TaskResult::Task(task_repr) => { // 在相同的地址空间里面
let task: Arc<UserTask> = unsafe { Arc::from_raw(task_repr as *mut _) };
task.mark_sleep();
// make a waker for our task
let waker = waker_ref(&task);
// poll our future and give it a waker
let mut context = Context::from_waker(&*waker);
println!(">>> User executor: task = {:p}", task);
let ret = task.future.lock().as_mut().poll(&mut context);
if let Poll::Pending = ret {
mem::forget(task); // 不要释放task的内存它将继续保存在内存中被使用
@ -63,7 +59,9 @@ pub fn run_until_idle(
// 让出操作
do_yield(next_asid);
},
TaskResult::Finished => break
TaskResult::Finished => {
break;
}
}
}
}

View File

@ -13,15 +13,12 @@ use core::pin::Pin;
use alloc::boxed::Box;
use core::future::Future;
use core::sync::atomic::{AtomicUsize, Ordering};
use super::shared::{AddressSpaceId};
/// 临时的用户态任务实现
pub struct UserTask {
/// 任务的编号
pub id: UserTaskId,
/// 任务所属的地址空间
pub asid: AddressSpaceId,
/// 任务信息的可变部分
pub inner: Mutex<UserTaskInner>,
/// 任务的 future
@ -64,7 +61,6 @@ impl UserTask {
Arc::new(
UserTask {
id,
asid: unsafe { AddressSpaceId::from_raw(crate::ADDRESS_SPACE_ID) },
inner: Mutex::new(UserTaskInner {
sleeping: false,
finished: false,