Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add basic userspace shell #548

Merged
merged 16 commits into from
Nov 21, 2023
Binary file added dsk/bin/exec
Binary file not shown.
Binary file modified dsk/bin/hello
Binary file not shown.
1 change: 1 addition & 0 deletions src/api/allocator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,6 @@ unsafe impl GlobalAlloc for UserspaceAllocator{
}
}

#[allow(dead_code)]
#[cfg_attr(feature = "userspace", global_allocator)]
static ALLOCATOR: UserspaceAllocator = UserspaceAllocator;
30 changes: 30 additions & 0 deletions src/bin/exec.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#![no_std]
#![no_main]

extern crate alloc;

use alloc::string::String;
use alloc::vec::Vec;
use moros::api::io;
use moros::api::syscall;
use moros::api::process;
use moros::entry_point;

entry_point!(main);

fn main(_args: &[&str]) {
loop {
syscall::write(1, "\n> ".as_bytes());
let line = io::stdin().read_line();
let cmd = line.trim();
if cmd == "quit" {
syscall::exit(process::ExitCode::Success);
} else {
//let args: Vec<&str> = cmd.split(' ').collect();
let args = Vec::new();
let mut path = String::from("/bin/");
path.push_str(cmd);
let _ = process::spawn(&path, &args);
}
}
}
35 changes: 26 additions & 9 deletions src/sys/process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,14 @@ use x86_64::structures::idt::InterruptStackFrameValue;
use x86_64::structures::paging::{FrameAllocator, OffsetPageTable, PageTable, PhysFrame};

const MAX_HANDLES: usize = 64;
const MAX_PROCS: usize = 2; // TODO: Update this when more than one process can run at once
const MAX_PROCS: usize = 4; // TODO: Update this when more than one process can run at once
const MAX_PROC_SIZE: usize = 10 << 20; // 10 MB

pub static PID: AtomicUsize = AtomicUsize::new(0);
pub static MAX_PID: AtomicUsize = AtomicUsize::new(1);

lazy_static! {
pub static ref PROCESS_TABLE: RwLock<[Box<Process>; MAX_PROCS]> = RwLock::new([(); MAX_PROCS].map(|_| Box::new(Process::new(0))));
pub static ref PROCESS_TABLE: RwLock<[Box<Process>; MAX_PROCS]> = RwLock::new([(); MAX_PROCS].map(|_| Box::new(Process::new())));
}

#[derive(Clone, Debug)]
Expand Down Expand Up @@ -192,10 +192,10 @@ pub fn exit() {
let page_table = unsafe { sys::mem::create_page_table(proc.page_table_frame) };
let phys_mem_offset = unsafe { sys::mem::PHYS_MEM_OFFSET.unwrap() };
let mut mapper = unsafe { OffsetPageTable::new(page_table, VirtAddr::new(phys_mem_offset)) };

sys::allocator::free_pages(&mut mapper, proc.code_addr, MAX_PROC_SIZE);

MAX_PID.fetch_sub(1, Ordering::SeqCst);
set_id(0); // FIXME: No process manager so we switch back to process 0
set_id(proc.parent_id);

unsafe {
let (_, flags) = Cr3::read();
Expand All @@ -219,10 +219,20 @@ pub unsafe fn alloc(layout: Layout) -> *mut u8 {
proc.allocator.alloc(layout)
}

pub unsafe fn free(ptr: *mut u8, layout: Layout) {
pub unsafe fn free(ptr: *mut u8, _layout: Layout) {
let table = PROCESS_TABLE.read();
let proc = &table[id()];
proc.allocator.dealloc(ptr, layout)
let bottom = proc.allocator.lock().bottom();
let top = proc.allocator.lock().top();
//debug!("heap bottom: {:#?}", bottom);
//debug!("ptr: {:#?}", ptr);
//debug!("heap top: {:#?}", top);
if bottom <= ptr && ptr < top {
// FIXME: panicked at 'Freed node aliases existing hole! Bad free?'
//proc.allocator.dealloc(ptr, layout);
} else {
//debug!("Could not free {:#?}", ptr);
}
}

/************************
Expand Down Expand Up @@ -264,6 +274,7 @@ const BIN_MAGIC: [u8; 4] = [0x7F, b'B', b'I', b'N'];
#[derive(Clone)]
pub struct Process {
id: usize,
parent_id: usize,
code_addr: u64,
stack_addr: u64,
entry_point_addr: u64,
Expand All @@ -275,7 +286,7 @@ pub struct Process {
}

impl Process {
pub fn new(id: usize) -> Self {
pub fn new() -> Self {
let isf = InterruptStackFrameValue {
instruction_pointer: VirtAddr::new(0),
code_segment: 0,
Expand All @@ -284,7 +295,8 @@ impl Process {
stack_segment: 0,
};
Self {
id,
id: 0,
parent_id: 0,
code_addr: 0,
stack_addr: 0,
entry_point_addr: 0,
Expand All @@ -310,6 +322,10 @@ impl Process {
}

fn create(bin: &[u8]) -> Result<usize, ()> {
if MAX_PID.load(Ordering::SeqCst) >= MAX_PROCS {
return Err(());
}

let page_table_frame = sys::mem::frame_allocator().allocate_frame().expect("frame allocation failed");
let page_table = unsafe { sys::mem::create_page_table(page_table_frame) };
let kernel_page_table = unsafe { sys::mem::active_page_table() };
Expand Down Expand Up @@ -367,8 +383,9 @@ impl Process {
let allocator = Arc::new(LockedHeap::empty());

let id = MAX_PID.fetch_add(1, Ordering::SeqCst);
let parent_id = parent.id;
let proc = Process {
id, code_addr, stack_addr, entry_point_addr, page_table_frame, data, stack_frame, registers, allocator
id, parent_id, code_addr, stack_addr, entry_point_addr, page_table_frame, data, stack_frame, registers, allocator
};

let mut process_table = PROCESS_TABLE.write();
Expand Down
2 changes: 2 additions & 0 deletions src/sys/syscall/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use core::arch::asm;
use smoltcp::wire::IpAddress;

pub fn exit(code: ExitCode) -> ExitCode {
//debug!("syscall::exit(code={})", code as usize);
sys::process::exit();
code
}
Expand Down Expand Up @@ -89,6 +90,7 @@ pub fn close(handle: usize) {
}

pub fn spawn(path: &str, args_ptr: usize, args_len: usize) -> ExitCode {
//debug!("syscall::spawn(path={}, args_ptr={:#x}, args_len={})", path, args_ptr, args_len);
let path = match sys::fs::canonicalize(path) {
Ok(path) => path,
Err(_) => return ExitCode::OpenError,
Expand Down
3 changes: 2 additions & 1 deletion src/usr/install.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@ pub fn copy_files(verbose: bool) {
create_dir("/var", verbose); // Variables

copy_file("/bin/clear", include_bytes!("../../dsk/bin/clear"), verbose);
//copy_file("/bin/exec", include_bytes!("../../dsk/bin/exec"), verbose);
copy_file("/bin/halt", include_bytes!("../../dsk/bin/halt"), verbose);
copy_file("/bin/hello", include_bytes!("../../dsk/bin/hello"), verbose);
//copy_file("/bin/hello", include_bytes!("../../dsk/bin/hello"), verbose);
copy_file("/bin/print", include_bytes!("../../dsk/bin/print"), verbose);
copy_file("/bin/reboot", include_bytes!("../../dsk/bin/reboot"), verbose);
copy_file("/bin/sleep", include_bytes!("../../dsk/bin/sleep"), verbose);
Expand Down
31 changes: 0 additions & 31 deletions src/usr/shell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -240,36 +240,6 @@ fn variables_expansion(cmd: &str, config: &mut Config) -> String {
cmd
}

fn cmd_proc(args: &[&str]) -> Result<(), ExitCode> {
match args.len() {
1 => {
Ok(())
},
2 => {
match args[1] {
"id" => {
println!("{}", sys::process::id());
Ok(())
}
"files" => {
for (i, handle) in sys::process::handles().iter().enumerate() {
if let Some(resource) = handle {
println!("{}: {:?}", i, resource);
}
}
Ok(())
}
_ => {
Err(ExitCode::Failure)
}
}
},
_ => {
Err(ExitCode::Failure)
}
}
}

fn cmd_change_dir(args: &[&str], config: &mut Config) -> Result<(), ExitCode> {
match args.len() {
1 => {
Expand Down Expand Up @@ -499,7 +469,6 @@ fn exec_with_config(cmd: &str, config: &mut Config) -> Result<(), ExitCode> {
"net" => usr::net::main(&args),
"pci" => usr::pci::main(&args),
"pi" => usr::pi::main(&args),
"proc" => cmd_proc(&args),
"quit" => Err(ExitCode::ShellExit),
"read" => usr::read::main(&args),
"set" => cmd_set(&args, config),
Expand Down
Loading