1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
#![no_std]
#![feature(asm)]
#![deny(warnings, unused_must_use, missing_docs)]
extern crate alloc;
#[macro_use]
extern crate log;
use {
alloc::{boxed::Box, string::String, sync::Arc, vec::Vec},
core::{future::Future, pin::Pin},
kernel_hal::{GeneralRegs, MMUFlags},
linux_object::{
fs::{vfs::FileSystem, INodeExt},
loader::LinuxElfLoader,
process::ProcessExt,
thread::ThreadExt,
},
linux_syscall::Syscall,
zircon_object::task::*,
};
pub fn run(args: Vec<String>, envs: Vec<String>, rootfs: Arc<dyn FileSystem>) -> Arc<Process> {
let job = Job::root();
let proc = Process::create_linux(&job, rootfs.clone()).unwrap();
let thread = Thread::create_linux(&proc).unwrap();
let loader = LinuxElfLoader {
#[cfg(feature = "std")]
syscall_entry: kernel_hal_unix::syscall_entry as usize,
#[cfg(not(feature = "std"))]
syscall_entry: 0,
stack_pages: 8,
root_inode: rootfs.root_inode(),
};
let inode = rootfs.root_inode().lookup(&args[0]).unwrap();
let data = inode.read_as_vec().unwrap();
let path = args[0].clone();
let (entry, sp) = loader.load(&proc.vmar(), &data, args, envs, path).unwrap();
thread
.start(entry, sp, 0, 0, thread_fn)
.expect("failed to start main thread");
proc
}
async fn new_thread(thread: CurrentThread) {
loop {
let mut cx = thread.wait_for_run().await;
if thread.state() == ThreadState::Dying {
break;
}
trace!("go to user: {:#x?}", cx);
kernel_hal::context_run(&mut cx);
trace!("back from user: {:#x?}", cx);
match cx.trap_num {
0x100 => handle_syscall(&thread, &mut cx.general).await,
0x20..=0x3f => {
kernel_hal::InterruptManager::handle(cx.trap_num as u8);
if cx.trap_num == 0x20 {
kernel_hal::yield_now().await;
}
}
0xe => {
let vaddr = kernel_hal::fetch_fault_vaddr();
let flags = if cx.error_code & 0x2 == 0 {
MMUFlags::READ
} else {
MMUFlags::WRITE
};
error!("page fualt from user mode {:#x} {:#x?}", vaddr, flags);
let vmar = thread.proc().vmar();
match vmar.handle_page_fault(vaddr, flags) {
Ok(()) => {}
Err(_) => {
panic!("Page Fault from user mode {:#x?}", cx);
}
}
}
_ => panic!("not supported interrupt from user mode. {:#x?}", cx),
}
thread.end_running(cx);
}
}
fn thread_fn(thread: CurrentThread) -> Pin<Box<dyn Future<Output = ()> + Send + 'static>> {
Box::pin(new_thread(thread))
}
async fn handle_syscall(thread: &CurrentThread, regs: &mut GeneralRegs) {
trace!("syscall: {:#x?}", regs);
let num = regs.rax as u32;
let args = [regs.rdi, regs.rsi, regs.rdx, regs.r10, regs.r8, regs.r9];
let mut syscall = Syscall {
thread,
#[cfg(feature = "std")]
syscall_entry: kernel_hal_unix::syscall_entry as usize,
#[cfg(not(feature = "std"))]
syscall_entry: 0,
thread_fn,
regs,
};
regs.rax = syscall.syscall(num, args).await as usize;
}